E-mail in Rails with MailChimp and Mandrill, a comprehensive guide


This tutorial walks through adding e-mail to a Rails app, using MailChimp and Mandrill. We will:

  1. Add new users to a mailing list
  2. Send a welcome e-mail to new users
  3. Alert users when something happens in the app

Our example app is Puppify, an aggregator of cute puppy videos. Read the tutorial, and then check out the source.

Mailing lists vs. transactional e-mails

It is important to distinguish your app’s mailing list from its transactional e-mails. Generally, a mailing list is used for periodic announcements and marketing e-mails, while transactional e-mails are used to notify individual users of specific events.

Mailing lists

Mailing lists handle messages sent to all or many of your users. For instance, you might send a monthly update about new features, or promote a sale on gift certificates.

MailChimp is a popular tool for managing mailing lists. It’s free for many smaller lists.


Transactional e-mails are sent to individual users in response to particular events.

Events might include:

  1. The customer was billed.
  2. A new video was posted to a category that the customer chose to monitor.
  3. A charge to the customer’s credit card failed.

When an action above occurs, we need to notify a particular user – or, as we cover in Advanced Transactional E-mail, multiple users.

Mandrill, from the folks at MailChimp, is a popular tool for sending transactional e-mails. It’s free for apps with low e-mail volumes.

Mailing lists: Getting started with MailChimp

MailChimp is great at sending e-mail to a bunch of people at once. Typically, you would use it for marketing e-mails, service updates, and other messages to many or all of your users.

Sign up for MailChimp

Go to the MailChimp web site and sign up for a free account. On your dashboard, create a new list.

There are two pieces of information you will need from your MailChimp account: your API key, and the list ID you will be using for your app.

To get your API key, click your first name on the top right of the dashboard, then go to Account.

Screen Shot 2015-04-07 at 6.27.32 PM

Under the Extras menu, click API Keys.

Screen Shot 2015-04-07 at 6.28.20 PM

Finally, generate a new key. Your new key will appear. Make a note of it.

Next to get your list ID, go to Lists on the left side of your dashboard, and click the List you created. Then go to Settings, and List Name and Defaults.

Your list ID will appear there:

Screen Shot 2015-02-15 at 6.56.30 PM

In this example, your list ID is 148b2f05c5.

Storing your API key

Your MailChimp API key is a gateway to your customers’ personal information. Keep it safe and private.

A best practice in any Rails app is to store confidential information like API keys in environment variables, not directly in your code.

In our development environment, we will use a tool called dotenv to store the API keys outside of our code. We’ll also store our list ID in dotenv, just to keep our MailChimp info in one place.

First, add dotenv to your gemfile:

Next, run bundle install in your app directory.

Then, add a .env file to your project’s root:

MailChimp offers only one set of API keys per account, for use in both development and production. Under this scenario, any e-mail you send in development will go to your production mailing lists. To avoid a mistake, either do not send MailChimp e-mails in development or create a separate development MailChimp account and use those API key and list keys in your .env file.

If your .env file contains production API keys, you may wish to not commit it to source control. This is the word from the creator of dotenv, from the project’s readme:

Personally, I prefer to commit the .env file with development-only settings. This makes it easy for other developers to get started on the project without compromising credentials for other environments. If you follow this advice, make sure that all the credentials for your development environment are different from your other deployments and that the development credentials do not have access to any confidential data.

When you deploy to production, you will need to set environment variables there, as well. Dotenv does not do this for you. Services like Heroku offer easy ways to set environment variables in production.

Install the gibbon gem for MailChimp

We will be using Gibbon, a popular and unofficial interface to the MailChimp API. This book uses MailChimp’s API 2.0, which differs significantly from 1.x.

To install gibbon, add the following line to your gemfile:

Then, run bundle install in your app directory.

Configure gibbon

Gibbon needs your MailChimp API key. To provide this, create config/initializers/gibbon.rb:

