Common Email Template Coding Mistakes and How to Fix Them
The email template coding mistakes that break real sends — dead links, missing unsubscribe, unresolved merge tags, invalid HTML — and how to fix each.
The most common email template coding mistakes aren’t exotic. Every developer ships the same handful, and they rarely show up in your own inbox test — they surface in a subscriber’s Outlook, in a language version you don’t read, or in the campaign report a week later. The upside: they’re predictable, and most take a minute to fix once you know where to look. Here are the ones that come up again and again in HTML email, and what to do about each.
The short version: check every link on the compiled email, confirm a visible unsubscribe link, leave no unresolved merge tags, validate the HTML, keep it under Gmail’s 102 KB clipping limit, and run the whole list against every language version — not just the primary one. The twelve mistakes below, with the fix for each, follow that order.

1. Broken links
A link that returns a 404 is the most common and most damaging email bug. A subscriber clicks your CTA, lands on a dead page, and trusts you a little less. Check every URL in the template — and check the compiled version, after merge fields resolve, not the raw source with unresolved tokens sitting in the href. If your ESP wraps links for click tracking, test the pre-wrap URLs. Mailchimp, Klaviyo, Brevo and others rewrite links at send time, and the wrappers report as failures if you check too early.
2. Missing or hidden unsubscribe link
No unsubscribe link puts the whole send at risk under CAN-SPAM, GDPR, and the Gmail and Yahoo bulk-sender rules. A link that’s technically in the HTML but invisible — white text on a white background, display:none, buried in a collapsed block — fails for the same reason. Keep it visible, in every language version, and make sure it uses the unsubscribe token your ESP expects instead of a hard-coded URL.
3. Unresolved merge tags and broken personalization
Hi {{first_name}}, going out with the braces still in it is a classic, and it usually happens because the test profile had a value and the real list doesn’t. Give every personalization tag a fallback and preview with both a filled and an empty profile. Each ESP has its own tag syntax too — a template that’s correct for Mailchimp’s *|FNAME|* is broken for Klaviyo’s {{ first_name }} — so proof it against the platform you actually send from.
4. Invalid or unclosed HTML
An unclosed <td>, a mismatched <table>, or a templating block like {% if %} with no {% endif %} won’t necessarily look wrong in your test. Browsers and Apple Mail quietly repair it; Outlook and Gmail each repair it differently, so one stray tag can collapse a multi-column layout in Outlook while every other client looks fine. Run the compiled HTML through a validator before it goes out.
5. CSS the email client silently drops
Email clients are years behind browsers. display:flex, grid, position:absolute, gap, modern selectors, unprefixed properties — Outlook’s Word rendering engine ignores most of them, and other clients are inconsistent. Build layout with nested tables and inline styles. Treat <style> blocks as progressive enhancement, since Gmail strips them in some contexts and most clients strip <head> entirely. Check any property you’re unsure about against a client-support table before you rely on it.
6. Fonts with no fallback
A custom or non-web-safe font-family with nothing after it renders as Times New Roman in most clients. Stay on the web-safe stack — Arial, Helvetica, Georgia, Verdana, Tahoma — or always close the stack with sans-serif or serif. Treat @font-face as a bonus for the clients that support it, never as the thing the design depends on.
7. Images with no dimensions, no alt text, or too much weight
Missing width and height make the layout jump as images load, and leave a collapsed empty box when a client blocks images — which most do by default. Missing alt text means a blocked image shows nothing and a screen reader reads the file name aloud. Oversized files slow the first render on mobile and push you toward Gmail’s clipping limit. Set explicit dimensions, write real alt text, and compress every image.
8. Passing Gmail’s 102 KB limit
Gmail clips a message at roughly 102 KB of HTML and hides everything past that behind a “View entire message” link — including, often, your unsubscribe link and open-tracking pixel. Builder bloat, duplicated inline styles, and base64-embedded images get you there faster than you’d expect, and a localized version is usually the one that crosses the line first. Keep the compiled HTML comfortably under 102 KB.
9. Fixed-width, non-responsive layout
A layout locked wider than about 600–640 px forces a horizontal scroll or a zoomed-out view on phones, where most opens now happen. Keep the main container near 600 px, use fluid widths and max-width, and test on a real device rather than a desktop preview pane.
10. Accessibility and preheader basics
Small fixes that get skipped:
- No
langattribute — screen readers guess the language and often mispronounce it. Set it per language version, and adddir="rtl"for right-to-left locales. - Layout tables without
role="presentation"— assistive tech announces every spacer table as a data grid, row and column counts included. - Low contrast — body text below the WCAG AA ratio is hard to read for a lot of people; check it against the actual background colour.
- Missing or wrong-length preheader — with none set, the client pulls the first text it finds into the inbox preview, usually “View in browser” or an image’s alt string.
11. Language versions that drift apart
When every locale is a separate hand-maintained file, they diverge: the German version gains a row the English one never got, a French version still has an English sentence under lang="fr", a link points at the wrong regional page. Build every language version from one shared structure so the layout can’t drift, and diff the variants before send.
12. Inconsistent UTM tags
If some links in a campaign are tagged and some aren’t — or the same campaign is utm_campaign=spring_sale on one link and spring-sale on another — your analytics split one campaign across several sources and the report stops being useful. Standardise the parameters and apply them to every tracked link.
A pre-send checklist for these email template coding mistakes
Before you hit send, in about a minute:
- Every link resolves, checked on the compiled email
- Unsubscribe link present, visible, using the ESP token
- No
{{ }}or*| |*left in the rendered output; fallback on every personalization tag - HTML validates — no unclosed tags or template blocks
- Layout holds in Outlook, Gmail and Apple Mail
- Images have dimensions and alt text; total weight is reasonable
- Compiled HTML under 102 KB
- Readable on a phone
langset, contrast passes, preheader written- Every language version checked, not just the primary
Fixing these mistakes for good
Most of these email template coding mistakes are mechanical — which is exactly why they slip when a campaign is running late, and why they multiply when you send in several languages. EmailStitch compiles your template and runs these as 31 checks on every locale, ranked by severity, and holds the export back when something would actually break the email. The judgment calls — does the layout really hold in Outlook, does the French copy read well — stay with you; the mechanical checks don’t need to.
Want a QA gate in front of every export? Start a free EmailStitch account.