HTML Emails - the COBOL of the 1990s
Tags: htmlemails, tablesforlayout, thehorrorthehorror, outlook4eva
Published: 2020-01-02 13:21:36

---
title: HTML Emails - the COBOL of the 1990s
published: true
description: Should we code like it's 1999 or use a framework? Spoiler: I am old.
cover_image: https://thepracticaldev.s3.amazonaws.com/i/21ho6ahdymaruu0qvu4h.png
canonical_url: https://dev.to/rossangus/html-emails-the-cobol-of-the-1990s
tags: HTML emails, Tables for layout, The horror the horror, Outlook4eva
---

<abbr title="Common Business-Oriented Language">COBOL</abbr> is a computer language developed in the late 1950s. They wrote a bunch of banking software on it then somehow ... it never got replaced (<abbr title="Information Technology">IT</abbr> projects are _hard_). So today, if you know <abbr>COBOL</abbr>, two things are certain:

1. You are old. _So_ old.
1. You can basically charge whatever you like as a freelancer.

  In the late 1990s, I learned <abbr title="Hypertext Markup Language">HTML</abbr>. It was a godless time. <abbr title="Cascading Style Sheets">CSS</abbr> wasn't invented. Layout was done with tables. 30<abbr title="kilobytes">kB</abbr> was considered hefty.

I've got all kinds of obsolete tricks locked away in my noggin. Using them, I could build a site which would work in IE4 or Netscape Navigator 4.7. So the question is this: are these skills at all useful?

**Yes.**

Can I command a high price for them?

**No.**

Am I going to tell you about them now, in case you might find them useful?

**Yes (sorry).**

## Wait, why are we doing this?

<abbr>HTML</abbr> emails. For a couple of reasons, <abbr>HTML</abbr> emails require you to party like it's 1999.

### Reason one: bloody Microsoft

Many modern versions of _Outlook_ use the <abbr>HTML</abbr> rendering engine of <abbr title="Internet Explorer">IE</abbr>7, <abbr>IE</abbr>8 or even _Microsoft Word_(!). But while <abbr>IE</abbr>7 and <abbr>IE</abbr>8 _did_ support <abbr>CSS</abbr>, let's just pretend they didn't. For the sake of argument.

