How I Use Action Mailbox to Email Myself Book Notes
This one is about receiving incoming email in your Rails application using Action Mailbox. You’ve likely used Action Mailer, which is for sending emails from your application. Action Mailbox is for receiving email.
A long time ago, I used to email myself all kinds of things - a quote I liked, or a book recommendation, a reminder. Nowadays I’ve set up one of those fancy personal-knowledge-management-second-brain-note-taking systems like a civilized person. (not really! I write everything in markdown in Obsidian, including this newsletter).
I have been fiddling with a book notes app for personal use though. I added this feature to it: when I’m reading/listening to a book, I can email myself a short note with a thought or an idea that occurs to me and have it show up in the app.
Let me show you how I did this and how Action Mailbox works:
Action Mailbox Overview
Here are some facts to know about Action Mailbox:
- Action Mailbox routes incoming emails to controller-like mailboxes for processing in your Rails application.
- The incoming emails are routed asynchronously using Active Job.
- The emails are turned into
InboundEmail
records using Active Record, which can interact directly with the rest of your domain model. - The original emails are stored via Active Storage while processing along with their status. They’re also automatically deleted after some configurable time (called Incineration).
- In order to actually receive email, we configure something called an ingress. Email providers like Mailgun, Postmark, Sendgrid, etc. have a way to configure these. The instructions are in the Action Mailbox guides. I used Postmark and it was easy enough to setup. Action Mailbox ships with built-in ingresses for local testing.
Okay now let’s see some code!
Receiving Book Notes by Email
First, we install Action Mailbox with bin/rails action_mailbox:install
.
This will generate application_mailbox.rb
and copy over some migrations.
The new table action_mailbox_inbound_emails
stores incoming messages and their processing status. The status
column can be one of pending
, processing
, delivered
, failed
, or bounced
.
Next, we setup routing. In this case we are matching an email sent to an address like book-42@whatever.com
to a mailbox we call active_reading_notes
. The application_mailbox.rb
looks like this:
class ApplicationMailbox < ActionMailbox::Base
# routing /something/i => :somewhere
routing(/^book-\w+@/ => :active_reading_notes)
end
Now we need to actually create this mailbox which does not exist yet. We do this with bin/rails generate mailbox active_reading_notes
.
Next, we implement the process
method of the ActiveReadingNotesMailbox
to do something with the incoming email. This is the interesting part. Here you can create other models based on the email data, you can send emails, you can start a background job. You can do anything you want.
I’m creating an ActiveReadingNote
based on the body of the email, associated with the Book
identified by the integer in the mail.to
field. My Book
model has_many :active_reading_notes
.
class ActiveReadingNotesMailbox < ApplicationMailbox
def process
book_regex = /^book-(\w+)@/i
# find the book from email address
email_to = mail.to.first
book_id = email_to.match(book_regex)[1]
book = Book.find(book_id)
body = mail.body.decoded
book.active_reading_notes.create(content: body)
end
end
(Note: this is a ‘naive’ implementation, for harding it we would handle if the book doesn’t exist and use better identifiers).
Notice that in the mailbox process
method, we have access to the mail
object, which is from the Mail Library
and has all the fields that you’d expect in an email.
How do we test if this is working locally? Action Mailbox mounts a conductor controller at http://localhost:3000/rails/conductor/action_mailbox/inbound_emails
. We can use this to create new InboundEmail
and send it. We can also see an index of all the InboundEmails
in the system and their state of processing. That’s pretty cool.
I’m displaying all my “active reading notes” (i.e. emails I sent to my app while reading) on the book’s show
page, like you see in the screenshot at the top.
That’s all for this one. I challenged myself to keep this as short and to the point as possible.
More details about the mail
object, incineration, and how to configure Action Mailbox with an external email provider (e.g. postmark) in production are in the new and improved Action Mailbox guide.
Subscribe for more Ruby, Rails, and Hotwire
Short posts, clear explanations