Pretty image
Dave Hoover was instrumental in Michael Koziarski's revamping of our email system at Pragmatic Programmers.

The design and delivery of HTML email is a pain. It’s also a solved problem, so why not use the existing Web APIs to do the heavy lifting? In this article I work through three quick scenarios where a Ruby developer can outsource email functionality by integrating with an email marketing service.

There are many existing email marketing services with APIs, such as Constant Contact, iContact, and MailChimp. In this article, I’m going to show examples of integrating with Mad Mimi, a more recent player in the email marketing space. The principles here should work with any service; I’m using Mad Mimi because it makes it more concrete to use a specific tool and, well, because I know Mad Mimi very well. I’m the lead developer.

The first two scenarios focus on a typical Rails application, and then the final scenario shows general-purpose integration.

Scenario 1: Out of the HTML Business

If you’re ready to throw your failed attempts at email design out the window, or you’re starting a Rails app from scratch and don’t have the budget to put any research and development into making your HTML emails look perfect, you can set up the emails using the WYSIWYG-style tools that many email marketing services provide. Ideally, someone other than you (like, someone non-technical) can take on this task. These services have already gone through the effort of creating an HTML template that is optimized for all known email clients, and in most situations, there is no compelling reason for you to reinvent that wheel.

The simplest way to accomplish this integration with the Mad Mimi service is via the mad_mimi_mailer Ruby gem. This gem extends ActionMailer::Base to give you a remarkably familiar API.

 class UserNotifier < MadMimiMailer
  def mimi_welcome(user)
  subject "Welcome to WidgetHub"
  recipients user.email
  bcc ADMIN_PEEPS
  from "system@example.com"
  body :username => user.name,
  :email => user.email,
  :password => user.password
  end
 end

Let’s walk through this example. First, instead of inheriting from ActionMailer::Base, we’ve inherited from MadMimiMailer. You would have needed to install and configure the mad_mimi_mailer gem in your environment in order for the MadMimiMailer class to be available. You would have also needed to configure your Mad Mimi API credentials so that the MadMimiMailer can authenticate to the web service. This is unsurprisingly simple:

 MadMimiMailer.api_settings = {
  :username => 'dave@example.com',
  :api_key => '75a6c6f1SomeFakeApiKeycbcc300'
 }

The rest of the method looks exactly like you’d expect an ActionMailer::Base class to look. Then, what actually happens when you call UserNotifier.deliver_mimi_welcome(current_user)? First, the mimi_ prefix tells MadMimiMailer to step in and handle the delivery. Without that mimi_ prefix, the delivery is handled like a normal ActionMailer::Base. MadMimiMailer grabs the rest of the method name welcome, passes that name to Mad Mimi along with the rest of the data you’ve passed in, and sends your welcome promotion to the recipient you’ve specified.

The biggest difference between a typical ActionMailer::Base and a MadMimiMailer is the body hash. Typically, the body method takes a hash of any sort of Ruby objects, often ActiveRecord::Base instances. But when you’re calling out to Mad Mimi, you need to pass in a simple hash of strings. This will, naturally, evolve over time, and as Mad Mimi’s Mailer API grows in popularity, more powerful templating features will be supported, but for now, the keys of the body hash will expect to match their counterparts inside {curly} braces in your Mad Mimi “promotion.” So, for the example above, you would expect to find {username}, {email}, and {password} somewhere in the body of the content. The values need to be plain old strings.

That’s how you do it with Mad Mimi, and you could do something similar with any other email marketing service that supports this functionality. The beautiful thing about this approach is that once it’s set up, non-technical people can change the design and content of your emails without involving developers. They just need to be careful of the {placeholders} and not rename the promotion.

Scenario 2: Sticking to Your Guns

If you’re comfortable designing excellent HTML emails, or have someone who can do it for you, there are still some good reasons to outsource the delivery of those emails to a service.

First and foremost, while your site is under development, or even in the first few months while it is still small and sending relatively few emails, all of your emails will magically appear in inboxes instantaneously. But as you grow, and you’re sending hundreds, thousands, and tens of thousands of emails a day, suddenly your deliverability will begin to suffer unless you start learning the black magic of email deliverability. Unless email is the core of your application, email deliverability is a distraction and should be handed off to a service that has already solved these tough problems for you.

