Why HTML email code still looks like 1999
Show a web developer the source of a well-built email and they’ll ask what went wrong. Nested tables. Styles repeated on every element. Comments that only Outlook can read.
Nothing went wrong. An inbox isn’t a browser, and that changes everything.
You don’t get one browser. You get dozens of email clients.
A website runs in a handful of modern browsers that mostly agree. An email runs in whatever your reader happens to use: Gmail on an Android phone, Apple Mail on an iPhone, Outlook on an office PC. Each one has its own rules about which HTML and CSS it keeps and which it throws away.
The Outlook problem
Classic Outlook on Windows renders email with Microsoft Word’s engine, not a browser engine. Flexbox and grid don’t work there, and even simple things like padding and widths behave differently. The new Outlook has moved on, but classic Outlook is still on plenty of office desktops, so a professional email has to work in both.
That’s why the columns in a modern email often carry a hidden table that only Outlook sees:
<!--[if mso]>
<table role="presentation" width="600"><tr><td width="300">
<![endif]-->
<div style="display:inline-block; max-width:300px; width:100%;">
Left column
</div>
<!--[if mso]></td></tr></table><![endif]-->
Phones get a column that stacks. Outlook gets the fixed table it understands. Same email, two sets of instructions.
Three more things that catch people out
- Gmail clips long emails. Go past about 102KB of HTML and Gmail cuts the message off behind a “View entire message” link. Bloated code can hide your call to action.
- Dark mode rewrites your colours. Some clients invert parts of an email without asking. A dark logo on a transparent background can vanish, so logos and backgrounds need checking in both modes.
- Images get blocked. If your whole email is one big image, some readers see an empty box. Live text and proper alt text keep the message readable.
How I build now
I write the structure in MJML, which compiles down to the tables and fallbacks above, so I’m not hand-coding every workaround. Then I test in Litmus across real clients in light and dark mode before anything goes out.
The ugly code isn’t a sign of an old-fashioned developer. It’s what it takes for one email to look right in every inbox.