Receiving emails with Ruby on Rails
Written by Robin Fisher in 622 words
17
Jun
I spent the weekend getting a little application to play nicely with emails being sent to it. As receiving emails with Rails is something that is not written about as much as sending emails, I thought I would share my solution.
This tutorial will show you how to receive emails into your application, store them in the database and forward the contents to multiple recipients.
The first problem of course is getting the emails into your application. I have root access to my server, so my solution uses Postfix. If you don’t have root access, you can use POP and there are a number of examples out there. On with the instructions…
As I am hosting a number of domains on the same box, I set up my main.cf file as follows:
virtual_alias_domains = mydomain.com virtual_alias_maps = hash:/etc/postfix/virtual
I then set up my virtual file (which you may need to create) with a single line:
@mydomain.com rails_mailer
This will intercept any emails sent to mydomain.com and pass them to the rails_mailer alias, which is created in your alias file. Mine is located in /etc/aliases: yours might be in /etc/postfix/aliases. Add to the bottom of your aliases file:
rails_mailer: "|curl -F mail='<-' http://mydomain.com/emails"
This uses curl to post the mail as form data to the given url. The email contents will be stored inside the mail parameter. The pipe character at the start indicates that this is a shell command and not a directory.
To apply all these changes:
sudo postmap /etc/postfix/virtual sudo newaliases sudo /etc/init.d/postfix reload
To check that this is working, change into your /var/log directory and use:
tail -f mail.info
Then send an email to any address @mydomain.com and you should see it received in your mail log and passed to your Rails app. If you look in your app’s logs, you should see it spitting out a 500 error as there is no code to handle the email…yet.
On to the Ruby. Create an Emails controller and define a create method:
def create
if params[:mail]
Notifier.receive(params[:mail])
end
end
This receives the contents of params[:mail] and passes it to the receive method of our notifier model.
To deal with Rails’ cross-site scripting protection, you need to add to the top of your controller:
skip_before_filter :verify_authenticity_token
Next, generate a mailer called notifier. In notifier.rb, define a method called receive(email). Using this method name automatically invokes the power of TMail. My receive method is as follows. You will need to change this to make sure you pull the information you need from the email:
def receive(email)
event_name = email.to
event_name = event_name.to_s.sub('@mydomain.com', '')
event = Event.find_by_tidy_name(event_name)
body = email.body
address = Array.new
event.attendees.each do |attendee|
address << attendee.email.to_s
end
from = email.from.to_s
new_email = event.emails.new
new_email.from = email.friendly_from
new_email.body = body
new_email.save
Notifier.deliver_event_email(event, from, address, body)
end
Before running through this code, I should explain that when people use the app, they receive a dedicated email address in format myeventname@mydomain.com.
This code does two things. Firstly, it extracts the following data from the email: the name of the event, the body of the email and who the email is from. It then constructs a new email that belongs to the event and saves to the database. It then invokes another method in our notifier.rb to forward the email body to the individuals who are attending the event.
def event_email(event, from, address, body)
setup_email(from)
@bcc = address
@subject += "#{event.name}"
@body[:body] = body
end
In terms of the application that I wrote this for, I hope to launch it within the next week. If you’ve got any questions or run into any problems, leave a comment and I’ll try and help.
Thanks very much for going to the effort of posting this – saved me scrabbling around to figure out how the postfix stuff is configured.
I sincerely am grateful to you for sharing this clean documentation on receiving emails into Rails app..
I have doubt understanding the differences in usage as I am using a Windows based Development PC..
Where should I make the changes which you made in
-main.cf file?
-@mydomain.com rails_mailer
-/etc/postfix/aliases
[Also is there a Postfix installation for Windows or I need to use some different Mail Handler??]
I am yet to incorporate the above solution in my Rails App, but this solution is exactly what my App was lacking intending to do..
Thanks,
Nitin R
Is there a way to do the same thing, but for smtp outgoing emails as well with postfix?
Hi Tripp,
I haven’t sent emails directly from one of my servers for a while.
My preferred method is to pass this off to an external service. I’m currently using Amazon Simple Email Service but I hear good things about Postmark.
Hi,
Many thanks for this very useful guide!
I had a question; you mentioned that for every user that signs up on your website, you automatically create an anonymous email like 12345@mydomain.com. How do do this?
If you could share code/guidelines for doing this, that would be awesome as I am relatively new to rails.
Thank you,
Faisal
Hi Faisal,
I don’t actually create the email address. For each event created, it would be given a downcased name e.g. robinsbirthday. Emails sent to robinsbirthday@mydomain.com would be routed into the application and then I strip out the part before the @ sign and find the relevant event e.g. Event.find_by_downcased_name
Robin