the word "email" displayed using keyboard keys that look like scrabble tiles

The wacky world of HTML email development

by

in

I recently decided I wanted to create a newsletter template from scratch. I’m (over)subscribed to a huge number of newsletters and I’ve noticed most of them are very similar — aka plain. The ones that go the extra mile to create beautiful custom designs really stand out and leave an impression. ✨

Since I’m confident in my HTML/CSS skills I figured building an email template would be easy-peasy. Maybe an hour’s worth of work. Turns out I was wrong. Very wrong.

If you’re a web developer then you know that there are some differences between browsers in how they render HTML and CSS. Most of the time these differences are negligible and can be fixed easily by adding a prefix. This usually happens because browsers release features at different times and sometimes have to play catch up with each other. But they’re all moving in the same direction, innovating together toward a set of common features. The harmony of web standards after the brutal browser wars. 🙌

Well, there’s no harmony in email development. There are a ton of email clients and absolutely no standards to unite them. Trying to optimize for one client will likely break your code in another. What. A. Mess. It’s enough to give a veteran web developer PTSD flashbacks.

I almost backed out, but instead I tripped and fell into the email dev’s deep dark rabbit hole. 🕳️

Here’s what I learned.

The battle of the Email clients

The way that an email is rendered depends on the client that it’s opened in. An email client’s ability to render an HTML email correctly ranges widely from Apple Mail (💖) to Microsoft Outlook (😭).

Apple mail is the best. It’s basically safari without Javascript. Which means you can create awesome interactive components for your emails. On the other hand, the Outlook desktop app uses Microsoft Word as a rendering engine…. 🤦‍♀️

Because of this, email devs everywhere are forced to use tables to create their layouts (instead of the usual modern options like flexbox or grid that we know and love).

Why Microsoft? WHY!?

Microsoft released their eponymous word processor back in 1983. To create layouts in MS Word you have to use tables. When Microsoft released MS Outlook in 2007 they incorporated Word’s word processing engine. I guess compatibility wasn’t a top priority at the time.

Note: Microsoft finally started to use a better rendering engine in 2022, but there’s still a lot of people out there using older versions of Outlook, so all the old advice still applies.

Apple Mail and Gmail are by far the two most popular email clients. Unfortunately Outlook is 4th on the list. Out of all the clients, it’s the biggest pain in the ass, but lots of people use it, so I guess we can’t ignore it.

We want to make sure our emails render correctly for as many users as possible, so we need to consider a wide variety of risk factors and then preemptively put measures in place to prevent our code from breaking.

If you want to dive deeper into what makes rendering HTML emails so terrifying complex, check out this article by the Modern Marketing Blog.

Let’s figure out how to make it work.

For each problem there are a few different methods that could work.

One of the challenges I faced when researching this topic is that there are a ton of different opinions on how to handle rendering issues and mail clients push little updates all the time. I had to sift through a lot of info to determine for myself which client quirks are still relevant, and which solutions still do the trick.

Let’s walk through the code and I’ll explain what’s going on.

If you’re familiar with caniuse (an awesome reference that shows you which modern web features are supported by each browser), you’ll love the email dev’s equivalent called caniemail. It’s an invaluable resource that I highly suggest checking out.

Configuring the document

Set up your HTML email foundation

Doctype

First thing’s first— doctype.

All HTML documents begin with a doctype to let the browser or email client know what kind of markup to expect and how to render your content properly. Technically, if you choose the wrong doctype your email will be displayed in “quirks mode.” It won’t completely break your content, but it won’t look exactly how you want.

💡 The quirks of quirks mode

  • CSS class and id names are case insensitive
  • Unit-less numbers in CSS are automatically interpreted as pixels
  • You can’t apply display:block to <td>, but you can apply it to <th>

I’m going to explain the different options and then let you know which one I would choose. Don’t stress about this too much. In the end, even if you choose the “correct” doctype, some email clients will go in and rip it out anyway. 😅