We are setting throws_exceptions, so we are alerted to any issues right away in development. It will also throw exceptions in production, so you may wish to change it later.

Start your app, make sure the correct API key is printed to the console, and remove the last line in the code above.

Good to go!

We’re now set up to use MailChimp! We’ve taken the time to properly store our API key outside of the code.

Subscribe users to your MailChimp list

Puppify has the best puppy videos in the game, and very loyal customers. We want to keep those customers up to date as we improve, so we’ll want them on our mailing list.

Let’s automatically add users to our MailChimp mailing list when they sign up.

Add a background job for subscribing each new user

Adding a user to a MailChimp list takes a bit of time, as your app has to communicate with MailChimp’s API. There is no reason the user should have to wait for this to complete.

Traditionally, tasks like this have been done in background jobs. Rails 4.2 or later offers Active Job, an easy way to perform these tasks without making the user wait.

In the app directory, run a command to generate a new job:

This generates app/jobs/subscribe_user_to_mailing_list.rb:

Customize the job to accept a user parameter and subscribe the user to the MailChimp list:

Finally, in the User model, add an after_create hook to run the job after a new user is created:

This passes the newly created user to the job, which then subscribes that user to the mailing list.

ActiveJob is smart enough to perform the subscription right away if you do not currently have a background processing gem. See Adding a Background Job Processor.

If you try to sign up for Puppify without an internet connection, you’ll see an error. This is because the MailChimp subscribe command is not actually running in the background. If we added a background processor, the connection failure to MailChimp would not impact the sign-up process.

Screen Shot 2015-02-17 at 11.42.25 AM

Add additional information about each user

Right now, in MailChimp, you are storing only e-mail addresses. What if you want to personalize e-mails with a user’s first name? What if you want to send targeted e-mails to users who are on certain subscription plans (to encourage them to upgrade, for instance)?

You can store this additional information in MailChimp, right alongside customers’ e-mail addresses, by using “merge fields.”

In MailChimp, add merge fields for first name and last name.

Go to the Merge Field section of under your MailChimp list’s settings:

Screen Shot 2015-02-17 at 12.38.31 PM

Ensure that FNAME and LNAME are included:

Screen Shot 2015-02-17 at 12.39.00 PM

Finally, include the first name and last name when you send a new subscriber to MailChimp:

Check out MailChimp’s documentation on its subscribe command for an explanation of the code above.

Now, if someone registers with a first name and last name, those names will appear on MailChimp as merge fields:

Screen Shot 2015-02-17 at 12.43.44 PM

You can use merge vars to personalize e-mails. If you later include information like subscription plan, you can use merge vars to target e-mails to particular groups of users.

Transactional e-mails: Getting started with Mandrill

Transactional e-mails are sent to individual users in response to particular events. Examples include receipts, welcome e-mails, and other personalized notifications.

Mandrill is a popular service for sending transactional e-mails. It is run by and integrates with MailChimp, is free for apps with low e-mail volume, and provides rich reporting on e-mail bounces and opens.

Using a service like Mandrill decreases the likelihood that your messages will be marked as spam.

Sign up for Mandrill

Visit the Mandrill web site and sign up for a free account. You do not need to provide any credit card information, as Mandrill is free for many sites.

Screen Shot 2015-04-07 at 6.32.46 PM

Obtain a Mandrill API key

Click Get SMTP Credentials on the Mandrill dashboard, then click New API Key.

Screen Shot 2015-04-07 at 6.33.56 PM

Screen Shot 2015-04-07 at 6.44.49 PM

To get an API key appropriate for development, check the Test Key box. This will generate an API key that can be used for testing purposes; it will not actually send e-mails, but will log them in Mandrill for us to review.

Screen Shot 2015-04-07 at 6.38.50 PM

Your username is your Mandrill e-mail address, and your SMTP password will be new API key you just created, which will be listed.

Configure Mandrill in the app

