Re: Sample code for displaying a MIME email message on a web page?

Kip
Sun, 05 Aug 2007 00:38:55 -0000

Josh, I have done a *very* simple wrapper around this message parsing
bit.  This will let you get at the parts of a mime multipart message.
I guess you could use sanitize() strip_tags() and strip_links() to
help make the html more displayable.  Note I just put this together
for a proof-of-concept for emailing articles and images to a content
system I''m writing so i sure wouldn''t cut and paste!

  require ''hermes_messages.rb''
  my_messages.HermesMessages.new
  my_messages.get_messages(pop server parameters)
  my_messages.message.each do |m|
    # Each message has many parts, but we simplifiy with some helper
methods
    puts m.subject
    puts m.from
    puts m.body       # Note the ''body'' method retrieves the
text/
plain part for my needs - modify as required to get the html part
  end

Hope this helps a little more,

--Kip


class HermesMessages
  require ''net/pop''
  require ''action_mailer''

  EMPTY_PART = " \r\n\r\n"
  TEXT_PLAIN = ''text/plain''
  MULTIPART_ALTERNATIVE = ''multipart/alternative''

  attr_reader :messages

  def get_messages(host, user, password, port, *args)
    options = args.last.is_a?(Hash) ? args.pop : {}
    @messages = []
    begin
      Net::POP3.start(host, port, user, password) do |pop|
        if pop.mails.empty?
          puts ''No mail.''
        else
          puts "#{pop.mails.size} messages will be processed."
          pop.each_mail do |m|
           @messages << IncomingImageHandler.receive(m.pop)
           m.delete if options[:delete] == true
          end
        end
        puts "#{pop.mails.size} mails popped."
        return pop.mails.size
      end
    rescue
      puts "Exception detected - could not retrieve email"
      return -1
    end
  end

  class Message
    attr_accessor :subject, :from
    attr_reader :parts

    def initialize
      @parts = []
    end

    def add_part(p)
      @parts << p
    end

    def has_jpeg?
      parts.each {|p| return true if p.sub_type == "jpeg"}
      return false
    end

    def has_body?
      parts.each {|p| return true if p.main_type == "text" &&
p.sub_type == "plain"}
      return false
    end

    def body
      parts.each {|p| return p.body if p.main_type == "text"
&&
p.sub_type == "plain"}
      return ""
    end

    def jpeg
      parts.each {|p| return p.body if p.main_type == "image"
&&
p.sub_type == "jpeg"}
      return ""
    end

    def image_filename
      parts.each {|p| return p.filename if p.main_type == "image"
&&
p.sub_type == "jpeg"}
      return ""
    end

  end

  class Content

attr_accessor :main_type, :sub_type, :body, :filename, :file_extension, :index
  end

  class IncomingImageHandler < ActionMailer::Base
    # email is a TMail::Mail
    def receive(email)
      @message = Message.new
      @message.from = email.from[0]
      @message.subject = email.subject
      puts "Processing message: #{@message.subject}"
      process(email)
    end

  protected

    def process(part)
      if part.multipart? then
        part.parts.each {|p| process(p) } unless
          part.content_type == MULTIPART_ALTERNATIVE &&
          plain_part_is_empty(part)
      else
        process_part(part)
      end
      return @message
    end

    def process_part(part)
      puts "   part: #{part.content_type} with size
#{part.body.length}"
      pp "     content is: ''#{part.body}''" if
part.body.length <= 10
      content = Content.new
      content.main_type = part.main_type
      content.sub_type = part.sub_type
      content.body = part.body
      content.filename = part_filename(part)
      content.file_extension = ext(part)
      @message.add_part(content)
    end

  private

    def plain_part_is_empty(part)
      part.parts.each do |p|
        return true if p.content_type == TEXT_PLAIN && p.body
=EMPTY_PART
      end
      return false
    end

    def part_filename(part)
      # get filename
      if part[''content-location''] != nil &&
part[''content-
location''].body.length != 0
        filename = part[''content-location''].body
      elsif part.type_param(''name'') != nil  &&
part.type_param(''name'').length != 0
        filename = part.type_param(''name'')
      elsif part.disposition_param(''filename'') != nil
&&
part.disposition_param(''filename'').length != 0
        filename = part.disposition_param(''filename'')
      else
        filename = nil
      end
    end

    CTYPE_TO_EXT = {
      ''image/jpeg'' => ''jpg'',
      ''image/gif''  => ''gif'',
      ''image/png''  => ''png'',
      ''image/tiff'' => ''tif''
    }

    def ext( mail )
      CTYPE_TO_EXT[mail.content_type] || ''txt''
    end
  end #class
end




On Aug 4, 6:37 pm, Kip <kipco...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
wrote:
> Josh, I found the following very helpful:
>
>
http://blog.mondragon.cc/articles/2006/12/30/decoding-email-attachmen...http://www.ruby-doc.org/stdlib/libdoc/net/pop/rdoc/classes/Net/POP3.html
>
> Cheers, --Kip
>
> On Aug 4, 11:08 am, Joshua Baer
<joshuab...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
> > Can anyone point me to a good source of sample code for taking a raw
> > email message (multipart, with attachments) and displaying it on a web
> > page? Also same thing for composing a new message with attachments?
>
> > ~Josh