The doctype you choose dictates which HTML elements are available for you to use. W3Schools has a handy table of all HTML elements, and what Doctype each element appears in.

The contestants:

  • HTML5
    • HTML5 is what developers today are most familiar with. It’s the doctype that all modern websites are written in & fortunately these days it’s also widely accepted doctype for email.
<!DOCTYPE html>
  • HTML 4.01 (Transitional)
    • HTML4 is not very common and email clients will likely either not support it, or treat it as HTML5.
    • You can’t set a <td> to display:block in HTML4 but you can in HTML5.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  • XHTML
    • XHTML (extensible hypertext markup language) used to be the de facto standard for emails because it was the most widely supported form.
    • XHTML doctypes require the use of body tags—<html>, <head>, <body>, etc.— and HTML does not.
    • XHTML doctypes also help to interpret “bad” markup. This is an issue for many small devices, as they simply don’t have the resources or power to interpret poor HTML coding, and XHTML allows these devices to read the markup and render the document.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

The winner:

I personally would go with HTML5. It’s supported by 74% of email clients (source: caniemail ), and some clients only support the HTML5 doctype.

My target audience is young consumers reading email on their phone, but if my target audience was enterprise employees reading emails at work on Outlook 2007, then I might consider XHTML.

HTML

The HTML tag defines the language as HTML, which is kinda redundant because the .html file extension already does that. The attributes on it are important though.

Set the language of the content:

lang="en"

The direction of the text:

// English is read from left to right
dir="ltr"

// Arabic is read from right to left
dir="rtl"

The xmlns and office namespace for Outlook support (see section conditional comments):

xmlns:o="urn:schemas-microsoft-com:office:office"

Meta

Metadata tags are nested inside the <head> section, and are used to provide some additional important information about the document. Clients process the meta tags and ignore those they don’t support.

Set the character encoding

<meta charset="utf-8">

// UTF-8 is standard and allows you to use special characters and emojis

Set the viewport to match the device width

<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">

Fix autoscaling on Apple devices.

<meta name="x-apple-disable-message-reformatting">
//  Without this, emails will appear zoomed out or off-centered due to auto-scaling

Title

As usual you want to include a descriptive title. If the user opens your email in the browser this will be displayed in the tab. Titles also show up in notification windows.

<title>Super Awesome Email Title</title>

Conditional XML

This XML is wrapped in comments that are only visible to MS Outlook (mso = ‘Microsoft Outlook’). It helps to render content (i.e. PNG images) properly on Windows laptops that have higher than standard resolution monitors, and makes background images in 72ppi Outlook render at the correct size.

<!--[if mso]>
<noscript>
  <xml>
    <o:OfficeDocumentSettings>
      <o:PixelsPerInch>96</o:PixelsPerInch>
    </o:OfficeDocumentSettings>
  </xml>
</noscript>
<![endif]-->

Basic Template

All of this boilerplate will make sure that your document can be read by any email client. It’ll be the same for every email, so you can copy and paste this part directly into your project.

Just don’t forget to change the title. 🙂

<!DOCTYPE html>

<html
  lang="en"
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:o="urn:schemas-microsoft-com:office:office">
  <head>

    <!-- To allow the use of special characters-->
    <meta charset="UTF-8" />

    <!-- To display properly on mobile -->
    <meta name="viewport" content="width=device-width,initial-scale=1" />

		<!-- To fix autoscaling -->
    <meta name="x-apple-disable-message-reformatting" />

    <title>My Awesome Email!</title>

    <!--[if mso]>
      <noscript>
        <xml>
          <o:OfficeDocumentSettings>
            <o:PixelsPerInch>96</o:PixelsPerInch>
          </o:OfficeDocumentSettings>
        </xml>
      </noscript>
    <![endif]-->

	<body>
<!-- Keep reading to see what goes here -->
  </body>
</html>

It’s all about Style 💃

It’s best not to leave any style decisions up to the email client because who knows what their default settings are.

