Handling inbound emails in Rails using Postmark
It’s common to send emails from your Rails app, but what about receiving incoming emails? In this tutorial, you’ll learn how to receive emails in your Rails app using Postmark’s inbound email processing.
We’ll be creating a simple blog application that allows readers to post responses to articles using email.
Let’s get started.
Prerequisites #
You’ll need a Postmark account for this tutorial. If you don’t have one already, sign up for a free developer account now.
This tutorial assumes that you’re familiar with running a Rails app locally. The demo application we’ll be using is built to run on Rails 5 using Ruby 2.4.1.
If you don’t already have Ruby 2.4.1 installed, please install it using rvm before continuing.
rvm install 2.4.1
Setting up the demo application #
Start by downloading the demo application and unzipping the contents to your home folder.
Open up Terminal and cd
into the inbound-demo-rails
directory.
Install the project’s dependencies using Bundler.
gem install bundler
bundle install
Now you need to set up the database. We’ll be using an SQLite database in this demo for simplicity.
Start by creating the database:
bin/rails db:setup
This command will set up your database and populate it with some example articles you can use for testing.
Now your database is set up, and you’re ready to run the app. Head back to the terminal and start up the Rails server.
bin/rails s
Navigate to http://localhost:3000 in your web browser. You should see three test articles.
Configuring Postmark’s inbound processing #
Now you’ve got the demo app up and running it’s time to configure Postmark to receive your emails.
Log in to your Postmark account and create a new server that will handle your app’s inbound emails.
Head over to the Credentials tab and grab the inbound email address for this server. It should look something like huigh8923hg782ygh7348y734g8y@inbound.postmarkapp.com
. This is the email address where readers will send their article responses.
If you want to use a custom email address for inbound emails, check out the inbound domain forwarding setup guide.
Open the config/initializers/postmark.rb
file and input the hash from the start of your inbound email address. (Everything before the @ symbol.) Postmark uses this hash to determine which server inbound emails belong to.
Rails.application.config.postmark_inbound_email_hash = 'huigh8923hg782ygh7348y734g8y'
In order to test webhooks locally, you’re going to use a service called Ultrahook. Ultrahook will catch webhook payloads sent from Postmark and forward them to the Rails app running on your local machine.
If you haven’t used Ultrahook before, start by registering for an API key.
Once you’re done, add your Ultrahook API key to a .ultrahook
file in your home folder.
echo "api_key: YOUR_ULTRAHOOK_API_KEY" > ~/.ultrahook
You’re now ready to start Ultrahook.
ultrahook inbound-demo 3000
Once Ultrahook starts running, you should see a URL output in the console.
Authenticated as YOUR_USER
Forwarding activated...
http://inbound-demo.YOUR_USER.ultrahook.com -> http://localhost:3000
Any requests sent to http://inbound-demo.YOUR_USER.ultrahook.com
will now forward to http://localhost:3000
on your local machine.
Now that you have Ultrahook set up, the final step of this section is to tell Postmark about your Webhook URL.
Go to the inbound settings page for your server. (Settings → Inbound)
In the Webhook field, add your ultrahook URL followed by /responses
. This path is for the endpoint that will process incoming inbound webhooks in your Rails app. (We’ll set that up shortly.)
http://inbound-demo.YOUR_USER.ultrahook.com/responses
Make sure to come back and update the Webhook URL when you’re ready to launch your application into production.
Handling inbound webhooks from Postmark #
It’s time to create the endpoint in your Rails app that will handle inbound webhooks from Postmark.
Create the controller method #
Open the app/controllers/responses_controller.rb
file in your favorite text editor.
Add a new create
method. This will receive inbound webhook payloads from Postmark that contain the responses sent from readers.
def create
end
The first thing you need to do is parse the JSON payload sent by Postmark. Add the following to your new create
method:
message = JSON.parse(request.body.read)
To identify which article a response should be associated with, we’re going to add the article’s ID to the inbound email address. We’ll do this using the +
character.
Anything after the +
will be extracted by Postmark as the MailboxHash
which is made available in the JSON request received by the Rails application.
huigh8923hg782ygh7348y734g8y+124@inbound.postmarkapp.com
In this example, Postmark would identify 124
as the MailboxHash
.
Processing replies to your transactional emails #
A common use case for inbound email processing is to catch replies to transactional emails. For example, if a user replies to a comment notification email for a blog post they wrote, their reply should be added to the comments section of that blog post. To process replies to your transactional emails, add a Reply-To
header on the emails your application sends out. This should be your inbound email address with a unique hash or ID which can be used to identify a database record that replies should be associated with.
Reply-To: Postmark<qwerty12345+myrandomhash@inbound.postmarkapp.com>
Back in the create
method, retrieve the article ID from the webhook JSON.
article_id = message['MailboxHash']
Next, use this article_id
variable to find the Article that the new response should be associated with.
You can now create the new response using the data from the reader’s email.
article.responses.create(
name: message['FromName'],
email: message['From'],
body: message['TextBody']
)
Here we’re extracting the user’s name and email address as well as the body of the email and using it to create a new Response record.
Check out the Postmark documentation for a full list of properties available in the inbound webhook JSON.
Finally, return a 200 response code so that Postmark knows the inbound email was processed successfully.
render plain: 'Response Saved', status: 200
To recap, your full create
method should now be:
def create
# Parse the message
message = JSON.parse(request.body.read)
# Grab the Article ID from the message
article_id = message['MailboxHash']
# Find the article
article = Article.find(article_id)
# Create a new response
article.responses.create(
name: message['FromName'],
email: message['From'],
body: message['TextBody'] # Could also use message['HtmlBody']
)
# Return a 200 code so Postmark know’s the webhook was processed
render plain: 'Response Saved', status: 200
end
By default, Rails comes with a security feature that requires POST requests to include an authenticity token to validate they were made from the app. As Postmark does not have access to this authenticity token, you’ll need to disable this feature for the create
method.
Add the following above the create
method definition to disable CSRF protection on the webhook endpoint.
protect_from_forgery except: :create
Set up a route #
Now your controller action is complete you just need to register a new route for it.
Add the following to your config/routes.rb
file:
resources :responses, only: [:create]
Your app can now receive POST requests at /responses
which will be handled by the create
method on the ResponsesController
.
Testing inbound processing #
Your app is now ready to start processing inbound emails!
Make sure both your local Rails server and Ultrahook are still running and navigate to http://localhost:3000/articles/1.
Scroll down to the bottom of the page and hit the Send a response button. This should launch your mail client.
Note that the email address includes the +
symbol followed by the article ID, in this case, 1
.
Type a quick message into the body of the email and hit send.
Wait a few seconds and then refresh the page. If everything is set up correctly, you should see your response at the bottom of the page.
Now navigate to a different article and post a response their too.
Summary #
In this tutorial you’ve learned how to receive email in your Rails app using Postmark’s inbound email processing.
Now you’ve got the basics mastered, try tackling some more advanced topics like setting up a custom inbound email address or blocking inbound messages based on their spam score.
Be sure to let us know how you’re using inbound processing in your app.
Grab a copy of the completed code for the demo application on GitHub.