18.4. HTML Emails
Table of Contents
Why HTML Emails Matter
Plain text emails are simple and reliable, but many real applications need richer messages. Think of:
- Password reset emails with a big “Reset password” button
- Order confirmations with tables of items
- Welcome emails with your logo and brand colors
All of these are HTML emails. They are small web pages, but with very strict rules.
In this chapter you will not learn how to send emails. You will focus on how to build HTML email content that works in real inboxes.
Key idea: HTML emails are like tiny web pages, but email clients support old and limited HTML and CSS. You must code them in a careful, old‑school way.
HTML vs Plain Text Emails
Plain Text Emails
A plain text email contains only characters, no formatting:
Hi Alice,
Your order has been shipped!
Track it here:
https://example.com/track/123
Thanks,
Example StorePros:
- Very compatible with all clients and devices
- Small and fast
- Easy to generate from backend code
Cons:
- No colors, no bold, no images, no layout
- Easy to miss links or important information
HTML Emails
HTML emails support formatting and structure:
<html>
<body>
<p>Hi Alice,</p>
<p><strong>Your order has been shipped!</strong></p>
<p>
Track it here:
<a href="https://example.com/track/123">View tracking status</a>
</p>
<p>Thanks,<br>Example Store</p>
</body>
</html>Pros:
- Better branding: logo, fonts, colors
- Clear CTAs (call to action) with buttons
- Tables for invoices and order summaries
Cons:
- Rendering is inconsistent across email clients
- More likely to break if you use modern CSS
- Requires more testing
In practice, many applications send multipart emails with both versions:
- A
text/plainpart - A
text/htmlpart
The email client chooses which one to show.
Rule: Always provide a plain text fallback when sending HTML emails. This improves deliverability and accessibility.
Core Structure of an HTML Email
Basic HTML Skeleton
Email HTML usually looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Your subject here</title>
</head>
<body>
<!-- Content -->
</body>
</html>
Some clients ignore <head> contents, but including it is still good practice.
Use Tables for Layout
Modern web pages often use flexbox or CSS grid. Email clients, especially Outlook, often do not support them well. For layout you usually use <table> tags.
Example: a simple one‑column email layout:
<body style="margin:0; padding:0;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td align="center" style="padding:20px 0;">
<!-- Container -->
<table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" style="border:1px solid #dddddd;">
<tr>
<td style="padding:20px; font-family:Arial, sans-serif; font-size:16px; line-height:1.5;">
<!-- Email content here -->
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>Notes:
- Outer table is full width, used to center the inner container.
- Inner table uses a fixed width, for example 600 pixels, which is common for emails.
role="presentation"tells screen readers that this table is only for layout.
Rule: Use <table> based layouts for HTML emails, not flexbox or CSS grid. This is crucial for compatibility.
Styling HTML Emails Safely
Inline Styles
Many email clients strip out <style> blocks or ignore some CSS sources. The most reliable way to apply styles is with the style attribute.
Bad (may be ignored):
<head>
<style>
.button {
background: #4CAF50;
}
</style>
</head>
<body>
<a href="..." class="button">Click</a>
</body>Better:
<a href="https://example.com"
style="background:#4CAF50; color:#ffffff; padding:10px 20px; text-decoration:none; border-radius:4px; display:inline-block;">
Click
</a>This is verbose, but works across more clients.
Commonly Supported CSS Properties
Safe to use in most clients:
| Category | Examples |
|---|---|
| Text | font-family, font-size, font-weight, color, line-height |
| Box model | padding, margin (limited), border, background-color |
| Display/layout | display:block, display:inline-block, text-align, vertical-align |
| Images | width, height, border-radius (partially) |
Risky or often unsupported:
| Feature | Notes |
|---|---|
| Flexbox | Poor support, especially in Outlook |
| CSS Grid | Poor support |
position | Often ignored |
| Web fonts | Limited support, require fallbacks |
| Complex media queries | Not supported in many desktop clients |
When unsure, test or check email CSS support tables (for example, caniemail.com).
Use System Fonts
Web fonts are not guaranteed to load. Use a stack of safe fonts:
<span style="font-family: Arial, Helvetica, sans-serif; font-size:16px;">
Hello from our app!
</span>Creating a Simple HTML Template
Here is a very small but realistic HTML email for a password reset.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Password reset</title>
</head>
<body style="margin:0; padding:0; background-color:#f4f4f4;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td align="center" style="padding:20px 0;">
<table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" style="background-color:#ffffff; border-radius:4px; overflow:hidden;">
<!-- Header -->
<tr>
<td style="background-color:#2b6cb0; padding:16px 24px; color:#ffffff; font-family:Arial, sans-serif; font-size:20px;">
Example App
</td>
</tr>
<!-- Body -->
<tr>
<td style="padding:24px; font-family:Arial, sans-serif; font-size:16px; color:#333333; line-height:1.5;">
<p style="margin:0 0 16px 0;">Hi {{ user_name }},</p>
<p style="margin:0 0 16px 0;">
We received a request to reset your password. Click the button below to choose a new one.
</p>
<p style="margin:0 0 24px 0; text-align:center;">
<a href="{{ reset_link }}"
style="background-color:#2b6cb0; color:#ffffff; text-decoration:none; padding:12px 24px; border-radius:4px; display:inline-block; font-weight:bold;">
Reset your password
</a>
</p>
<p style="margin:0 0 16px 0; font-size:14px; color:#666666;">
If you did not request a password reset, you can ignore this email.
</p>
<p style="margin:0; font-size:14px; color:#666666;">
Thanks,<br>Example App Team
</p>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="background-color:#f4f4f4; padding:12px 24px; text-align:center; font-family:Arial, sans-serif; font-size:12px; color:#999999;">
© {{ year }} Example App. All rights reserved.
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
Dynamic parts, like {{ user_name }}, {{ reset_link }} and {{ year }}, will be filled by your backend template system.
Buttons and Call‑To‑Action Links
Button as a Styled Link
Most email buttons are just <a> tags with styles:
<a href="{{ verify_link }}"
style="background-color:#38a169; color:#ffffff; text-decoration:none; padding:12px 30px; border-radius:4px; display:inline-block; font-family:Arial, sans-serif; font-size:16px;">
Verify your email
</a>
You can center it using a containing <p> with text-align:center.
Bulletproof Buttons with Tables
Some clients handle inline styles inconsistently on <a>. You can use a button built from a table cell.
<table role="presentation" cellpadding="0" cellspacing="0" border="0" align="center">
<tr>
<td bgcolor="#3182ce" style="border-radius:4px;">
<a href="{{ action_link }}"
style="display:inline-block; padding:12px 24px; font-family:Arial, sans-serif; font-size:16px; color:#ffffff; text-decoration:none;">
Confirm your account
</a>
</td>
</tr>
</table>This is more verbose, but tends to be more reliable.
Using Images in HTML Emails
Inline Images vs External URLs
Most of the time you will host images on a server and reference them with src URLs:
<img src="https://cdn.example.com/email/logo.png"
alt="Example App logo"
width="120"
style="display:block; margin:0 auto 16px auto;">Important points:
- Always include
alttext. Many clients block images by default. - Specify
widthand possiblyheightso layout is stable even when images are blocked. - Use HTTPS URLs.
Avoid Background Images
Background images in CSS are often not supported. Prefer regular <img> elements.
Bad:
<td style="background-image:url('https://...');">
...
</td>
Better: just use an <img> tag at the top of a cell.
Logo Example
A header with a logo:
<tr>
<td style="padding:20px; text-align:center; background-color:#1a202c;">
<img src="https://cdn.example.com/logo-email.png"
alt="Example App"
width="140"
style="display:block; margin:0 auto;">
</td>
</tr>Making HTML Emails Responsive
Many recipients read emails on phones. A 600‑pixel fixed width layout is standard, but on small screens you want text to remain readable.
Full responsive design can be complex in emails and heavy use of media queries may not work everywhere. For beginners, focus on:
- Single column layouts
- Larger font sizes, at least 14px to 16px
- Buttons that are easy to tap, for example at least 44px high
Simple example with a safe width:
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td align="center">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="max-width:600px;">
<tr>
<td style="padding:16px; font-family:Arial, sans-serif; font-size:16px;">
Content
</td>
</tr>
</table>
</td>
</tr>
</table>
Here max-width:600px lets the email shrink nicely on narrow screens.
Rule: Prefer simple, single column layouts with large fonts and clear buttons. Complex multi‑column responsive layouts are hard to make reliable in emails.
Dynamic Content and Templating
In a backend application you will rarely write raw HTML with actual values. Instead, you create a template with placeholders.
Example for a “welcome” email template, using a generic template syntax:
<p style="font-family:Arial, sans-serif; font-size:16px;">
Hi {{ user_name }},
</p>
<p style="font-family:Arial, sans-serif; font-size:16px;">
Welcome to Example App! Click the button below to get started.
</p>
<p style="text-align:center;">
<a href="{{ onboarding_link }}"
style="background-color:#2b6cb0; color:#ffffff; text-decoration:none; padding:12px 24px; border-radius:4px; display:inline-block;">
Go to your dashboard
</a>
</p>Your backend language and template engine will:
- Load this HTML file as a template.
- Replace
{{ user_name }}and{{ onboarding_link }}with real values. - Send the final HTML string through your email sending code.
Accessibility and Text‑Only Fallbacks
HTML emails should still be readable if:
- Styles are removed
- Images are blocked
- The user uses a screen reader
A few practices help:
- Use semantic tags like
<p>,<h1>for important headings. - Provide
alttext for images, for example"Order receipt"for a banner image. - Avoid using text embedded inside images as the only way to convey information.
- Make sure the HTML email still makes sense as plain text.
Plain text version example for the earlier password reset email:
Hi {{ user_name }},
We received a request to reset your password.
Reset your password by opening this link:
{{ reset_link }}
If you did not request a password reset, you can ignore this email.
Thanks,
Example App TeamCommon Pitfalls and Gotchas
Here are typical mistakes when creating HTML emails:
| Mistake | Problem |
|---|---|
| Using modern CSS layout only | Layout breaks in Outlook and older clients |
Putting all styles in <style> only | Styles may be stripped or ignored |
| No plain text version | Worse deliverability and bad experience in some clients |
| Relying only on images for content | Content invisible when images are blocked |
| Very wide content (full‑width 1200px) | Hard to read on mobile, horizontal scrolling |
Forgetting alt attributes | Screen readers and blocked images show nothing useful |
| Using JavaScript | JavaScript is usually removed and is also a security risk |
Rule: Do not use JavaScript in HTML emails. It is stripped or blocked by almost all email clients.
Reusable Patterns for Application Emails
You can design basic patterns and reuse them across many emails.
Common Layout Blocks
- Header
Contains logo and maybe application name. - Body
- Greeting: “Hi {{ user_name }},”
- Main message paragraph
- Call‑to‑action button
- Additional information or instructions
- Footer
- Copyright info
- Company address (for legal reasons in many countries)
- “You received this email because …” text
Example footer:
<p style="margin:0; font-family:Arial, sans-serif; font-size:12px; color:#999999; text-align:center;">
You received this email because you signed up for Example App.
</p>
<p style="margin:4px 0 0 0; font-family:Arial, sans-serif; font-size:12px; color:#999999; text-align:center;">
© {{ year }} Example App, Inc. 123 Example Street, Example City
</p>You can extract these repeated sections into separate templates in your backend, and include them in each email template.
Summary
HTML emails are constrained mini web pages that must:
- Use table‑based layouts
- Use mostly inline CSS
- Avoid JavaScript and advanced CSS features
- Provide text‑only fallbacks
- Be simple, readable, and robust
With these patterns, your backend can generate HTML emails for verification, password resets, order receipts, and many other common flows.
Views: 6
KAHIBARO