Email clients receive 2 types of emails: HTML emails and plain text emails. Plain text still benefits from some formatting (padding, margin, line-height, etc.) to make the content easier to read. Mail clients provide some basic formatting by default, but that same formatting will clash with the styles we want to apply to our custom HTML email design. To prevent any issues we need to do a general CSS reset.

CSS Reset

These are some of the most popular general reset rules:

body {
  margin: 0 auto;
  padding: 0;
}

table {
  border-spacing: 0;
}

table td {
  border-collapse: collapse;
}

img {
	display: block; <!-- to prevent extra spaces after images -->
	border: none;
	height: auto; <!-- to prevent squishy images -->
}

a img {
	border: none;
}

Of course Outlook requires their very own set of reset rules, so you’ll need to throw these in too:

.ExternalClass {
  width:100%;
}

.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div{
  line-height: 100%;
}

/* Outermost container in Outlook.com */
.ReadMsgBody {
  width: 100%;
  background-color: grey; /* your custom background color */
}
table {
  mso-table-lspace: 0pt;
  mso-table-rspace: 0pt;
}

img {
  -ms-interpolation-mode: bicubic;
}

Dark Mode

To support light/ dark modes you can add a meta tag in the head and some root styles. The older “supported-color-schemes” was renamed to simply “color-schemes”, but older safari and mail apps may require the legacy naming so we include them both.

<head>
...
	<meta name="color-scheme" content="light dark" />
  <meta name="supported-color-schemes" content="light dark" />
...
</head>

<style>
	:root {
	        color-scheme: light dark;
	        supported-color-schemes: light dark;
	      }
</style>

Layout the Content

Due to the lack of standards support in email, it’s not possible to use divs, sections or articles, so it’s all tables from here on out. If you’re like me, you probably don’t use tables very much, but they’re not that difficult.

And because neither the colspan nor rowspan attributes are properly supported we have to nest tables inside one another if we want to build more complex layouts.

To make sure our content looks good everywhere we have to build the layout with HTML tables.

An HTML email table consists of three main elements:

  1. A <table> element (table)
  2. A <tr> element (table row)
  3. A <td> element (table data cell)

Wrapper Table

It’s best to create one main wrapper table that defines the width and center-alignment and then put the rest of the content inside so that the entire email is nicely centered.

The main wrapper table needs to include a few special attributes:

Role

role = “presentation”

This is for accessibility. It tells screen readers that the table is merely for presentation purposes. Screen readers will only read out the contents of the table cells, instead of also announcing the structure.

Cell Padding

cellpadding=“0”

Removes the default padding so that there aren’t any gaps around the content of cells.

Cell Spacing

cellspacing=“0”

Removes the default padding so that there aren’t any gaps around the cells themselves.

Border

border=“0”

Removes all of the borders.

While you’re working on laying out your content you may find it beneficial to display borders on your tables so that you can actually see what you’re working with. We’ll remove them at the end to make everything pretty.

Width

width=“600px”

600px is the agreed upon ideal width for an email so that it still looks good on smaller devices and tiny preview panes.

Aside from this absolute width (px), it’s a good idea to use relative width (percentages) as much as possible so that the content adapts to any screen size.

Align

align=“center”

To center the main content in the case that the screen size is larger than 600px.

Tips for Table Layouts

Whenever you want your content to begin on a new line you need to create a new row with <tr> Inside the <tr> tags you’ll add table data cells with <td>, which will line up beside each other from left to right.

If you add 5 cells to one of the lines it will split every other line up as if they have 5 cells in them as well. Instead, you need to have one cell on each row and then add a new table inside of that row to split up the content without affecting the rest of the layout.

We need to rely on nesting tables because colspan and rowspan are not widely supported across email clients.

The nested table also needs to include all of the attributes as the wrapper.

Testing

Since email-specific HTML is a little wonky 🤪, you’ll want to run your code through an HTML validator to make sure everything is functional. Pro tip: test it a few times throughout the process instead of waiting until the end. It’ll be waaay easier to debug!

