Since forever, **action\_mailer** has been able to receiving incoming email. The [conventional wisdom](http://wiki.rubyonrails.org/rails/pages/HowToReceiveEmailsWithActionMailer) for realtime email handling is to jam an address into the aliases file, something like:
mailman: “|/path/to/app/script/runner Mailman.receive(STDIN.read)”
This is very easy to setup. Now when each message comes in it will call **Mailman.receive**. Unfortunately, this also starts a new ruby process each time. Not only that, but **script/runner** also loads the entire rails stack each time it gets called. Wow! As your project gets bigger and bigger this becomes more and more expensive. Suppose, you found acts as exactly what I need plugin, now you get the joy of deciding whether or not to use it, because it will be loaded each time a message comes in, SUCK.
Because of that factor I decided to move away from the script runner approach.
There are two ways to fix this problem. The easy way, and the right way. I chose the easy way for the time being.
mailman: “|/path/to/app/script/mail_process”
Instead of using **script/runner** I am using **script/mail\_process**, the difference is in the details. **mail\_process** doesn’t load the entire rails stack. Instead, it parses the message, then passes the important bits to a web service (mongrel), where the rails stack is already loaded. This approach is sometimes called a Service Oriented Architecture, although I think people were using this technique well before someone invented the term</digression>
Here is my actual implementation:
#!/usr/bin/env ruby
require ‘rubygems’
require ‘action_mailer’
mail = TMail::Mail.parse(STDIN.read)
mail.base64_decode
body = mail.body
respond_to = mail.from
url = “http://#{SOME_URL}?body=” +
CGI.escape(body) + “&respond_to=” +
CGI.escape(respond_to[0])
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.read_timeout = 5
begin
res = http.get(uri.path + “?” + uri.query)
rescue Timeout::Error
#handle errors
rescue Exception => e
#handle errors
end
As I said this is the easy way, if I ever want to *really* scale this, I will have to go to a more reasonable approach. That approach involves replacing postfix as the mail transfer agent (mta) that processes incoming messages. A coworker pointed out [qpsmtpd](http://smtpd.develooper.com/ “qpsmtpd - Develooper LLC”) which is a perl based mta that allows you to write perl scripts that don’t fork (start up) a new perl process for each incoming message. I could then replace **mail\_process** with something very similar. But that day is quite a ways off for me.
Leave a Reply