Tools for writing HTML emails

At Swiftype, we send quite a few emails to our users, so I needed to pick up some tools to make sure they look right. HTML email display is very fragmented. Making an email that looks OK in the majority of clients is like going back to writing HTML for Netscape and IE 4.

Here’s some tools that have been helpful to me:

Rails 3 has great support for writing multipart HTML emails. This is pretty basic, but the HTML email support in Rails is worlds away better than Rails 2, which is what I used the last time I had to send HTML emails. The refactoring that brought Action Mailer in line with Action Controller has really paid dividends.

In Rails 2, sending multipart emails looked like this (example adapted from Rails 2.3 Action Mailer Basics Guide:

class UserMailer < ActionMailer::Base
  def welcome_email(user)
    recipients      user.email_address
    subject         "New account information"
    from            "system@example.com"
    content_type    "multipart/alternative"
 
    part "text/html" do |p|
      p.body = render_message("welcome_email_html", :message => "<h1>HTML content</h1>")
    end
 
    part "text/plain" do |p|
      p.body = render_message("welcome_email_plain", :message => "text content")
    end
  end
end

In Rails 3, this was simplified considerably.

Action Mailer will automatically send multipart emails if you have different templates for the same action. So, for our UserMailer example, if you have welcome_email.text.erb and welcome_email.html.erb in app/views/user_mailer, Action Mailer will automatically send a multipart email with the HTML and text versions setup as different parts.

RSpec helpers make testing the emails easier. I’m not using email-spec, just a few matchers I wrote to help out with this. They let me write simple tests like this:

describe LifecycleMailer do
  let(:user) { FactoryGirl.create(:user) }
 
  context 'welcome' do
    subject(:mail) { LifecycleMailer.welcome(user.id.to_s) }
 
    it { should have_subject("Welcome to Swiftype! Here's some tips help to get you started.") }
    it { should have_full_name_in_to_field(user) }
    it { should be_multipart }
    it { should have_mailgun_campaign('lifecycle_welcome_none') }
    it { should be_from('"Matt Riley, Swiftype" ') }
  end
end

The helpers look like this:

RSpec::Matchers.define :have_subject do |subject|
  match do |mail|
    mail.subject.should == subject
  end
 
  failure_message_for_should do |actual|
    "expected subject to be '#{subject}' but was '#{actual.subject}'"
  end
end

mail_view by 37signals is a great gem that embeds a small Rack app in your Rails app that lets you view your emails (both HTML and plain-text). I’m using a fork that puts the generated HTML into an iframe, which makes it possible to view the generated HTML by itself, and also extract the HTML for pasting into other tools. It would be nice if that was merged, because it’s an important feature for me.

Litmus is a terrific email testing service that will show you what your email looks like in differrent browsers, email services, and mobile devices. Litmus helped me fix a number of webmail problems in IE. My only complaint with Litmus is I wish it had a pay-per-test option. We primarily use one email layout, so we don’t test enough email to justify a monthly account.

Mailgun makes it easy to configure email delivery in development (as opposed to using Sendmail, for example). That’s not generally recommended, of course, but with a quick configuration change, I can view real emails in my personal accounts, or email them to Litmus.

W3C’s Markup Validation Service helps track down tricky HTML errors. After verifying the emails in mail_view, I view the raw source and paste it into the validator. This picked up some HTML errors that choked up Gmail, but that Chrome glossed over when viewing in mail_view.

Campaign Monitor’s guides to HTML and CSS for email are a great resource for how to write emails that work across different clients.