ActionMailer quicktips: receiving and parsing mail

by Naomi Butterfield on November 19, 2007

I was working on a fix for a mail_receiver model that implemented ActionMailer’s receive method. I was seeing a problem while it was trying to parse out sub-parts from a mime multitype message, where it wasn’t capturing the content correctly for multipart/alternative. The existing code was pulling the message text as so:

def get_multipart_body(mail)  
  types =  mail.parts.collect(&:content_type)
  if types.include?("multipart/alternative")
    body = mail.parts.find { 
      |m| m.content_type == "multipart/alternative" 
    }.body
  end
end

What fixed it was this:

def get_multipart_body(mail)
  types = mail.parts.collect(&:content_type)
  if types.include?("multipart/alternative")
    # we need to dig down a level to get the sub-parts
    m_part =  mail.parts.find { 
      |m| m.content_type == "multipart/alternative" 
    }
    sub_types = m_part.parts.collect(&:content_type)
    if sub_types.include?("text/plain")
      body = get_text_plain(m_part)
    else
      body = get_text_html(m_part)
    end
  end
end

So with ‘mail’ being a TMail object (which ActionMailer uses to parse email into its constituent parts), the sub-parts can be retrieved by calling mail.parts.find to get the sub-parts of the message.

Now technically, there can be an unlimited number of nestings within parts (check out RFC 2046 for the nitty-gritty details). The fix above only goes one level down. I considered doing a little recursive method for handling it, but ran out of time. Still, I’ll keep that idea as an exercise for future interest.

Bookmark and Share

Other Posts That Might Interest You

  1. Nuts, I forgot to attach that file, again…
  2. Custom Form Validations Without ActiveRecord
  3. Yay Google Is Helping Kill IE6
blog comments powered by Disqus

Previous post:

Next post: