Essential Tips and Tricks for Coding HTML Emails

    Rémi Parmentier
    Share

    One of the most difficult aspects of HTML email coding is that every email client has its own quirks and features. Email clients usually end up with these quirks through the best of intentions. For example, they might turn a plain text website address into a clickable link. There’s also the issue of security. Email clients need to make sure that our email’s HTML and CSS won’t interfere with their own interface’s HTML and CSS. A malicious email could use certain CSS properties (like absolute positioning) to lure people into clicking on overlaid hidden links. So email clients should parse, filter and manipulate HTML email code. But this means that we, as email developers, must be aware of this and make our code as friendly as possible for them.

    From features to bugs, here are some of the most popular tips and tricks we need to know. This article is excerpted from Crafting HTML Email, available on SitePoint Premium.

    Supporting the Outlooks

    According to email analytics tool Litmus, Outlook (on both Windows and macOS) accounted for 4.44% of email client market share in January 2022. That may not seem much, and remember to take email analytics with a pinch of salt, but chances are you’ll meet Outlook on Windows at some point in your email developer journey.

    Here’s what you need to know to make your HTML emails work painlessly in the Outlooks on Windows.

    How the Outlook Rendering Engine Works

    Since 2007, the Outlooks on Windows have used Word as the rendering engine for HTML and CSS. Microsoft justified the use of Word in 2009:

    We’ve made the decision to continue to use Word for creating e-mail messages because we believe it’s the best e-mail authoring experience around, with rich tools that our Word customers have enjoyed for over 25 years.

    Not only is Word not very good for rendering HTML and CSS, but the documentation on the matter is abysmal. The only official existing documentation about Word’s rendering is a 2006 post from Microsoft explaining HTML and CSS rendering capabilities in Outlook 2007.

    It includes information on the following:

    • CORE: color, background-color, text properties (font, font-family, font-style, font-size, font-weight, text-decoration, text-align, vertical-align, letter-spacing, line-height, white-space), border shorthand properties (border, border-color, border-style, border-width, border-collapse) and a few others.
    • COREEXTENDED: text-indent and margin properties (margin, margin-left, margin-right, margin-top, margin-bottom).
    • FULL: width, height, padding (as well as padding-left, padding-right, padding-top, padding-bottom) and border longhand properties (border-left, border-left-color, border-left-width, border-left-style, and so on).

    And each of these categories will only apply to certain HTML elements:

    • <body> and <span> only support CORE properties.
    • <div> and <p> support both CORE and COREEXTENDED properties.
    • All the other elements supported by Outlook (like <table>, <td>, <h1>, <ul>, <li>, and so on) support CORE, COREEXTENDED and FULL properties.

    This means we must think about which element to use to apply certain styles. So if we have to define a width or a height on a generic container element, we’ll use a <table>. If we need padding, we’ll also use a <table> and a <td>.

    To this day, the Outlooks on Windows are the sole reason we still use tables in HTML emails. Luckily, there are ways for us to only make those tables visible for Outlook, hiding them from more capable email clients and allowing us to use more semantic code.

    Conditional Comments

    Microsoft introduced conditional comments back in 1999 in Internet Explorer 5. They were quite popular on the Web during the IE6–9 era, but they were removed for Internet Explorer 10 and 11. Here’s how it works: inside a regular HTML comment (<!-- -->), you can code a condition that will make the rest of the content visible if that condition is fulfilled. Here’s an example:

    <!--[if IE]>
    <p>This is only visible in Internet Explorer.</p>
    <![endif]-->
    

    It turns out that conditional comments are also supported in the versions of Outlook on Windows using Word’s rendering engine. Instead of using IE as a condition, we’re going to use the mso keyword:

    <!--[if mso]>
    <p>This is only visible in Outlook 2007 and above on Windows.</p>
    <![endif]-->
    

    Conditions can also be tied to a version number. For example, mso 12 targets Outlook 2007. Unfortunately, Microsoft has stopped incrementing this version number in the latest Outlook releases. So mso 16 targets both Outlook 2016 and the most recent Outlook 2019.

    We can also use operators like gte (greater than or equal) or lte (less than or equal) to create more complex conditions:

    <!--[if gte mso 12]>
    <p>This is visible in Outlook 2007 and above.</p>
    <![endif]-->
    

    Another useful operator is the NOT operator (!), which lets us insert code for every email client except Outlook on Windows:

    <!--[if !mso]><!-->
    <p>This is visible in every email client except the Outlooks on Windows.</p>
    <!--<![endif]-->
    

    mso- Properties

    Outlook on Windows has hundreds of proprietary CSS properties, mostly recognizable thanks to the mso- prefix. A complete list is available in a .chm file, but email developer Stig Morten Myre has a handy archive of it readable online.

    For a lot of standard CSS properties, Microsoft has an equivalent proprietary version prefixed by mso- and suffixed by -alt. For example, we can define a padding value for just Outlook on Windows with the mso-padding-alt property. One way I often use this is when I code buttons. Ideally, the entire visible area of a button should be clickable, so I normally add padding to <a> elements. But Outlook on Windows doesn’t support this. So instead, I wrap each <a> element with a <table> and apply a padding only for Outlook on Windows with the mso-padding-alt property:

    <table border="0" cellpadding="0" cellspacing="0" role="presentation" align="center" style="margin:0 auto; max-width:100%; background:#2ea44f; border-radius:5px; border-collapse:separate;" class="email-btn">
        <tr>
            <td style="mso-padding-alt:14px 16px; text-align:center;">
                <a style="padding:14px 16px; display:block; min-width:128px; color:#fff; font:bold 16px/20px Helvetica Neue, Roboto, sans-serif; text-decoration:none; text-align:center;" href="https://www.example.com" target="_blank" >Call to Action</a>
            </td>
        </tr>
    </table>
    

    Outlook also has other unprefixed proprietary properties that can mimic their more modern CSS equivalents. For example, text-underline-color in Outlook is the same as text-decoration-color in CSS. So if you want to apply a specific color to a text underline, you can use both properties:

    text-underline-color: red; /* Outlook version */
    text-decoration-color: red; /* Standard version for clients that supports it */
    

    Stig Morten Myre has a great article explaining how to fix bugs with Outlook specific CSS, including tips on how to use mso-text-raise or mso-line-height-rule: exactly.

    VML

    VML is SVG’s ancestor, crafted by Microsoft in the late nineties. Just like SVG, you can draw content with markup code. For example, if we want to draw a red rectangle, we can use the <v:rect> element and the following code:

    <v:rect xmlns:v="urn:schemas-microsoft-com:vml" 
            fillcolor="red" 
            stroked="false" 
            style="width:200px; height:100px;">
    </v:rect>
    

    A prerequisite for getting VML to work in Outlook on Windows is to add its namespace declaration (xmlns:v="urn:schemas-microsoft-com:vml"). It can either be repeated inline for each VML element we use, or it can be added on the <html> element only once. And because VML will only work in Outlook on Windows, we’ll make sure to wrap it in a conditional comment. Here’s a full working example for our previous red rectangle:

    <!DOCTYPE html>
    <html lang="en" xmlns:v="urn:schemas-microsoft-com:vml">
    <head>
        <title>VML rectangle</title>
    </head>
    <body>
        <!--[if mso]>
        <v:rect fillcolor="red" stroked="false" style="width:200px; height:100px;"></v:rect>
        <![endif]-->
    </body>
    </html>
    

    Of course, we can do more exciting things than red rectangles. One way we can use VML is to fake properties unsupported by Outlook on Windows — such as background images. If we want to show a background image on our <body> element, we can use the <v:background> element. However, this might be a source of accessibility issues, as it turns the content within it into part of the VML image, which might get lost for assistive technologies like screen readers.

    Campaign Monitor’s Backgrounds.cm and Buttons.cm make extensive use of VML to fake background images or rounded corners. And email developer Mark Robbins provides great examples of how VML can be used to create CSS triangles or fake absolute positioning.

    Microsoft’s “How to Use VML on Webpages” and “VML Object Model Reference” are great places to start learning about VML.

    Rendering at 120dpi

    On certain Windows configurations, Outlook on Windows applies DPI scaling on emails. Email developer Courtney Fantinato has a detailed guide to correct Outlook DPI scaling issues. Here are the three rules you need to follow:

    1. Add the Microsoft Office namespace on the <html> element:
      <html xmlns:o="urn:schemas-microsoft-com:office:office">
      
    2. Add the following OfficeDocumentSettings declaration inside the <head> element:
      <!--[if mso]>
      <xml>
        <o:OfficeDocumentSettings>
          <o:PixelsPerInch>96</o:PixelsPerInch>
        </o:OfficeDocumentSettings>
      </xml>
      <![endif]-->
      
    3. Always use dimensions defined in CSS instead of HTML attributes:
      <!-- Bad example -->
      <table align="center" role="presentation" width="600"></table>
      
      <!-- Good example -->
      <table align="center" role="presentation" style="width:600px;"></table>
      

    The only exception for this is with images. In Outlook on Windows, a width set in a style attribute is ignored on images.

    Making Your Emails Work without <style>

    When it comes to applying styles to any HTML content (be it for a web page or an HTML email), there are three ways to do it, using:

    • a <link> element and an external stylesheet
    • a <style> element
    • an inline style attribute

    Email clients are very opinionated when it comes to this, and support for each of these techniques can vary wildly. This is usually due to security issues. Email clients need to be very cautious about the styles they allow, because a malicious email could use styles to deceive a user. For example, using fixed or absolute positioning could let a malicious email developer stack fake elements over an email client’s own interface.

    Email clients employ a variety of methods for getting around this, such as only allowing a subset of properties or values from a safe list of their own. They also apply prefixing to CSS selectors in an HTML email to prevent email styles from impacting the client’s interface. For example, a selector like .button {} would become .rps_1234 .x_button {} in Outlook.com.

    The <link> element is very well supported in desktop native applications like Apple Mail (on macOS or iOS) or Outlook (on Windows or macOS). However, it’s almost universally ignored by webmail clients (such as Gmail, Outlook.com, Yahoo Mail, and so on) as well as a lot of mobile apps (like Gmail, Outlook or Yahoo Mail, on either iOS or Android). So it’s not a recommended way to style an HTML email. But it can have interesting use cases, like when Litmus created a live dynamic Twitter feed in 2015.

    The <style> element has way better support. But it also has a few quirks. Gmail clients, in particular, only support style tags defined in the <head> (not in the <body>). They’re also very picky about any syntax error, and Gmail will remove an entire <style> that contains something it doesn’t like (like an @ in an @ declaration, for example). It’s a common practice to use multiple <style> elements in HTML emails. After removing the unsupported ones, Gmail will combine them into a single one that’s limited to 16KB.

    But <style> elements are not always supported. For example, if you receive an email in the Gmail app (on iOS or Android) with a non-Gmail address (like an Outlook.com or Yahoo address), you won’t get <style> support.

    <style> elements can also be removed contextually. For example, when you forward an email in the desktop webmail of Gmail, all <style> tags are removed. Gmail also removes <style> tags when an email is viewed in its unclipped version.

    So as a general rule, it’s safer and more robust to use inline styles via the HTML style attribute. We can also use <style> tags, but only as a progressive enhancement, especially for things like @media queries or :hover pseudo-classes that can’t be inlined.

    “Making an email work” without the <style> element can mean a lot of different things. But it’s best to think first and foremost about the following:

    • Layout. An email without <style> should adjust to any width without horizontal scroll. I usually consider going as low as 280px wide, which reflects the width of an email viewed on Gmail on an iPhone SE.
    • Branding. An email without <style> should reflect the branding of the sender.

    Email clients automatically add links to certain keywords. This can happen to the following kinds of text:

    • URLs (sitepoint.com, https://www.sitepoint.com/blog/)
    • email addresses (support@sitepoint.com)
    • phone numbers
    • mailing addresses
    • dates
    • flight numbers

    The image below shows how Apple Mail provides detailed information on air flights when a current flight number is clicked.

    Examples of automatically added links in Apple Mail

    The problem is that, if we don’t plan for them, these links will come up with their default styles (usually blue and underlined) — and this can create unexpected and undesirable effects. For example, an automatic blue link on an already blue background will be unreadable. Unfortunately, anticipating these automatic links isn’t foolproof. It’s not uncommon that a custom offer or tracking code is turned into a date or phone number link.

    Here are three possible ways to avoid automatic links:

    • Add a specific meta declaration for Apple Mail. With this tag in the <head> of our email, Apple Mail won’t add automatic links:
      <meta name="format-detection" content="telephone=no, date=no, address=no, email=no, url=no">
      
    • Use a zero-width non joiner character. A zero-width non joiner is an invisible character represented by the entity &zwnj; (or &#847;) in HTML. We’ll use it here to break email clients’ content detection algorithm by placing it in the middle of text where a link might be added:
      Visit Sitepoint&zwnj;.com for more details!
      
    • Add a link ourselves. Email clients are clever enough to not try to add a link to text that’s already linked. So if we add a link ourselves around text that we know might get automatically linked, we can apply our own styles. A link would still be there, but at least not so prominently visible:
      Visit <a href="https://sitepoint.com" style="color:#000; text-decoration:none;">sitepoint.com</a> for more details!
      

    Using Real URLs

    Microsoft’s Outlook.com webmail has a bug when using non-URL text as the href value of an <a> element. For example, consider the following code:

    <a href="" style="color:blue;">Get the app on iOS</a><br>
    <a href="TBD" style="color:green;">Get the app on Android</a>
    

    This is transformed by Outlook.com into the following:

    Get the app on iOS<br>
    [TBD] Get the app on Android
    

    The entire <a> element, including its styles, is removed. And the value of the href attribute (if it’s not empty) is added between brackets before the link text.

    I’ve been caught by this bug more than once, usually because I didn’t have the links to put there at the time I was coding. My go-to solution now is to always use the client’s domain or https://example.com as a temporary link. Example.com is another handy domain that’s reserved by IANA “for use in illustrative examples”.

    Adding an Empty <head>

    Yahoo Mail on Android removes the <head> element of any email. This is very inconvenient, since this means that <style> tags, along with media queries, can’t work there. But it was discovered that the Yahoo Mail app will only do this for the first <head> of an email.

    So this means that if we include a dummy empty <head> first in our code, and then keep our regular <head> element, Yahoo Mail on Android will correctly keep it and interpret it:

    <!DOCTYPE html>
    <html lang="en">
    <head></head>
    <head>
        <title>My Email</title>
        <style>
            @media (max-width: 600px) {}
        </style>
    </head>
    

    The image below shows an example email (courtesy of Really Good Emails) in the Yahoo Mail app on Android. Without the double <head>, the email is automatically scaled by the client. With the fix, the email renders media queries just as expected.

    Screenshots in Yahoo Mail Android showing the rendering with and without the double head hack

    Keeping Email Sizes below 102KB

    Gmail’s desktop webmail has a notorious threshold of 102KB, after which it will truncate an HTML email and show a “[Message clipped]” alert, along with a “View entire message” link. While it’s unknown why this limitation exists and why it’s at such an odd number precisely, it’s been measured consistently across the years.

    Screenshot of a clipped email in Gmail

    This 102KB limits only accounts for the size of the HTML of our email message. It doesn’t include other parts of an email (like the plain text version, or all of the MIME header fields). It also doesn’t include the weight of any distant asset like images or fonts. So if our HTML weighs 40KB with 500KB of images, we’re fine.

    We want to avoid this threshold because:

    • Gmail will cut our email at 102KB to insert its “[Message clipped]” alert, even if this is right in the middle of a <table>. This is very likely to break our email in unexpected ways.
    • Behind the “View entire message” link, Gmail will provide inferior support for HTML and CSS. For example, any <style> tag (and thus media queries) will be removed in this view.

    A basic way to measure this is to look at the weight of our HTML file in our operating system. Online email tools like Alter.email or Parcel also show an estimate of our code weight.

    Keep in mind that some email service providers may also process parts of our HTML in such a way that its weight will increase. For example, CSS inlining or link tracking can be big offenders in making our code overweight.

    Optimizing our HTML email code can be done in several ways. Here’s what I usually consider the most important steps:

    • Minify your code. But don’t use a minifier built for the Web! HTML Crush is a good one built for emails (avoiding making lines of code longer than 500 characters, for example). Just by removing indentations, you can diminish your HTML weight by a good third.
    • Remove unused code. If your email is built from a generic template that includes lots of styles for different components, you might end up with styles you don’t actually use. Online tool Email Comb cleans up unused code nicely.
    • Watch out for CSS inlining. If you have a CSS rule targeting the universal selector (for example, * { color:#000; }), this will be applied to every single HTML element in your code (including <tr>, <br>, and plenty of other useless places). Make sure your CSS inliner works as you expect and inspect your code after inlining styles.
    • Use fewer tables. Tables are necessary for Outlook on Windows, but they can be heavy. If we’re not using padding, border, or multiple columns, it might be better and lighter to simply have more semantic bits of code stack on top of each other.

    Gmail can also display the “[Message clipped]” alert without really clipping your message. This can be caused by the presence of special characters like © anywhere in our message.

    Removing CSS Comments

    Yahoo and AOL clients have a specific bug with CSS comments. For example, consider the following code:

    <style>
        /* Big title */
        .title {
            font-size: 32px;
        }
    </style>
    

    This is transformed by Yahoo and AOL into the following:

    <style>
        #yiv1234567890
        #yiv1234567890 .yiv1234567890title {
            font-size: 32px;
        }
    </style>
    

    The email client renames every class by adding a custom prefix (yiv1234567890) and adds a prefix to every selector (#yiv1234567890). This is a very common practice across email clients — especially webmail versions — and is needed to ensure that our email styles can’t affect the webmail client’s own styles, and vice versa.

    The bug here is that Yahoo also tries to add its prefix to the CSS comment. And because it only adds it alone on a single line of code, this means it applies to the CSS selector on the next line. Consider the following selector:

    #yiv1234567890 .yiv1234567890title { }
    

    This now gets interpreted as follows:

    #yiv1234567890 #yiv1234567890 .yiv1234567890title { }
    

    With twice the id prefix, it no longer matches anything on the page, and thus this makes the CSS rule void.

    This bug doesn’t apply if we’ve got CSS comments inside a CSS rule (between the curly braces). But as a general cautionary rule, it’s best to remove all CSS comments before sending an email.

    Using an HTML5 Doctype

    Email clients never output your HTML email code just as is. They apply various transformations, such as filtering unwanted tags (like <script>), attributes and styles. And webmail clients in particular don’t keep your entire HTML.

    A webmail email is displayed in a web page that already has its own doctype, <head> and <body>, along with other meta elements. So a webmail client like Gmail looks for <style> tags in your head, compiles them into a single one, and keeps the content of your <body> element.

    This means that, in a lot of cases, you’ll end up with the webmail’s doctype, not yours. And nowadays, most webmail clients use an HTML5 doctype:

    <!DOCTYPE html>
    

    One side effect of the HTML5 doctype is that <img> elements have a line spacing below them. This becomes clearly apparent when you slice images.

    The following image demonstrates what happens when you forget to set display:block on your images in an HTML email (courtesy of @HTeuMeuleu on Twitter).

    Screenshot of an email in Gmail with line spacing below images

    There are various solutions for getting around this. Here are three, by order of personal preference:

    • Add vertical-align:middle in an inline style on the <img> element. (This might impact surrounding text if you need to align the text and image differently.)
    • Add display:block in an inline style on the <img> element. (This changes the flow of the content and might impact sibling elements.)
    • Add font-size:0 to the parent element of the <img>. (This might impact alternative text rendering.)

    Here’s an example of the first solution applied to an image with an inline style attribute:

    <img src="logo.png" 
         alt="" 
         style="vertical-align:middle;" />
    

    Conclusion

    Dealing with email client quirks is part of the job of an email developer. It’s a good idea to follow email developer communities to follow the latest updates and practices. I recommend the #emailgeeks hashtag on Twitter and the #emailgeeks Slack channel.

    It can be tough to keep up to date with the new quirks and also move beyond the old ones. In 2015, I launched a GitHub repository to track email bugs, a collection of issues with active discussions and potential solutions for all the different email quirks and bugs. Over the years, it has gathered over a hundred issues, a quarter of which have since been fixed. This gives me good faith that by reporting what we see, email clients can improve and fix their own code. While it’s a slow process, I do feel like HTML emails are moving towards a better future, with more interoperability and standards support.

    And this is great news, because this can open the way for more fun and exciting features — such as interactivity! In the next part of this book, we’ll have a look at how we can make our emails more interactive with just CSS and HTML.