Custom Rails Mailer and Mandrill

Using the Mandrill API with Action Mailer in Rails

Mandrill is a popular transactional email service created by the folks over at Mailchimp. There are a number of Mandrill community gems for Rails, but several motivations exist for wrapping the Mandrill API with Action Mailer, primarily if you envision possibly swapping out email providers in the future (i.e. quota limits and costs, different template preferences, etc.), or you want more control customizing the actual content and design of your emails beyond the Mandrill templates and templating language.

We’ll walkthrough how to customize Action Mailer to use Mandrill, while attempting to keep our code modular and straightforward:

  • Set up the Mandrill API and credentials
  • Create our Mailer and actions to populate the Mail object and render our message views
  • Create our Mandrill delivery model to send our object via the mandrill-api gem
  • Configure Action Mailer to use our custom Mailer

The Mandrill API Gem And Credentials

Sign up for a Mandrill account to receive your API key. Mandrill has a test sandbox with a separate API key I recommended using in your development environment. I typically keep my keys in my .zshrc / .bashrc file, and access it as an environmental variable (ENV[‘MANDRILL_APIKEY’]) when using them in my application. Then stick “gem mandrill-api” in your Gemfile and “bundle install”.

Basic Mailer Overview

Action Mailer can be divided into two conceptual components:

  • Mailer [/mailers/NotificationMailer.rb]: analogous to a Rails Controller, the Mailer populates a Mail object that stores our e-mail data; content, addresses, etc. We setup the Mailer as e-mail “actions” that render the appropriate view. In this case, our Mailer is for generic “notifications”, so we’ll call it notification_mailer. We’ll set it to “respond” to sign-up and order notifications and render the appropriate message content.

  • Delivery method [/models/MandrillDelivery.rb]: contains calls to the Mandrill API and related sending operations. While this modular setup is more work than quickly using a community gem, we are separating the content and behavior of our emails from the service we use to send them. We can easily have multiple Mailers, rendering different e-mail content, while selectively switching among transactional e-mail providers; perhaps Mandrill for all, or only a select handful of our emails.

Creating The Mailer

We’ll create the Mailer, and the appropriate view. Note the subscriber parameter that we’ll pass in later.

/mailers/notification_mailer.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class NotificationMailer < ActionMailer::Base

  default from: "[email protected]"

  def sign_up_notification(subscriber)

      @subscriber = subscriber

      mail(:to => @subscriber.email,
             :name => @subscriber.name,
             :subject => "Thanks for Signing Up",
             :unsub_link => unsub_email_link(@subscriber.email_token))   
  end

  def order_notification(subscriber)

      @subscriber = subscriber

      mail(:to => @subscriber.email)
  end

end

We have our notification mailer creating a Mail object given different scenarios / actions. These may be triggered by a background worker (or even in the controller itself, although less than ideal.) Now we create the appropriate views for each mail action.

/views/notification_mailer/sign_up_notification.html.haml
1
2
 %h1 Thanks #{@subscriber.name}, for signing up!
  %p We hope you enjoy our awesome blabla yada yada
/views/notification_mailer/order_notification.html.haml
1
2
   %h1 Thanks, #{@subscriber.name} for your order!
   %p We'll be sending it to #{@subscriber.address}

Similar to a Controller, we access instance variables in the mailer’s associated views to provide the data we need when rendering. The examples are simplistic, but hopefully illustrative.

Creating our Delivery Method

We’ll create a mandrill_delivery model with our deliver! method. It’ll be in charge of a) setting up a Mandrill message hash with appropriate meta-data, and then b) sending the message via the API.

In this particular example we’re using a template already set up on Mandrill. It will take our rendered sign-up confirmation message and insert it in the appropriate section of the template before sending.

models/mandrill_delivery.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
require 'mandrill'

class MandrillDelivery
  attr_accessor :message

  def initialize(mail)
  end

  def deliver!(mail)
    build_meta_mandrill(mail)
    send_mandrill(mail)
  end

#Message stuff

  def build_meta_mandrill(mail)

    #build Mandrill message hash
    @message = {
      :from_name=> "Admin",
      :from_email=>"[email protected]",
      :subject=> "#{mail['subject']}",
      :to=>[
            {
              :email=> "#{mail['to']}",
              :name=> "#{mail['name']}"
            }
           ],
      :auto_text => true,
      :global_merge_vars => [
                             {
                               :name => "LISTCOMPANY",
                               :content => "Company Name Here"
                             }
                            ]
    }

    true
  end

  #sends email via Mandrill
  def send_mandrill(mail)
    m = Mandrill::API.new

    sending = m.messages.send_template('Sign-Up Confirmation',
                                       [
                                        {
                                          :name => 'main',
                                          :content => "#{mail.body}"
                                        },
                                        {
                                          :name => 'unsub',
                                          :content => "#{mail['unsub_link']}"
                                        }
                                       ],
                                       message = @message)
    Rails.logger.info sending
  end

end

Configure Your Custom Action Mailer

Lastly, a pretty straightforward configuration addition to link everything together. Create a mailer.rb file with the following in you Rails application directory config/initializers/.

/config/initializers/mailer.rb
1
   ActionMailer::Base.add_delivery_method :mandrill_delivery, MandrillDelivery

We use our newly assigned delivery method “mandrill_delivery” in our environmental configuration, choosing our dev or production environments accordingly.

/config/environments/production.rb
1
2
3
4
5
6
7
8
   #...stuff

   config.action_mailer.default_url_options = { :host =>
   'www.yourhostnamehere.com' }

   config.action_mailer.delivery_method = :mandrill_delivery

   #...other good stuff   

Likely the most confusing part about setting up a custom Mailer lies in the fact that the class never gets instantiated – we configure our application to use our new delivery method (mandrill_delivery) and, like controllers and views, Rails takes care of rendering the message appropriately. A background job or even a rake task calling NotificationMailer.sign_up_notification(subscriber).deliver will trigger the whole procedure.

1
2
#launches the whole procedure - to be called from a worker
NotificationMailer.sign_up_notification(subscriber).deliver

While the examples are simple, hopefully this provides a clear picture of customize Action Mailer with Mandrill.

Comments