Responsive emails that really work

Posted by kevingessner | Filed under engineering, mobile

If you’ve ever written an HTML email, you’ll know that the state of the art is like coding for the web 15 years ago: tables and inline styles are the go-to techniques, CSS support is laughably incomplete, and your options for layout have none of the flexibility that you get on the “real web”.

Just like everywhere online, more and more people are using mobile devices to read their email.  At Etsy, more than half of our email opens happen on a mobile device!  Our desktop-oriented, fixed-width designs are beautiful, but mobile readers aren’t getting the best experience.

We want our emails to provide a great experience for everyone, so we’re experimenting with new designs that work on every client: iPhone, iPad, Android, Gmail.com, Outlook, Yahoo Mail, and more.  But given the sorry state of CSS and HTML for email, how can we make an email look great in all those places?

Thanks to one well-informed blog commenter and tons of testing across many devices we’ve found a way to make HTML emails that work everywhere.  You get a mobile-oriented design on phones, a desktop layout on Gmail, and a responsive, fluid design for tablets and desktop clients.  It’s the best of all worlds—even on clients that don’t support media queries.

A New Scaffolding

I’m going to walk you through creating a simple design that showcases this new way of designing HTML emails.  It’s a two-column layout that wraps to a single column on mobile:

Layout

For modern browsers, this would be an easy layout to implement—frameworks like Bootstrap provide layouts like this right out of the box.  But the limitations of HTML email make even this simple layout a challenge.

Client Limitations

What limitations are we up against?

  • Android’s Gmail.app only supports inline CSS in HTML style attributes—no <style> tags, no media queries, and no external stylesheets.
  • Gmail.com supports a limited subset of HTML, stripping out many tags (including all of the tags in HTML5) and attributes (including classes and IDs), and only allows some inline CSS and a very limited subset in <style> tags (more on this later).
  • The iOS and Mac OS X Mail apps support media queries and a large selection of CSS.  Of all clients, these are most like a modern browser.

On to the Code

Let’s start with a simple HTML structure.

<html>
 <body>
   <table cellpadding=0 cellspacing=0><tr><td>
     <table cellpadding=0 cellspacing=0><tr><td>
       <div>
         <h1>Header</h1>
       </div>
       <div>
         <h2>Main Content</h2>
         <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec gravida sem dictum, iaculis magna ornare, dignissim elit.</p>
         <p>...</p>
       </div>
       <div>
         <h2>Sidebar</h2>
         <p>Donec tincidunt tincidunt nunc, eget pulvinar risus sodales eu.</p>
       </div>
       <div>
         <p>Footer</p>
       </div>
     </td></tr></table>
   </td></tr></table>
 </body>
</html>

It’s straightforward: a header and footer with two content areas between, main content and a sidebar.  No fancy tags, just divs and tables and paragraphs—we’re still partying like it’s 1999.  (As we apply styling, we’ll see why both wrapping tables are required.)

Initial Styling

Android is the least common denominator of CSS support, allowing only inline CSS in style attributes and ignoring all other styles.  So let’s add inline CSS that gives us a mobile-friendly layout of a fluid single column:

<html>
 <body style="margin: 0; padding: 0; background: #ccc;">
   <table cellpadding=0 cellspacing=0 style="width: 100%;"><tr><td style="padding: 12px 2%;">
     <table cellpadding=0 cellspacing=0 style="margin: 0 auto; background: #fff; width: 96%;"><tr><td style="padding: 12px 2%;">
     <div>
       <h1>Header</h1>
     </div>
     <div>
       <h2 style="margin-top: 0;">Main Content</h2>
       <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec gravida sem dictum, iaculis magna ornare, dignissim elit.</p>
       <p>...</p>
     </div>
     <div>
       <h2 style="margin-top: 0;">Sidebar</h2>
       <p>Donec tincidunt tincidunt nunc, eget pulvinar risus sodales eu.</p>
     </div>
     <div style="border-top: solid 1px #ccc;">
       <p>Footer</p>
     </div>
     </td></tr></table>
   </td></tr></table>
 </body>
