There are many libraries and services out there that make sending and tracking transactional emails in your Rails app a breeze. I’ve used Sendgrid and Postmark; both make it possible to start sending emails in a matter of minutes.
But the pain points of transactional emails have not been removed entirely.
The pain points of transactional emails
The first pain point is styling. Tools like roadie can automatically inline CSS in email templates based on stylesheets and Rails 4.1 comes with the ability to preview emails in development out of the box, but determining whether those styles look right in different email clients and devices is a lot of extra work. More than once, I’ve had something look awesome in Gmail and then have a client show me the same email looking completely broken in Outlook.
The second pain point is the need for regular copy changes. After setting up an email template, the copy of an email template rarely stays the same for long. Whether it’s right away or a few days later, I almost always find myself tweaking email copy on several occasions to meet client and other stakeholder requests.
Why use Mandrill?
A couple of years ago, my approach to the this problem was to set up an
emails
table in my database with name
and content
fields. The name
would correspond with an email template name, and the content
would be the
main chunk of copy for an email. I would set up RailsAdmin as an interface for stakeholders to log
in and update individual email
records, which would be used to populate the
copy for various transactional emails. While this system worked, it was very
brittle because it relied on certain records existing in the database in order
for the app to function and only allowed for email layouts with one big chunk
of copy. In addition, this did not address the issue of responsive email
styles.
So, I was very excited to discover Mandrill, Mailchimp’s transactional email service. While Mandrill is about as easy to set up as other services, it also addresses the two pain points that the others do not. Because Mandrill is a Mailchimp product, you can easily import Mailchimp’s responsive templates into Mandrill to use in transactional emails. In addition, stakeholders can edit email copy within Mailchimp’s WYSIWYG and re-import to Mandrill with the click of a button. This means that copy changes don’t require developer time or a new deploy. Awesome.
I’ve now implemented transactional emails with Mandrill for a handful of Rails apps. It’s pretty simple but much simpler once you’ve seen how it’s done. Let’s go through how to send responsive emails with Mandrill and Rails, step-by-step.
How to set up Mandrill in your Rails app
Sign up for Mailchimp / Mandrill
You need both a Mandrill account and a Mailchimp account.
Connect your Mailchimp and Mandrill accounts
Follow these instructions for integrating your Mailchimp and Mandrill accounts
Set up a template in Mailchimp
Create a basic template in Mailchimp. Don’t worry about nailing down the content, but make sure you give the template a good, clear name since you will be referencing that name in your code. I am creating a welcome email so I am going to name mine
welcome
.Also, if you already know which portions of your email are going to be dynamic, include merge variables for those elements. A merge variable is an element of an email that is dynamic; therefore, it’s values must be set each time an email is sent out. A commonly used merge variable is
first_name
, since the name in an email changes depending on who the email is being sent to. Mailchimp’s format for merge variables looks like this:*|FIRST_NAME|*
. You can also set dynamic links by setting thehref
value of ana
tag to a merge variable, like this:<p>Update your account details <a href=“*|USER_URL|*" target="_blank">here</a></p>
Here’s what my template looks like with basic merge variables:
Send the Mailchimp template to Mandrill
Once you save and exit the template editing view in Mailchimp, you will be on a list of all templates. Find the template you just created, and click the dropdown option next to the
edit
button. You should see the option to “Send to Mandrill”. Click on that link. A few seconds later, you should see a flash message saying that your template was sent to Mandrill. Note: as of right now, this flash message takes several seconds to appear, which can be a bit confusing.Log into Mandrill and visit your templates
You should see the template you just created. Make sure your template is set to “published” within Mandrill.
Once a template is in Mandrill, there is no need to edit it. Editing is best done in Mailchimp and then sent to Mandrill using the “Send to Mandrill” link, since Mailchimp’s templates are optimized for multi-client and multi-device compatibility.
Set up your Rails app to send mail with Mandrill
Add
mandrill-api
to your Gemfile and bundleSet the following
ENV
vars in your Rails app:SMTP_ADDRESS=smtp.mandrillapp.com SMTP_DOMAIN=localhost SMTP_PASSWORD=mandrill_api_key SMTP_USERNAME=mandrill_username
You need set up your SMTP settings for environments where you’d like to actually send emails via Mandrill (for most, this will be production and staging):
# config/environments/production.rb Rails.application.configure do ... config.action_mailer.smtp_settings = { address: ENV.fetch("SMTP_ADDRESS"), authentication: :plain domain: ENV.fetch("SMTP_DOMAIN"), enable_starttls_auto: true, password: ENV.fetch("SMTP_PASSWORD"), port: "587", user_name: ENV.fetch("SMTP_USERNAME") } config.action_mailer.default_url_options = { host: ENV["SMTP_DOMAIN"] } ... end
Set up your Rails app to send Mandrill templates
Now that you’ve got the basic setup for Mandrill done, it’s time to set up your mailer to use the template you created in Mailchimp and sent to Mandrill. In my experience, it’s best to encapsulate this logic in a mailer class that all other mailer classes inherit from. Existing system emails that use SMTP but do not need Mandrill templates will still send properly via Mandrill, so no need to update those until you want to.
# app/mailers/base_mandrill_mailer.rb require "mandrill" class BaseMandrillMailer < ActionMailer::Base default( from: "hello@example.com", reply_to: "hello@example.com" ) private def send_mail(email, subject, body) mail(to: email, subject: subject, body: body, content_type: "text/html") end def mandrill_template(template_name, attributes) mandrill = Mandrill::API.new(ENV["SMTP_PASSWORD"]) merge_vars = attributes.map do |key, value| { name: key, content: value } end mandrill.templates.render(template_name, [], merge_vars)["html"] end end
I set up my
UserMailer
to inherit from this class and use the private methods to simplify mywelcome
email logic. This is where it is important to make sure you are referencing the same template name and merge variables as you used when you set up your template in Mailchimp.# app/mailers/user_mailer.rb class UserMailer < BaseMandrillMailer def welcome(user_id) user = User.find(user_id) subject = "Welcome to our awesome app!" merge_vars = { "FIRST_NAME" => user.first_name, "USER_URL" => user_url(user), } body = mandrill_template("welcome", merge_vars) send_mail(user.email, subject, body) end end
Iterate on email styles and copy to your heart’s content
You’re done! Time to celebrate.
From now on, anyone can go into Mailchimp to edit the template’s style and content. All someone needs to do to update system emails for your Rails app is make updates in Mailchimp and click the “Send to Mandrill” link. Just make sure the template name and merge variables stay the same or you’ll need to make changes on the Rails side, too.
It’s also easy to send test emails from within Mailchimp, which is great for sharing email content and iterations with stakeholders.
Make sure your environment variables are set on staging and production and then get going. Mandrill lets you send up to 12k emails per month for free, so if you think you will go over that, make sure you add some payment information to your Mandrill account, too.