It’s super important to make sure that you’ve covered all your bases by testing how your emails render on different clients. There are a few popular options like Litmus and Email on Acid, but their “only free” option is a trial, and I didn’t want to risk forgetting to cancel before the trial period ends because they’re both priced around $200 a month.

I tried to find an actually free alternative by searching “alternative to X” and was directed to a service called Send In Blue. The testing capablities were extremely basic — they didn’t actually test how the email looks on different clients, only on different screen sizes. I could accomplish that myself by resizing the browser window, so I didn’t find it very useful.

The next option I tried was Mailosaurus. I was able to login with Github which was nice & simple but when I got to the dashboard I saw that it was also only a free trial. At least i didn’t have to enter a credit card. It also wouldn’t let me use their client testing functionality without requesting it first? Which is kind of a strange onboarding experience.

Some other options I saw and didn’t love:

Mail Ninja by Mailchimp also only lets you test emails on different screen sizes, not clients.

Putsmail by Litmus allows you to send 10 test emails at a time to emails that you own

So, in the end I guess the only way to test your emails for free is to create test emails with different email service providers (gmail, outlook, icloud, etc.) and send yourself your email to make sure it works. Ideally, you’ll want to open it on multiple devices, so that you can verify that it looks good on the webmail, desktop and mobile app versions of each.

Failsafe

Lots of emails these days will have a “View on Web“ link will opens the email in the browser. This makes it easy for people to bookmark or share it with others without having to forward it to them. It’s also an important fallback in case, despite all your hard work, the HTML doesn’t render correctly.

Some other Tidbits

  • Webmail clients will sometimes strip out your <body> and <head> code so it does not interfere with their own design code, so it’s best to use inline styles on each html element in the <body>.
  • Design your CSS to “fail gracefully” so that it makes sense even if the styles fail. You can do this by laying out all of your HTML content first, and then adding styles after.
  • Keep your total file size as small as possible. <100kb is ideal, under 250kb is acceptable. Optimize your image sizes because those usually add the most bulk. Text is fairly light.
  • Images should have a resolution of 72dpi.
  • Do not use one large image for your entire email — this is an old practice that triggers modern spam filters, and will not be displayed if the recipient has images turned off (common). Images are used to support text, not the other way around.
  • The best way to embed images is to host them on an external web server and then pull them in using absolute URLs. Don’t forget to add alt text in case the images don’t load in. Declare a width and height of “100” on each image. Make sure your image files have been optimized. Don’t use images for the entire background, and opt for background colours instead. Don’t use images for important content like headlines, links or CTAs.
  • Never use white text. If the background doesn’t load then it will be invisible. White text is read as “invisible” and can raise your spam score. If you want a white-ish colour then choose something like a light grey.

Not so bad after all?

Email development is certainly a laborious process in many ways. At first I was a little taken aback by how archaic the whole process is, but somehow it’s actually kind of grown on me over the last few days. Sure, table layouts are not as convenient as grid or flexbox layouts, but it’s just tedious, not hard.

See the Pen Retro HTML Email by Alekzandriia (@alekzandriia) on CodePen.

Click the codepen logo in the top right to see the result in a larger window. 
I went for a "retro" aesthetic to give it that ugly-on-purpose anti-design vibe, but I'm not sure that it's fooling anyone. 😂 Oh well, if you're too scared to be bad at something then you'll never get good. 🙂

After working on this project I have a huge appreciation for the web standards. Getting everybody on the same page has allowed modern web development to flourish.

I’m happy that I decided to try something new & I hope that you considering it too. If my chaotic study notes helped you at all please let me know. If you’re an email dev and you see that I’ve completely bastardized this then definitely tell me asap so I can correct it.

I only scratched the surface of this topic so far, maybe next time I’ll dive into how to make a template responsive, or how to use one of the newer template frameworks like MJML. 🤔

Ciao for now! xox