</html>

It honestly doesn’t look that different from the unstyled HTML (but the groundwork is there for your beautiful ideas!).  The table-within-a-table wrapping all the content lets us have our content area in a colored background, with a small (2%) gutter on each side.  Don’t forget the cellspacing and cellpadding attributes, too, or you’ll get extra spacing that can’t be removed with CSS!

Screen Shot 2014-03-12 at 12.03.47 PM.png

Dealing with Gmail

This design is certainly adequate for both mobile and desktop clients, but it’s not the best we can do.  Desktop clients and large tablets have a lot of screen real estate that we’re wasting.

Our main target here is Gmail—desktop and laptop screens keep getting bigger, and we want Gmail users to get a full-width experience.  But Gmail doesn’t support media queries, the go-to way of showing different layouts on different-sized clients.  What can we do?

I mentioned earlier that Gmail supports a small subset of CSS inside <style> tags.  This is not a widely known feature of Gmail—most resources you’ll find tell you that Gmail only supports inline styles.  Only a handful of blog comments and forum posts mention this support.  I don’t know when Gmail’s CSS support was quietly improved, but I was certainly pleased to learn about this new way of styling my emails.

The subset of CSS that Gmail supports is that you are limited to only using tag name selectors—no classes or IDs are supported.  Coupled with Gmail’s limited whitelist of HTML elements, your flexibility in styling different parts of your email differently is severely limited.  Plus, the <style> tag must be in the <head> of your email, not in the <body>.

The trick is to make judicious use of CSS’s structural selectors: the descendant, adjacent, and child selectors.  By carefully structuring your HTML and mixing and matching these selectors, you can pinpoint elements for providing styles.  Here are the styles I’ve applied to show a two-column layout in Gmail:

        <head>
          <style type="text/css">
/*  1 */    table table {
/*  2 */      width: 600px !important;
/*  3 */    }
/*  4 */    table div + div { /* main content */
/*  5 */      width: 65%;
/*  6 */      float: left;
/*  7 */    }
/*  8 */    table div + div + div { /* sidebar */
/*  9 */      width: 33%;
/* 10 */      float: right;
/* 11 */    }
/* 12 */    table div + div + div + div { /* footer */
/* 13 */      width: 100%;
/* 14 */      float: none;
/* 15 */      clear: both;
/* 16 */    }
          </style>
        </head>

In the absence of classes and IDs to tell you what elements are being styled, comments are your friend!  Let’s walk through each of these selectors.

Lines 1-3 lock our layout to a fixed width.  Remember, this is our style for Gmail on the desktop, where a fluid design isn’t our goal.  We apply this to the inner wrapping table so that padding on the outer one remains, around our 600-pixel-wide content.  Without having both tables, we’d lose the padding that keeps our content from running into the client’s UI.

Next, we style the main content.  The selector on line 4, reading right to left, finds a div immediately following another div, inside a table.  That actually matches the main content, sidebar, and footer divs, but that’s OK for now.  We style it to take up the left two thirds of the content area (minus a small gutter between the columns).

The selector on line 8 styles the sidebar, by finding a div following a div following a div, inside a table. This selects both the footer and the sidebar, but not the main content, and overrides the preceding styles, placing the sidebar in the right-hand third of the content.

Finally, we select the footer on line 12—the only div that follows three others—and make it full-width.  Since the proceeding selectors and styles also applied to this footer div, we need to reset the float style back to none (on line 14).

With that, we have a two-column fixed layout for Gmail, without breaking the one-column view for Android:

Screen Shot 2014-03-12 at 11.30.41 AM.png

The styles we applied to the outer wrapping table keep our content centered, and the other inline styles that we didn’t override (such as the line above the footer) are still rendered.

For Modern Browsers