Secondly, one of the most important features of an email marketing service is statistics. Standard stats include reads, clicks, opt-outs, forwards, and bounces. You get all of this information automatically from the email marketing service.

Here’s the Mad Mimi approach. Given that you want to stick with your standard ERB-based emails, simply let MadMimiMailer know:

 class UserNotifier < MadMimiMailer
  def mimi_welcome(user)
  use_erb true
 
  subject "Welcome to WidgetHub"
  recipients user.email
  bcc ADMIN_PEEPS
  from "system@example.com"
  body :user => user
  end
 end

In this case, we call use_erb to tell MadMimiMailer to use the typical Rails ERB template, mimi_welcome.text.html.erb, to send the email. This means we don’t need to have any emails set up within the service beforehand (like we did in the last example). Also, since we’re using ERB, there’s no longer any reason to flatten out the user object into strings, so we simply pass in the object for use in the template.

One less obvious requirement of using the ERB approach is that you need to include the following placeholder somewhere in your template:

 [[peek_image]]

Typically, people wrap that image in an invisible p tag:

 <p style="visibility:hidden;" title="Web beacon">
  [[peek_image]]
 </p>

This placeholder is used by the service to jam a little img tag into the email, which triggers a request back to the service, letting it know that the recipient opened their email, which is obviously critical for gathering statistics about your users’ behavior.

Scenario 3: Just the Facts, Ma’am

If the MadMimiMailer feels too magical, or you need lower-level control over the call to the API, it’s relatively straightforward to drop down to Ruby’s net/http library to make the call. If I wanted to mimic the core behavior of my first example, the underlying code would look like this:

 body = {
  :username => user.name,
  :email => user.email,
  :password => user.password
 }
 
 params = {
  'username' => 'dave@example.com',
  'api_key' => '75a6c6f1SomeFakeApiKeycbcc300',
 
  'promotion_name' => 'welcome',
  'recipients' => user.email,
  'subject' => 'Welcome to WidgetHub',
  'bcc' => ADMIN_PEEPS,
  'from' => 'system@example.com',
  'body' => body.to_yaml
 }
 
 url = URI.parse('https://madmimi.com/mailer')
 request = Net::HTTP::Post.new(url.path)
 request.set_form_data(params)
 http = Net::HTTP.new(url.host, url.port)
 http.use_ssl = true
 response = http.start do |http|
  http.request(request)
 end

There’s nothing very fancy going on here. The only out-of-the-ordinary detail is that I’m serializing the body hash into YAML before I post the request. If I wanted to use my own HTML rather than a pre-existing email that’s been set up in the service, I would simply swap out the body parameter with the raw_html parameter, whose value is, not surprisingly, a bunch of raw HTML (this is what use_erb uses in MadMimiMailer) instead of a hash. And just like in ERB-based approach above, you’ll want to ensure that [[peek_image]] is included in the HTML string.

This Mailer API from Mad Mimi is just the tip of the iceberg of what email marketing service APIs can take off your plate. Other API features include campaign statistics, list importing, list sync’ing, and list management. We’re living in a time when an increasing number of peripheral services can be outsourced from our projects, allowing smaller teams to focus more intensely on the heart of the problems they are trying to solve.

In this article, I’ve focused on email design and deliverability, which is just one of many services that are experiencing extremely rapid uptake in our industry, such as source control (GitHub), continuous integration (RunCodeRun), functional web tests (Sauce Labs) and of course, our CPUs (Amazon EC2) and hard disks (Amazon S3). I hope this article is the beginning of the end to your email struggles!

Some useful links: Mad Mimi Mailer Ruby gem, Mad Mimi API, Reviews of top 10 email marketing services.

Dave authored the book Apprenticeship Patterns: Guidance for the Aspiring Software Craftsman for O’Reilly, instigated the Software Craftsmanship North America conference, and is the Chief Craftsman at Obtiva. Dave began teaching himself to program in 2000, back when he was a family therapist. Dave lives near Chicago with his wife and three children. In his spare time, Dave competes in endurance sports.