Rails 6’s Action Mailbox Explained

Hakan Hatipoğlu
5 min readSep 16, 2020

Many new cool features has been introduced in Rails 6. I think that new methods for ActiveRecord, ActionText, Action Mailbox are the most important ones.Today I will try to explain what Action Mailbox is and how to use it in a simple way.

What is it?

This is how Rails boss defines it: “It serves to route incoming emails to controller-like mailboxes for processing in Rails.” ActionMailbox is a new feature of Rails 6 for processing inbound emails to let users respond to your app via email.It ships with ingresses for Mailgun, Mandrill, Postmark, and SendGrid. You can also handle inbound mails directly via the built-in Exim, Postfix, and Qmail ingresses.Inbound emails are routed asynchronously using Active Job to one or several dedicated mailboxes.

We’ll build a simple application and test this wonderful feature.

How to use it?

Firstly, lets create a really basic Rails application.

rails new mail_box_testing

For this simple application one users, one companies and one company_notes tables are enough.Lets quickly generate scaffolds for these tables and let scaffolds handle models, views and controllers for us.

rails g scaffold User name email
rails g scaffold Company title
rails g scaffold CompanyNote user:references company:references body:text

Companies can have lots of company notes. Lets not forget to add this relation to our company model.

class Company < ApplicationRecord
has_many :company_notes
end

We are going to install Action Mailbox next.In the meantime, Active Storage also will be installed.

Active Storage is the storage for emails that comes to our application.Whenever an email comes to Rails; Active Storage will save it and keep track of it(whether its processed or not), then it will load an ActiveJob to process the email and lastly delete that email when its done.However it will keep track of the message_id and message_checksum.If you ever got the same email twice, it will not process it twice.

rails action_mailbox:install

This is gonna generate 2 migrations for Active Storage(active_storage_blobs and active_storage_attachments tables) and Action Mailbox(action_mailbox_inbound_emails table).It will also create application mailbox for us.

The table we need to focus is action_mailbox_inbound_emails for now.I would like to mention shortly some columns in this table.

action_mailbox_inbound_emails table

Status column here for whether the email is pending, processing or finished.message_id and message_checksum is to avoid duplication as I mentioned before.

With rails action_mailbox:install command, also application mailbox file created.application_mailbox decides which emails should go to which mailbox.So, we need to match urls and mailboxes in this file.I am gonna route emails fits “/reply-(.+)@reply.example.com/i” regex to company_notes mailbox.However you can also route all incoming emails to one mailbox like this: routing :all => :company_notes.

class ApplicationMailbox < ActionMailbox::Base
#routing /something/i => :somewhere
routing /reply-(.+)@reply.example.com/i => :company_notes
end

After we configure our application_mailbox, lets create company_notes mailbox.

rails g mailbox CompanyNote

When we create our mailbox, we are gonna see a default method called process.This is the place what we want to do with coming emails.Inside of our mailbox, we have access to mail object(actual email that was given to us) and inbound_email(ActionMailbox::InboundEmail) record.What we need to do inside our company_notes mailbox is that finding user from coming email and finding company from url.Lastly, we are gonna create our company record.Simple!

You can do lots of cool things inside mailbox if its necessary.Lets say an email comes to your application and user cannot be found in the database.In this case you can use before_processing callback and bounce an email back to user saying that user cannot be found, please sign up for application.. etc. before processing.

class CompanyNoteMailbox < ApplicationMailbox
MATCHER = /reply-(.+)@reply.example.com/i
def process
return if user.nil?
company.company_notes.create(user: user, body: mail.decoded)
end
def user
@user ||= User.find_by(email: mail.from)
end
def company
@company = Company.find(company_id)
end
def company_id
recipient = mail.recipients.find{ |r| MATCHER.match?(r)}
recipient[MATCHER, 1]
end
end

mail.recipients above will give us a list of array of email addresses that user sent to.In our case its gonna be just one email, however we have to loop through it since its an array.In company_id method we get the related company and in user method we get user(mail.from).After these steps, all we need to do is just to create our company note record. If you look closely, when we could not find user, we do nothing.You can check all functions of mail object in mail gem documentation.

How to test?

Easiest way to test Action Mailbox is to use new rails conductor.This is the development url: http://localhost:3000/rails/conductor/action_mailbox/inbound_emails/new

Before test, make sure you created one user and one company record.Also make sure that you are showing company.company_notes in companies/show.html.erb file. Now we need to send an email matching our regex in company_notes mailbox(Unless you specified like this routing :all => :company_notes).

We are gonna see in rails logs that action_mailbox_inbound_emails, active_storage_blobs and active_storage_attachments tables are filled with new records after we send our inbound email.

inbound email

In inbound email page; we can see full email source and route email again.It also allows us to see other inbound emails.

Now lets view our company and see if our company note attached:

company record with id 1

Thats all for now.With Action Mailbox we can also save email attachments.In order to do that we need to dive deeper, of course.I will try to do that in another video.

Thanks for your time.

Same article in Turkish here.

Helpful sources:

--

--