S.E.A.N.I.C.U.S.

Monday, April 03, 2006

ActionMailer attachments

Disclaimer: Binary attachments seem to be broken on Windows because of a problem with the base64 encoding. See the bug I submitted.

ActionMailer is a curious beast. I spent much of last week debugging and retooling what I thought was already working. In testing sending an email with a binary attachment, I found that the file size was smaller, and that the Word document I was using to test it was corrupted -- it thought the character encoding was Japanese, of all things. Turns out this is not a problem on our Linux server, but only on my local Windows box.

That aside, I took procreate's suggestion and looked at some raw emails in my inbox. I wanted to do a gracefully-degrading body content, AND have binary attachments. Below is a snippet of what I came up with. Keep in mind that I'm still dealing with a problem that doesn't allow my templates to be rendered using render_message, so I broke the MVC pattern and put functions in my mailer that do that for me. (Maybe this is a bug I should submit?)

  def attachments(myObject)
subject 'Subject'
recipients 'somebody@kckcc.edu'
from 'somebody-else@kckcc.edu'
content_type "multipart/mixed"

# Message body
part :content_type => "multipart/alternative" do |p|

p.part :content_type => "text/html",
:body => html_view(myObject)

p.part :content_type => "text/plain",
:body => text_view(myObject)

end

# Attachments
part :content_type => "multipart/mixed" do |p|
for att in myObject.attachments
enctype = "Base64"
if att.content_type =~ /^(text\/)/
enctype = "Quoted-printable"
end
p.attachment :content_type => att.content_type,
:body => File.read(att.file),
:filename => File.basename(att.file),
:transfer_encoding => enctype,
:charset => "utf-8"
end
end
end


There's a lot of extra stuff there, like making sure we select Quoted-printable encoding for text content-types. Also, it's not necessary to place your attachments in a separate part -- they can exist at the same level as your message body. I just did it to make sure they weren't interacting with one another unexpectedly.

FYI: I'm using Rails 1.1 and the path/filename and content-type information for my email attachments are stored in the database via an ActiveRecord model called Attachment. As always, YMMV.