HTML Emails
Order confirmations, newsletters and bank statements are usually HTML emails. Email apps are far stricter and more varied than web browsers, so email developers still use techniques that went out of fashion on the web years ago.
In this lesson you will learn why email HTML is different, build a safe email layout with tables and inline styles, add preheader text and basic dark mode support, and test your email before it reaches real inboxes.
Why email HTML is different
Today's browsers all follow the same HTML standard closely. An email, however, is opened by an email client: Gmail on the web and on phones, several versions of Outlook, Apple Mail, Yahoo Mail and many more. Each one cleans the HTML for safety and supports a different mix of features.
| On the web | In email |
|---|---|
| CSS in a linked stylesheet | Linked stylesheets are ignored; important styles are written inline |
| Layout with Grid and Flexbox | Support is patchy, so layout uses tables |
| JavaScript adds behaviour | JavaScript never runs |
| Images load normally | Some apps hide images until the reader allows them |
| Any modern CSS | Each app supports its own subset |
The biggest problem is the classic desktop Outlook for Windows, which draws emails with Microsoft Word's layout engine, not a browser engine. It ignores much of modern CSS, including Flexbox, Grid and often max-width. Many offices still use it, so emails are built to survive it.
So in email, and only in email, you will deliberately use some of the old techniques described in Deprecated & Legacy HTML and Page Layout Techniques.
A safe email structure
A robust email follows a standard pattern:
- An outer table, 100% wide, that paints the background colour.
- An inner table, usually 600 pixels wide, that holds the content and shrinks on phones.
- One row per block: header, message, button, footer.
- Every layout table has
role="presentation", so screen readers do not announce it as a data table. - Styles are written in
styleattributes on each element.
Run this example to see a shipping notification. It is a preview in a browser; real email apps may show small differences.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<meta name="supported-color-schemes" content="light dark">
<title>Your order is on its way</title>
</head>
<body style="margin:0; padding:0; background-color:#f2f2f2;">
<div style="display:none; max-height:0; overflow:hidden; mso-hide:all;">
Your block-print kurta left Jaipur today and should reach Pune by Friday.
</div>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:#f2f2f2;">
<tr>
<td align="center" style="padding:24px 12px;">
<table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" style="width:100%; max-width:600px; background-color:#ffffff;">
<tr>
<td style="padding:20px 24px; background-color:#7a1f1f; color:#ffffff; font-family:Arial, Helvetica, sans-serif; font-size:20px; font-weight:bold;">
Meera's Handloom
</td>
</tr>
<tr>
<td style="padding:24px; font-family:Arial, Helvetica, sans-serif; font-size:16px; line-height:24px; color:#222222;">
<h1 style="margin:0 0 12px; font-size:22px; line-height:28px;">Your order is on its way</h1>
<p style="margin:0 0 16px;">Hi Priya, order JP-4471 (block-print kurta, ₹1,299) left our Jaipur workshop today. It should reach Pune by Friday.</p>
<table role="presentation" cellpadding="0" cellspacing="0" border="0">
<tr>
<td style="border-radius:6px; background-color:#1d4ed8;">
<a href="https://example.com/track/JP-4471" style="display:inline-block; padding:12px 24px; font-family:Arial, Helvetica, sans-serif; font-size:16px; font-weight:bold; color:#ffffff; text-decoration:none;">Track your parcel</a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding:16px 24px; border-top:1px solid #e5e5e5; font-family:Arial, Helvetica, sans-serif; font-size:13px; line-height:20px; color:#666666;">
Meera's Handloom, MI Road, Jaipur 302001<br>
You received this email because you placed an order.
<a href="https://example.com/email-preferences" style="color:#666666;">Email preferences</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>Look at what is unusual compared with a web page:
- Old table attributes.
width,cellpadding,cellspacing,borderandalignare obsolete on the web, but they help Outlook and other apps that ignore CSS. The inner table haswidth="600"for those apps andmax-width:600pxfor the rest, so it shrinks on phones. - Inline styles everywhere. Each
<td>repeats its font settings, because some apps remove<style>blocks or do not pass styles down into tables. - A "bulletproof" button. The button is a real link with padding, on a coloured table cell, so it still works when images are switched off.
- Absolute URLs. An email has no website folder, so every link and image needs a full
https://address. See File Paths & URLs. - A real footer. Who sent the email, why the reader got it, and a way to unsubscribe. Large email providers such as Gmail expect easy unsubscribing from bulk senders.
Writing CSS, then inlining it
Typing the same font-family on fifty cells is slow and error-prone. Most teams write normal CSS in a <style> block and then run the email through a CSS inliner, a tool that copies each rule into the style attributes of the matching elements. Many email platforms do this automatically. Keep the <style> block too, for things that cannot be inlined, such as media queries:
<style>
@media (max-width: 480px) {
.stack { display: block !important; width: 100% !important; }
}
</style>The !important is needed because inline styles normally win over a <style> block.
Images and text
- Some email apps do not display images until the reader allows them, so never put the main message only inside an image.
- Give every image a full
https://URL,widthandheightattributes, a meaningfulalttext, andstyle="display:block"to avoid a thin gap below it. - Use PNG or JPG. Many email apps do not show SVG images.
- Custom web fonts work in only some apps. Always end the font list with a common font such as Arial or Georgia.
The preheader
In the inbox, most apps show a short line of text after the subject. This is the preheader. If you do not write one, the app takes the first text it finds in your email, which is often "View this email in your browser" or an image's alt text.
<div style="display:none; max-height:0; overflow:hidden; mso-hide:all;">
Your block-print kurta left Jaipur today and should reach Pune by Friday.
</div>Place it as the very first thing inside <body>. The styles hide it in the opened email; mso-hide:all is a special property that Outlook for Windows understands. Write it as a second subject line: short, useful and different from the subject.
Dark mode
Many readers use their email app in dark mode, and apps handle it in three ways: some leave your colours alone, some invert only light backgrounds, and some invert everything. You cannot control all of them, but you can help:
- Add the
color-schemeandsupported-color-schemesmeta tags shown in the example, which tell supporting apps that your design handles both modes. - Apple Mail and some other apps honour a
prefers-color-schememedia query, so you can choose your own dark colours there. Many others, including the Gmail apps and Outlook for Windows, ignore it and recolour the email themselves. - A logo with dark lettering on a transparent background vanishes on a dark page. Give it a light outline or put it on its own coloured tile.
<style>
@media (prefers-color-scheme: dark) {
.email-card { background-color: #1f1f1f !important; }
.email-text { color: #eeeeee !important; }
}
</style>Testing before you send
Never send an email to thousands of people after only checking it in your browser.
- Send test emails to real accounts: Gmail on the web and on a phone, Outlook (both the desktop app and Outlook on the web if you can), Apple Mail on an iPhone, and Yahoo Mail.
- Check the email with images switched off, in dark mode, and on a narrow phone screen.
- Click every link, and check that the preheader looks right in the inbox list.
- Keep the HTML small. Gmail is known to cut off ("clip") messages whose HTML is larger than about 100 KB, hiding the rest, including your footer, behind a "View entire message" link.
- Send a plain-text version alongside the HTML; the reader's app chooses one. The PHP side of sending is covered in Sending Email.
Paid preview services can show your email in dozens of apps at once, and the free website Can I Email lists which features each app supports.
Common mistakes
- Relative image paths. Use full
https://URLs. - The whole email as one big image. Image-blocking shows a blank email, and screen readers get nothing.
- Relying on a
<style>block or linked stylesheet. Inline the important styles. - Using Flexbox, Grid or JavaScript. Most email apps ignore them.
- No preheader. The inbox then shows whatever text it finds first.
Key points
- Email apps are not browsers; each supports a different subset of HTML and CSS, and none run JavaScript.
- Lay out emails with nested tables marked
role="presentation", about 600 pixels wide, with old table attributes for Outlook. - Write important styles inline, often with an inliner tool, and keep media queries in a
<style>block with!important. - Use absolute
https://URLs, real text instead of images of text, and meaningfulalttext. - A hidden preheader controls the inbox preview line; colour-scheme meta tags and careful colours help in dark mode.
- Test in real email apps, with images off and in dark mode, and keep the HTML under about 100 KB.
Exercise
Write an HTML email for a Lucknow coaching centre announcing that admissions for the 2027 batch are open. Include a preheader, a 600-pixel table layout with role="presentation", a heading, a short paragraph, a bulletproof "See batch timings" button and a footer with the centre's address. Use only inline styles and absolute URLs.
Show solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Admissions open for 2027</title>
</head>
<body style="margin:0; padding:0; background-color:#eef2f7;">
<div style="display:none; max-height:0; overflow:hidden; mso-hide:all;">Morning and evening batches, classes start 5 April.</div>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td align="center" style="padding:24px 12px;">
<table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" style="width:100%; max-width:600px; background-color:#ffffff;">
<tr>
<td style="padding:24px; font-family:Arial, sans-serif; font-size:16px; line-height:24px; color:#222222;">
<h1 style="margin:0 0 12px; font-size:22px;">Admissions open for the 2027 batch</h1>
<p style="margin:0 0 16px;">Join our Class 11 science batch in Hazratganj. Seats are limited to 30 students per batch.</p>
<table role="presentation" cellpadding="0" cellspacing="0" border="0">
<tr>
<td style="background-color:#0f766e; border-radius:6px;">
<a href="https://example.com/batches" style="display:inline-block; padding:12px 24px; color:#ffffff; font-family:Arial, sans-serif; font-weight:bold; text-decoration:none;">See batch timings</a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding:16px 24px; font-family:Arial, sans-serif; font-size:13px; color:#666666; border-top:1px solid #e5e5e5;">
Hazratganj, Lucknow 226001 | <a href="https://example.com/unsubscribe" style="color:#666666;">Unsubscribe</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>The outer table paints the background, the inner one holds the content at up to 600 pixels, and the button is a padded link, so it works even with images switched off.
Quick Quiz
1. Why do HTML emails still use tables for layout?
Outlook for Windows uses Word's rendering engine, so tables are the layout method every app understands.
2. Which image address will work in an email?
An email has no folder of its own, so only a full absolute URL can be loaded.
3. What is the preheader?
A hidden block at the top of the body controls the inbox preview line.
4. Why should the main message never be only an image?
If images are blocked, an image-only email appears blank.
Learn HTML with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