Finally, let’s consider Mail.app on iOS and Mac OS X.  I’m lumping them together because they have similar rendering engines and CSS support—the media queries and full CSS selectors you know and love all work.  The styles we applied for Gmail will be also applied on iPhones, giving a mobile-unfriendly fixed-width layout.  We want Android’s single-column fluid layout instead.  We can target modern, small-screen clients (like iPhones) with a media query:

/* Inside <style> in the <head> */
@media (max-width: 630px) {
  table table {
    width: 96% !important;
  }
  table div {
    float: none !important;
    width: 100% !important;
  }
}

These styles override the earlier ones to restore the single-column layout, but only for devices under 630 pixels wide—the point at which our fixed 600-pixel layout would begin to scroll horizontally.  Don’t forget the !important flag, which makes these styles override the earlier ones.  Gmail.com and Android will both ignore this media query.  iPads and Mail.app on the desktop, which are wider than 630 pixels, will also show the desktop style.

This is admittedly not the prettiest approach. With multiple levels of overriding selectors, you need to think carefully about the impact of any change to your styles.  As your design grows in complexity, you need to keep a handle on which elements will be selected where, particularly with the tag-only selectors for Gmail.  But it’s nearly the holy grail of HTML email: responsive, flexible layouts even in clients with limited support for CSS.

The biggest caveat of this approach (besides the complexity of the code) is the layout on Android tablets: they will display the same single-column layout as Android phones.  For us (and probably for you, too), Android tablets are a vanishingly small percentage of our users.  In any case, the layout isn’t unusable, it’s just not optimal, with wide columns and needlessly large images.

Bringing it All Together

You can find the complete code for this example in this gist: https://gist.github.com/kevingessner/9509148

You can extend this approach to build all kinds of complex layouts.  Just keep in mind the three places where every item might be styled: inline CSS, tag-only selectors in a <style> tag, and one or more media query blocks.  Apply your styles carefully, and don’t forget to test your layout in every client you can your hands on!

I hope that in the future, Gmail on the web and on Android will enter the 21st century and add support for the niceties that CSS has added in recent years.  Until then, creating an HTML email that looks great on every client will continue to be a challenge.  But with a few tricks like these up your sleeve, you can make a beautiful email that gives a great experience for everyone on every client.

You can follow me on Twitter at @kevingessner

Want to help us make Etsy better, from email to accounting? We’re hiring!


5 responses to Responsive emails that really work

  • Great article! I also didn’t know Gmail Desktop supported STYLE tags. Good info.

    But for me this seems a potentially broken approach, not future friendly. What happens when Gmail Mobile adds support for STYLE tags too. This whole approach will break. It seems to me that it’s best not to rely on this difference between Gmail Desktop an Mobile.

  • bradleyhh says:

    Great post! We intend to use a version of this for our next round of emails.

  • Ezy-E says:

    Thanks for sharing this code. Tried it. Works well for Gmail (desktop and mobile app), but not Samsung devices.Doesn’t work well in Outlook – the main area become fluid, so on large monitors it becomes too wide.

  • deanmorganekm says:

    I’ve just tested this out using the example code provided (without any amendments) and on every mail client I tested (gmail desktop, gmail mobile & outlook.com desktop) it appears as a single column display with the sidebar sitting underneath the main content.

    I’m just wondering if things have changed since this was posted, the example is incorrect, or if I am perhaps doing something wrong.

    Any help would be appreciated as I thought I had struck gold when I stumbled across this post.

  • beeeees says:

    wow. that gmail suggestion is blowing my mind. thank you, cant wait to try.

  • Leave a Response

    Recent Posts

    About

    Etsy At Etsy, our mission is to enable people to make a living making things, and to reconnect makers with buyers. The engineers who make Etsy make our living with a craft we love: software. This is where we'll write about our craft and our collective experience building and running the world's most vibrant handmade marketplace.

    Code as Craft is proudly powered by WordPress.com VIP and the SubtleFlux theme.

    © Copyright 2014 Etsy