What you might think now is <q>but Microsoft replaced _Outlook Express_ years ago with [Mail](https://www.microsoft.com/en-gb/p/mail-and-calendar/9wzdncrfhvqm)</q>. This is true. Unfortunately, the <abbr>HTML</abbr> rendering engine seems to be exactly the same.

### Reason two: health and safety

I dunno if you've heard this, but The Internet is a _dreadful_ place. One can't help a simple man liberate his inheritance from a bank account without somehow handing over the keys to one's own savings. Email is the platform where many of these scammers practice their art. As a result, most reputable email services will put all your mail through some form of pre-processing. All JavaScript will be removed. Images may be blocked. External <abbr>CSS</abbr> and typefaces will be ignored. And in some cases, even <abbr>CSS</abbr> added within the `head` of the document (and even as `style` attributes) will be stripped out.

This limits the techniques we can use to a tiny subset of the kinds of things we used to do in the 1990s.

### But surely, it can't be _that_ bad, can it?

What you might be thinking right now is <q>hasn't this berk heard of [progressive enhancement](https://en.wikipedia.org/wiki/Progressive_enhancement)?</q> to which I'd be forced to answer <q>yes, but I had to Google it first, for an exact definition</q>. Unfortunately, _Outlook_ still has a huge chunk of the email market. Unless you're 100% sure all your users have iPhones, it's probably worth your while using Ye Olde <abbr>HTML</abbr>. This means it'll work in _Outlook_ but also on more modern web browsers. Because if support for obsolete <abbr>HTML</abbr> was dropped, how could modern eyes be expected to enjoy delights such as [the Space Jam website](https://www.spacejam.com/archive/spacejam/movie/jam.htm) or keep up to date on [how Bob Dole is doing in his election bid](http://www.dolekemp96.org/main.htm)?

Unsurprisingly, the relative simplicity of pre-<abbr>CSS</abbr> <abbr>HTML</abbr> also lends itself to a pretty compressed file, unless you use [one of those frameworks, which lets you write modern markup](https://mjml.io/), then converts it into hundreds of nested tables, with inline <abbr>CSS</abbr> up the wazoo.

But we are web devs. Let's create this from scratch.

## Page structure

All <abbr>HTML</abbr> email layout should be achieved with tables. Some of you might not even be old enough to realise what a controversial statement that is. If you _are_ this young, imagine I said <q>why should we use _React_? _jQuery_ does the same job</q>. Tables can offer many of the advantages of <abbr>CSS</abbr> Grid, but with fewer features plus a free look of horror from your web developer colleagues. However, tables are an ancient technology which works.

Congratulations. We have reached the lowest-common denominator.

Tables don't just allow us to produce multiple columns. They're also the only reliably method to change background colours (other than the `body` tag).

Let's start with a simple table:

```html
<table width="500" bgcolor="OldLace" align="center">
  <tr>
    <td>I am content</td>
  </td>
</table>
```

This is your <q>hello world</q> of HTML emails. That `align` attribute aligns the whole table to the centre. If you added the same attribute to a table cell, it would align the contents _within_ that table cell to the centre.

Here's some table tricks, to get you started:

{% codepen https://codepen.io/ross-angus/pen/gJJYjz %}

But tables are more useful than for mere grids. They're the only way (aside from the body tag itself) to add background colours to text. Here's some tricks you can use:

{% codepen https://codepen.io/ross-angus/pen/qGQWWK %}

Borders around tables require a Codepen all of their own:

{% codepen https://codepen.io/ross-angus/pen/xNeWJz %}

Now some good news:

## I hereby grant you permission to ignore pixel-pushing

It _is_ possible to pixel-push in HTML emails but doing so is kind of a waste of time. You can add an arbitrary space between two elements using a spacer gif - that is a single, pixel wide, clear gif. This can be stretched using the `width` and `height` attributes, until it takes up the required space.

The problem is that because many email clients block images by default, if you do this, you'll end up with white boxes scattered throughout your email, harshing your mellow, as we used to say in the 1990s. Also, there’s a chance that using any single-pixel gif will get your email flagged as Spam as it might be mistaken for a [web beacon](https://en.wikipedia.org/wiki/Web_beacon).

You _could_ use the `spacer` HTML element, but this was only ever supported by Netscape Navigator 4.7, so it won't do much good here. Even [Thunderbird](https://www.thunderbird.net/) doesn't use _that_ antique browser engine.

Probably the best method to introduce vertical space into your <abbr>HTML</abbr> emails is the simple `br` tag. This means you need to think in terms of units of line height, rather than pixels.

There is one other method, but it only works on images. The `hspace` and `vspace` attributes allow you to add either horizontal or vertical space, in pixels, onto an individual image. Note that this will be added on both sides of the image, so will often push the image out of alignment.

## Forget about block level elements

Because we'll be using `font` tags willy-nilly, there's a couple of things you need to know about them:

1. They're inline
1. If you wrap them around a block-level tag, they usually† won't have any effect

† Exceptions: you can influence `border-color` in tables by putting a `font` tag around the whole table and setting a colour on it. But it'll impact the text colour inside the table cells too.

This means that this pattern won't change the typeface using within the paragraph:

`font > p`

... but this one will:

`p > font`

However, we won't need no paragraph tags where _we're_ going. Here's the craptacular pattern we'll be using instead:

```html
<font face="sans-serif" size="2">
<b>This is a <q>heading</q></b>
<br/>
This is a <q>paragraph</q>.
<br/><br/>
This is a new <q>paragraph</q>.</font>
```

I'll give you a moment, so your nausea can subside. Yes, I _am_ using the `q` tag as <q>scare quotes</q>.

The reason for this horrible pattern is that we want to declare that big, long `font` tag as few times as possible. But every time we have text inside a new block level element (such as a table cell), it will need to be added again. This is what we're trying to avoid:

```html
<h2><font face="sans-serif">This is a heading
</font></h2>
<p><font face="sans-serif">This is a paragraph.
</font></p>
<p><font face="sans-serif">This is a new paragraph.
</font></p>
```

The _other_ reason we tended to avoid heading tags in the 1990s was that they came with a big old margin which was impossible to change, until <abbr>CSS</abbr> arrived, like a golden saviour on a mighty steed.

Note that because we can only rely on typefaces which are installed on the user's local machine, we need to declare a [font stack](https://www.cssfontstack.com/) instead of using your modern `font-face` nonsense. This means that a typical `font` tag will look like this:

```html
<font face="Arial, Helvetica Neue, Helvetica, sans-serif" size="2"></font>
```

Imagine hundreds of _them_ cluttering up your markup.

If you're _very_ old, you might remember [the `basefont` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/basefont). This pre-<abbr>CSS</abbr> tag's dream was that we'd just define the font stack we wanted once per page. I've tested it in thirty-three different email clients. It isn't parsed by _any_ of them.

## Responsive tricks

When you think of <abbr>HTML</abbr> emails, the image I need you to hold in your mind is a sports car pulling a wagon full of hay. Or a horse pulling a sports car. Doesn't matter. The important thing to remember is that *some* <abbr>HTML</abbr> email clients are *very* capable, and will parse all of your <abbr>CSS</abbr>. These tend to be on mobile devices, so we can use nice, modern tricks for them, while remembering the lumbering horse / cart which is holding us back.

### Avoiding horizontal scroll

Let's say we use the following table structure:

```html
<table width="500" align="center">
  <tr>
    <td>email contents go here</td>
  </tr>
</table>
```

On mobile devices, we could ensure that the table isn't too wide by adding this rule:

```css
@media (max-width: 500px) {
	table {width: 100%;}
}
```

Any <q>styles</q> added using <abbr>HTML</abbr> attributes (for example `width="500"`) will be overruled by CSS.

Unfortunately, if you have to consider _Outlook_ running on high <abbr title="Dots Per Inch">DPI</abbr> displays, one of the work-arounds is this:

```html
<table width="500" align="center"
  style="width:500px">
  <tr>
    <td>email contents go here</td>
  </tr>
</table>
```

This means the <abbr>CSS</abbr> needs to be a bit _extra_:

```css
@media (max-width: 500px) {
	table {width: 100% !important;}
}
```

Note this could have knock-on effects, if you use a table which needs to have a <q>natural</q> width within the mobile breakpoint.


### Swapping images

One way to swap out one version of an image for a different one in mobile is to add both images in the markup. This means that the mobile image needs to be hidden in _Outlook_. This is what the markup looks like:

```html
<table width="500" align="center">
  <tr>
    <td>

      <img src="http://url.com/mobile.jpg"
      width="1" height="1" alt=""
      class="hidden-lg">

      <img src="http://url.com/desktop.jpg"
      width="300" height="200" alt=""
      class="hidden-sm">

    </td>
     <td>Email content goes here</td>
   </tr>
</table>
```

Note that the `width` and `height` attributes of the mobile image are set to <var>1</var>. If you set them to zero, the browser tends to ignore them and display the image at its native size. This is the CSS which will swap the images:

```css
@media (max-width: 500px) {
  .visible-lg {
    display: none;
  }
  .visible-sm {
    height: auto;
    max-width: 100%;
    width: auto;
  }
}
```

This technique could also be used to switch the markup order of the email in the mobile viewport (albeit in a way which requires duplicated <abbr>HTML</abbr>).

### Linearising tables

Let's say you had the following markup, but you wanted it to be linear, on mobile:

```html
<table width="500" align="center"
  class="sm-totem">
	<tr>
		<th>Column one</th>
		<td>Column two</td>
		<td>Column three</td>
	</tr>
</table>
```

You could achieve this with the following <abbr>CSS</abbr>:

```css
@media (max-width: 500px) {
  .sm-totem, .sm-totem tr,
  .sm-totem th, .sm-totem td {
    display: block;
  }
}
```

This will stack the cells of the table on top of each other in a totem pole fashion.

Both these techniques can be seen below:

{% codepen https://codepen.io/ross-angus/pen/dEEbwV %}

## Tips and tricks

There's lots of patterns which can save some bytes, when writing antique <abbr>HTML</abbr>. For example:

### Combining attributes on a parent element

```html
<!-- Don't do this -->

<table>
  <tr>
    <td valign="top">Content which will wrap at
    some point</td>
    <td valign="top">Content</td>
    <td valign="top">Content</td>
  </tr>
</table>

<!-- Do this -->

<table>
  <tr valign="top">
    <td>Content which will wrap at some point</td>
    <td>Content</td>
    <td>Content</td>
  </tr>
</table>
```

### Removing placebo tables

```html
<!-- This table does nothing and can be removed -->
<table cellspacing="0" cellpadding="0" border="0">
  <tr>
    <td>I am content</td>
  </tr>
</table>
```

### Declaring `font` tags as few times as possible

```html
<!-- This: -->

<font face="sans-serif" size="3"><strong>Heading
</strong></font>
<br>
<font face="sans-serif" size="2">Content</font>

<!-- ... could be expressed leaner like this: -->

<font face="sans-serif">
  <font size="3"><b>Heading</b></font>
  <br>
  <font size="2">Content</font>
</font>
<!-- see also "i", rather than "em" -->
```

### Using structural tags to get stuff for free

```html
<!-- This: -->

<table cellpadding="20">
  <tr>
    <td align="center" bgcolor="AntiqueWhite">
      <b>Heading</b>
    </td>
    <td align="left" bgcolor="SeaShell">
      Content
    </td>
  </tr>
</table>

<!-- ... could also be achieved like this: -->

<table cellpadding="20">
  <tr>
    <th bgcolor="AntiqueWhite">Heading</th>
    <td bgcolor="SeaShell">Content</td>
  </tr>
</table>
```

Remember that by default, `th` elements are aligned to the centre and bold. `td` elements are aligned to the left.

### Some obsolete tags are useful

```html
<!-- This: -->

<table width="100%">
  <tr>
    <td align="center">Content</td>
  </tr>
</table>

<!-- ... could be expressed like this: -->

<center>Content</center>

<!-- or: -->

<p align="center">Content</p>
```

The above example is only useful if no background colour is required. Or if one line of text needs to be centred inside a table cell where all the rest of the text is not.

```html
<!-- This: -->

<font size="-1">Legal disclaimer</font>
<font size="+1">Shouty text</font>

<!-- ... could be done like this: -->

<small>Legal disclaimer</small>
<big>Shouty text</big>
```

### Images

A few things about images:

* They don't need a `font` tag around them (unless you're trying to influence their `border` colour)
* Declare a `width` and `height` - many email clients will not load the image by default and you don't want your layout to collapse because of this
* Fill in the `alt` attribute - some email clients will display this text in the image's stead

```html
<!-- Don't do this: -->

<table cellpadding="20" bgcolor="white">
  <tr>
    <td>
      <font face="sans-serif">
        <img src="https://google.com/logo.png"
        width="150" height="80" alt="Google"/>
      </font>
    </td>
  </tr>
</table>

<!-- This is all that is required: -->

<table cellpadding="20" bgcolor="white">
  <tr>
    <td>
      <img src="https://google.com/logo.png"
      width="150" height="80" alt="Google"/>
    </td>
  </tr>
</table>
```