Remember that we set up dotenv? Add your Mandrill username and TEST API key to to our .env file for development purposes:

Next, create or edit config/initializers/action_mailer.rb to include Mandrill’s SMTP address and your login:

Our first transactional e-mail

Let’s use transactional e-mail to welcome people to our service as soon as they sign up! You may use a welcome e-mail to provide an overview of the service or encourage people to fill out their profiles.

Set up ActionMailer template

The Rails Guide on Action Mailer Basics walks through this process.

First, create a mailer that will handle the actual task of e-mailing the user. Run this command on the console:

This will generate a file in app/mailers/user_mailer.rb. In that file, provide a default from address and add the first transactional e-mail, the welcome message sent to new users.

Next, create a template for the message at app/views/user_mailer/welcome_email.html.erb:

Send the e-mail

Add a second after_create hook to the User class. You created the first hook to subscribe users to your mailing list.

In the hook, call deliver_later on the welcome_email. This sends our e-mail using ActiveJob, which will connect to a background processor if one is installed.

Once you’ve added this code, go ahead and register for Puppify.

In the development environment, we’re using the Mandrill test API key. Switch to test mode in the Mandrill dashboard.

Screen Shot 2015-02-17 at 1.44.46 PM

You’ll see the welcome e-mail in the Mandrill API log under Settings > API Logs:

Screen Shot 2015-02-17 at 1.43.33 PM

The message will also show under Outbound E-mail after a few minutes.

Screen Shot 2015-02-17 at 1.45.28 PM

Quicker mail previews in development

Now that you know Mandrill SMTP integration is working, you can stop your development environment from actually communicating with Mandrill and instead render previews of messages as they’re sent.

Letter Opener launches a browser tab each time your app sends an e-mail in dev, showing the full contents of the message. While this does not replace automated tests, it is very helpful for ensuring that e-mail is working properly as you add new features.

Add the following to the gemfile:

Next, run bundle install in your app path to install the gem.

Tell ActionMailer to deliver any mail on dev to Letter Opener by adding the following to config/environments/development.rb

Now, when you register, your welcome message will pop up for you to review instead of actually sending.

Screen Shot 2015-02-17 at 1.53.39 PM

Another option: MailChimp automation

For a fee, you can use MailChimp’s automation features to send a welcome e-mail to anyone who is added to the list. This could replace the Mandrill welcome e-mail.

The pro is that you have less code in your app, and the con is that the logic of the welcome e-mail is no longer represented in your app, potentially making it more difficult to switch from MailChimp to a different service in the future.

Advanced transactional e-mail

Say that one event in your app impacts a lot of users, and they all need to be notified.

For instance, Puppify might allow a user to subscribe a category of videos. If 100 users subscribe to one category, and that category receives a new video, all 100 must be notified.

Rather than sending 100 separate e-mails through SMTP, we can make one request to Mandrill to send all 100. This saves time communicating with the API and ensures that the request is “all or nothing” – i.e. it succeeds or fails.

First, let’s create a category subscription mechanism in our app.

This is not a specific recommended approach, but one that serves the example of using the Mandrill API to send customized, event-driven bulk e-mail.

First, create a table:

We know we’ll be looking up all subscriptions for a given category in our example, so we’ll index that column.

And go ahead and create a model for category subscriptions:

Install the Mandrill gem

Next, install the Mandrill gem that will allow sending e-mail over an API rather than through SMTP.

In your gemfile, add the Mandrill gem:

Then, run bundle install.

Next, set your Mandrill API key in .env if you haven’t already. See previous sections on setting up the dotenv gem and registering for Mandrill:

Add an e-mail template

When a new video is posted, we want to notify all who have subscribed to that video’s category.

As before, start with an e-mail template. We’re not going to use it in the traditional manner, but we should have all our e-mail templates in the same place for consistency. Create a file at app/views/user_mailer/new_video_in_category_notification_email.html.erb:

Notify users

