Wednesday, 4 June 2008

ActionMailer: Receiving Emails Contain Attachments

Web applications may be forced to receive emails and process its content, either its body or contained attachments. ActionMailer can be used to receive emails and give you access to its content. ActionMailer functionality based on receiving TMail object of your email content and give you access on all its parts (from, to, attachments, etc).

All you need to do is add the following method to your action mailer model:

def receive(email)
...
end


"email" argument is an object of type TMail::Mail. You can use it to read email metadata:

@to = email.to
@from = email.from
@body = email.body


The nice part is accessing the email attachments (if exist) through simple code. The following code checks if the email have attachments and read each attachment file name, content type and its content:

def receive(email)
if email.has_attachments?
email.attachments.each do |attachment|
@file_name = attachment.original_filename
@content_type = attachment.content_type
@content = attachment.read
end
end

end


Using ActionMailer for receiving emails contains two magical parts:

  1. Some email bodys encoded using Base64 encoding, also the attachments. The magical part in TMail is that it handles decoding the attachment content using Base64 decoder for you. So, you access the attachment content directly without decoding it.

  2. If you read the incoming email from a system file and need to feed it to your ActionMailer.receive method, all you need to do is reading the file content and give it directly to your ActionMailer.receive method without converting it into TMail object and ActionMailer will do the rest:

    file = open("my_email")
    email_content = file.read
    file.close
    MailerAgent.receive(email_content)

The missing part in this process is that ActionMailer will not listen at the email server for catching the new emails. I used one solution for this part; you can configure your email server to catch all incoming emails, save them inside a specific folder (file per email). Then you create a rake task that run periodically, reads the folder files and send each file content to your ActionMailer.receive method. But you need to filter the spam emails in this case.

2 comments:

Unknown said...

Salam Wael, nice article, I read it in your blog before :)
However I have a question: what email server you used to receive your emails? And how did u configure it?
Thanks

Wael M. Shaban said...

Salam Hossam,
Thanks a lot :)
As I remember, the email server was exim.
We used it to receive the emails, put them inside some system folder as files and then I read the files through my RoR and pass them to ActionMailer.
Of course this is not the optimal solution, but we did it like that just for saving time :)