Pass data to mailer daemon in Rails?
-
20-09-2019 - |
Question
According to the Rails API (snippet below), the optimal way to receive mail is by creating a single Rails instance within a daemon that gets invoked by a MTA whenever new mail arrives.
My question is: how do you pass data to that daemon when new mail arrives?
========================
Rails API Snippet
To receive emails, you need to implement a public instance method called receive that takes a tmail object as its single parameter. The Action Mailer framework has a corresponding class method, which is also called receive, that accepts a raw, unprocessed email as a string, which it then turns into the tmail object and calls the receive instance method.
Example:
class Mailman < ActionMailer::Base
def receive(email)
page = Page.find_by_address(email.to.first)
page.emails.create(
:subject => email.subject, :body => email.body
)
if email.has_attachments?
for attachment in email.attachments
page.attachments.create({
:file => attachment, :description => email.subject
})
end
end
end
end
This Mailman can be the target for Postfix or other MTAs. In Rails, you would use the runner in the trivial case like this:
./script/runner 'Mailman.receive(STDIN.read)'
However, invoking Rails in the runner for each mail to be received is very resource intensive. A single instance of Rails should be run within a daemon if it is going to be utilized to process more than just a limited number of email.
Solution
In the example you provide, there is no daemon running to process email. The documentation is saying you can setup your mailer daemon, Postfix in this case, to invoke a command when mail is received. When you call the command from your mailer:
RAILS_ROOT/script/runner 'Mailman.receive(STDIN.read)'
The content of the email is passed into the receive method. A much better way to handle processing incoming email is to create an actual mailbox that receives email. You can then write a Ruby script that batch checks the mailbox to process the email. You can call that script via cron with lock run around it to insure that there is only one process performing this task.