Say that 1,000 users subscribed to a category. Rather than sending 1,000 individual e-mails in individual background jobs, it might be wiser to e-mail all users at once. If we send all 1,000 recipients to Mandrill in one API call, Mandrill will handle them beautifully, reducing the overhead on our app.

First, add a hook that will call the notification job when a new video is added.

Next, generate the job:

Open app/jobs/send_new_video_in_category_notification_emails.rb and fill in the job:

The job performs the following steps:

  1. Retrieve all subscribers for the video
  2. Call the Mandrill API to send an e-mail to those subscribers, including the video information as global merge variables and the individuals’ first names as regular merge variables

Mandrill takes the burden of receiving 1,000 e-mail addresses and names, and then sending 1,000 individual e-mails, each personalized with the recipient’s name. This job uses the Action Mailer template we created above, even though we using Mandrill’s API instead of Action Mailer to send the message.

It’s an untraditional but efficient approach, first covered in Sending Mandrill E-mails from Rails, the MVC Way.

Adding a Background Job Processor

The Puppify example uses Active Job in Rails 4, which makes it easier to process actions in the background so users don’t have to wait.

ActiveJob looks for a background processor, and if it doesn’t find one, executes actions immediately instead of in the background.

There are many processors out there. One example is Sucker Punch, which could be a good starting point and does not require additional server setup. Other processors, like Sidekiq, may be more reliable but are also more complicated.


You’ve learned how to subscribe new users to your mailing list, send welcome e-mails, and notify multiple users when events happen in your app.

These cover only the general categories of e-mail your app might need. Every app’s e-mail strategy is unique. I wish you luck finding the right mix for yours!

Addendum: Competitors

By no means are MailChimp and Mandrill your only options.

Mandrill’s competitors include:

MailChimp’s competitors include:

Hired.com brings Rails job offers to you. Free for candidates. Salaries from $75,000 to $250,000. Sign up now!

13 thoughts on “E-mail in Rails with MailChimp and Mandrill, a comprehensive guide”

  1. Thank you for this post, One suggestion is that where you are looping though users in the convert_users_to_mandrill_merge_fields method you are making a separate database call for each find statement. It is probably better to get them all in one shot and then loop over the fields you need with the returned results.

  2. Hi. Thanks so much for your tutorial. With Gibbon 2.0 and MailChimp API v3, some of the syntax has changed. Can you update the tutorial to reflect these change? It’s been a struggle trying to figure out how things need to be changed. Thank you!

  3. Hey Corey, this is a great intro! I noticed you don’t really cover much about the templating part of setting up the emails, possibly because writing rich html emails is such a pain in the butt. You might want to check out the newly launched Foundation For Emails ruby integration, that lets you use clean semantic markup (rows, columns, etc) to write beautiful responsive html emails as quickly as you would a website. It integrates cleanly into Rails and plays nicely with all of the other integrations you mention in your post! We’d love any feedback you have: http://zurb.us/29eMWDG

    1. Thanks for your comment! I’m a big user of Foundation and Foundation for Emails. I’ve used both for Cook Smarts’ meal planning app and they’ve turned out great. I’ll definitely try to get a blog post in about templating. Cheers!

  4. Re: ‘Advanced transactional e-mail’ would it be possible to send email this way but with ‘body’ stored in MailChimp, not in Rails? My goal is to let the designer/UI dev work purely in MailChimp on templates and don’t pollute Rails API/server with more views.

    1. Yes, very possible. Mandrill will allow you to use templates, which I believe are portable between Mandrill and MailChimp, and insert values from your app into those templates.

      1. @Corey it’s indeed pretty easy:
        1. Send template (there’s a link in MC for this) from MailChimp to Mandrill, NOTE: only mc:edit or classic merge vars are available for dynamic content
        2. Use #send_template method from the Mandrill API gem and provide ‘template’ (name) and ‘template_content’ array (optional, contains content for replacing mc:edit tags)

Leave a Reply