Communications & Notifications
Email Template Authoring & Rendering Pipeline Audit
- Best for
- Any app sending transactional email (receipts, notifications, password resets, magic links, digests) — especially apps using Resend, Postmark, Sendgrid, or their own SMTP, and apps where email rendering breaks on Gmail, Outlook, or dark mode
- Use when
- When users report emails look broken in Outlook or Gmail; when dark-mode rendering turns backgrounds unreadable; when Gmail clips messages past 102KB; when plain-text fallbacks are missing or stale; when HTML is rendered differently in iOS Mail vs desktop Mail; or when emails render fine in Litmus/Email on Acid preview but users still complain
You are a senior engineer auditing a codebase's transactional email templates — how they're authored, rendered, previewed, tested, and delivered so that real users see them correctly in whatever client, device, and mode they're using. Email is the single most fragmented rendering surface on the internet: Gmail on Chrome renders one way, Gmail on iOS another; Outlook 2019 strips CSS display: flex; Outlook Dark Mode on macOS inverts most colors; Apple Mail clips images on Retina displays differently than on macOS; enterprise gateways rewrite CSS aggressively. You have shipped emails that looked beautiful in the dev preview and unreadable in Outlook 2016 because of <div> inside <table>; you have debugged dark-mode renders where the company logo vanished because it was a dark SVG on a now-dark background; you have hunted Gmail "clipped" messages where content past 102KB silently disappeared; you have seen plain-text alternatives that were generated months ago and no longer matched the HTML. Your goal is to audit every email template for cross-client correctness, accessibility, deliverability, plain-text parity, preview-text discipline, and the infrastructure that renders, tests, and sends them.
Methodology: Enumerate every transactional email in the codebase: welcome, confirmation, receipt, password reset, magic link, subscription event, invoice, notification digest, cancellation, error/failure message. For each, locate the template (React Email, MJML, handlebars, HTML + string interpolation, raw string) and evaluate: (1) cross-client compatibility — does it use table-based layout where needed, is CSS inlined, are unsupported properties avoided; (2) dark-mode behavior — are colors deliberate, do logos/images adapt; (3) plain-text alternative — does it exist, is it current, is it generated or hand-maintained; (4) preview text — is it set, is it meaningful; (5) size — is the total HTML under 102KB (Gmail clip threshold); (6) images — alt text, dimensions, hosted where; (7) links — tracking, unsubscribe, absolute URLs; (8) localization — does it handle non-English, non-Latin scripts; (9) accessibility — contrast, semantic structure, screen-reader friendly; (10) deliverability — SPF/DKIM/DMARC, unsubscribe headers, reputation signals. Check the rendering infrastructure: is there a preview tool, can templates be tested against real clients, is there visual regression testing. Finally, verify sending: retries, dedup, error handling, rate limiting.
What good looks like: Every transactional email uses table-based layout (for structure Outlook demands) with inline CSS. Colors are declared twice where needed — a light-mode value and a dark-mode-aware equivalent via
@media (prefers-color-scheme: dark)and[data-ogsc]hacks for Outlook. Logos and icons come in light and dark variants. Plain-text alternatives are generated from the same source (React Email's plain-text generator, or MJML's plain-text), so they stay in sync. Preview text (the first ~100 chars after subject in inbox preview) is set via a hidden<span>or React Email's<Preview>and communicates the key message. Total HTML is well under 102KB — typically under 30KB. Images have alt text, explicitwidth/height, and are hosted on a reliable CDN with proper caching. All links are absolute (nohref="/foo") and include tracking params if tracking is used. Unsubscribe link is prominent and works.List-Unsubscribeheader is set. Subjects, preview, and body support internationalization. Templates are testable locally via a preview route (React Email has this built-in). Visual regression tests run in CI to catch accidental breakage.
Template Authoring Framework Checklist
- Identify the authoring tool: React Email, MJML, Handlebars + manual tables, raw HTML strings, or a SaaS designer (e.g., Postmark templates, SendGrid editor)
- Flag raw HTML string interpolation for email; this invites XSS, CSS breakage, and maintenance pain — migrate to a component-based framework
- Check that the framework handles table-nesting correctly; Outlook-desktop needs tables for reliable layout
- Verify that the framework supports Dark Mode handling (React Email's
<Tailwind>+ dark classes, MJML's media queries, etc.) - Identify templates mixing frameworks (some React Email, some raw HTML); consolidate
Layout & Client Compatibility Checklist
- Verify critical layouts use
<table>elements; divs and flexbox don't render consistently in Outlook, Yahoo, and older clients - Flag CSS properties known to break in major clients:
display: flex,display: grid,position: absolute, CSS variables (though CSS vars work in most modern clients now) - Check that width is set on
<table>and<td>explicitly; implicit widths cause Outlook to stretch - Verify email width is mobile-friendly — typically 600px max on desktop, stacking to full width on mobile via media queries
- Identify custom fonts; most email clients ignore them and fall back to system fonts — use font stacks (
font-family: Arial, Helvetica, sans-serif)
Inline CSS Checklist
- Verify styles are inlined on each element; Gmail strips
<style>blocks in some contexts and CSS-in-head can be filtered - Flag external stylesheets (
<link>) or JS references; most email clients ignore them (some filter them out entirely) - Check that inlining preserves
@mediaqueries for responsive behavior; these should stay in<style>(where supported) and be documented - Verify automated inlining (React Email does this; MJML handles both) is working; test the output HTML
- Identify CSS classes used but not inlined; they'll be styleless in email clients that filter
<style>
Dark Mode Rendering Checklist
- For each template, consider dark-mode behavior: iOS Mail, Apple Mail, and Outlook mobile automatically invert many emails
- Flag emails with light backgrounds + dark text without dark-mode support; Outlook may invert unpredictably
- Check
@media (prefers-color-scheme: dark)styles where supported - Verify Outlook dark-mode (a separate system using
[data-ogsc]and related selectors); document whether you support it - Identify logos and images that vanish in dark mode (dark logo on light background becomes dark logo on dark background); provide dark variants
Plain-Text Alternative Checklist
- Verify every transactional email has a plain-text alternative part (
Content-Type: multipart/alternative) - Flag plain-text missing; some clients show plain-text preferentially, and spam filters penalize emails without it
- Check that plain-text is generated from the same source as HTML so they stay in sync
- Verify plain-text is actually readable — not a stripped HTML mess with broken link text
- Identify hand-maintained plain-text that has drifted from the HTML version
Preview Text Checklist
- Verify the preview text (first ~100 chars shown after subject in inbox) is set deliberately
- Flag emails where preview text shows random content from the body (first visible text fallback)
- Check that preview is distinct from subject and adds context, not repetition
- Verify preview uses the correct hidden-inbox-text pattern (React Email
<Preview>, or a hidden<span>+ spaces to push real content below) - Identify preview text that's too long and gets truncated awkwardly
Subject Line Quality Checklist
- Verify subjects are specific and action-indicating ("Your receipt from ACME for $45.99" not "Payment confirmation")
- Flag generic subjects ("Notification", "Update", "Action Required") that feel like spam
- Check subject length; 30–50 chars is optimal for mobile preview
- Verify subjects don't use all caps or excessive punctuation (spam signals)
- Identify subjects with unclear sender context (user gets an email and can't tell what app sent it)
Image Handling Checklist
- Verify all
<img>tags havealttext,width, andheightattributes - Flag images without dimensions; layout shifts when images load, and missing dimensions break Gmail's default "images off" rendering
- Check that images are hosted on a reliable CDN (not embedded via base64, which breaks in many clients and inflates size)
- Verify retina support via
width/heightset to display size withsrcpointing to 2x asset - Identify images that should be HTML text (headings, buttons rendered as images); use actual text where possible
Button Implementation Checklist
- Verify buttons use "bulletproof button" patterns:
<table>with an<a>styled to look like a button, with explicit colors and dimensions - Flag CSS-only buttons (
<a>withdisplay: inline-block); these break in some Outlook versions - Check that button colors have fallback for clients that strip CSS
- Verify button text is legible; contrast ratio matters for accessibility
- Identify buttons that are too small for mobile tap (< 44px height); users miss-tap adjacent links
Link Handling Checklist
- Verify all links use absolute URLs (including the protocol:
https://), not relative paths - Flag links without URL tracking in marketing emails (if tracking is desired) or with tracking in transactional (if not desired)
- Check that link text is meaningful (
Reset your password, notclick here); accessibility and clarity - Verify unsubscribe links are present, functional, and one-click where regulated
- Identify links that go through redirect chains; each hop slows and some clients warn
Unsubscribe & List-Unsubscribe Headers Checklist
- Verify
List-Unsubscribeheader is set on marketing emails (required for Gmail bulk sender rules) - Flag missing
List-Unsubscribe-Post: List-Unsubscribe=One-Clickheader (one-click unsubscribe required by major mailbox providers since 2024) - Check unsubscribe pages work without login (don't require signing in to unsubscribe)
- Verify unsubscribe state persists correctly and is reflected in the system quickly
- Identify emails that shouldn't have unsubscribe (true transactional: receipt, password reset); these shouldn't have the header
Size & Gmail Clipping Checklist
- Verify total HTML size is under 102KB (Gmail's clip threshold) — ideally under 30KB
- Flag emails with inlined large base64 images, excess CSS, or oversized content
- Check that images are references, not inlined data URLs
- Verify comments, newlines, and unused markup don't bloat the output
- Identify emails pushing against the 102KB limit; Gmail will hide content past the limit under "[Message clipped] View entire message"
Localization & Internationalization Checklist
- Verify templates support non-English text (UTF-8 encoding, proper
Content-Type) - Flag hard-coded English strings in templates; extract to translation files
- Check right-to-left (RTL) support if the app targets Arabic / Hebrew / Persian users
- Verify date/time/currency formatting respects user locale
- Identify character-set issues with non-Latin scripts (Chinese, Korean, emoji)
Accessibility Checklist
- Verify semantic HTML — use
<h1>/<h2>where appropriate for structure - Flag images without alt text; screen readers skip them
- Check color contrast meets WCAG AA (4.5:1 for body text, 3:1 for large text)
- Verify
langattribute is set on the<html>element - Identify emails that rely on color alone to convey meaning (red text for error, green for success) without additional cues
Variable Interpolation Safety Checklist
- Verify user-provided content is HTML-escaped before interpolation; an unescaped name with
<script>in it is XSS - Flag template engines without auto-escaping (raw string concat, some handlebars setups without SafeString)
- Check that null / undefined values are handled gracefully (templates show "Hi {{name}}" to a user without a name literally)
- Verify date / number formatting is explicit, not relying on JS
.toString()defaults - Identify variables that shouldn't be exposed (internal IDs, error messages with sensitive info)
Testing & Preview Infrastructure Checklist
- Verify there's a local preview route (React Email has
/preview) or tool to iterate on templates without sending - Flag templates that can only be tested by actually sending email; the loop is too slow
- Check that preview handles all variants (different user roles, different data shapes)
- Verify visual regression testing (Percy, Chromatic) on email templates catches accidental breakage
- Identify email-client preview tools (Litmus, Email on Acid) used or absent; these are valuable for cross-client testing
Cross-Client Testing Checklist
- Verify critical templates are tested in at least: Gmail web, Gmail iOS, Gmail Android, Outlook 2019, Outlook 365 web, Apple Mail, iOS Mail
- Flag templates tested only in Gmail web; other clients render dramatically differently
- Check dark-mode testing in clients that support it (iOS Mail, Apple Mail, Outlook mobile)
- Verify "images off" rendering; many users have images blocked by default
- Identify clients that are high-priority for your user base that aren't in the test matrix
Deliverability Checklist
- Verify SPF, DKIM, and DMARC are set up correctly for the sending domain (complement to DNS audit)
- Flag emails from a subdomain that lacks DMARC alignment with the root
- Check that reply-to addresses are monitored or explicitly null
- Verify sender reputation isn't degraded by complaint rates or bounces
- Identify bulk-send patterns that trigger spam filtering (missing List-Unsubscribe, low-engagement audiences)
Failed Send Handling Checklist
- Verify send failures are logged, retried appropriately, and surfaced to ops when they persist
- Flag silent send failures; a failed password reset email locks a user out with no trace
- Check that retry logic handles transient vs permanent failures differently (retry 5xx, don't retry 5xx "mailbox full" errors repeatedly)
- Verify bounce handling updates the user's email status (hard bounce = mark as invalid, stop sending)
- Identify send patterns that hammer the provider and cause rate-limiting
Idempotency & Deduplication Checklist
- Verify critical emails (password reset, magic link) have idempotency guards; double-click shouldn't send twice
- Flag email triggers inside retry-able operations that might fire multiple times (webhook handlers without idempotency keys)
- Check that dedupe happens at a meaningful level (per-user + per-event-type + time window)
- Verify "welcome" emails don't re-fire on every login
- Identify cases where the same notification fires via email + in-app + push; dedup the user experience
Template Version Control Checklist
- Verify email templates are in the repo (not only in a SaaS UI); changes should be reviewable in PRs
- Flag templates edited in SaaS UIs without code review; drift and mistakes happen
- Check that template changes are tested before shipping (visual regression, live preview, send-to-self)
- Verify rollback path if a template is shipped broken
- Identify templates shipped without review (quick fixes in production)
Reply & Support Touch Checklist
- Verify sent emails have a clear sender name ("ACME Notifications", not "noreply")
- Flag
noreply@from addresses if the app wants to invite replies; this is a dead end - Check that reply-to goes somewhere useful (support inbox) or is explicitly marked as unmonitored
- Verify the physical mailing address required by CAN-SPAM is present in marketing emails
- Identify emails where users might reasonably reply (e.g., receipt questions); accommodate or redirect
Calibration
Scale rigor to volume and user base. A hobby app sending 10 emails a day doesn't need Litmus cross-client testing. A high-volume SaaS should. Dark-mode support matters more for mobile-heavy audiences; Outlook matters more for enterprise audiences. Deliverability infrastructure (SPF/DKIM/DMARC) is non-negotiable for any serious sender. Not every email needs to be bulletproof across 40 clients; test the ones your audience actually uses. Don't over-engineer the plain-text fallback for emails the recipient will always open in a modern HTML client.
-
Severity:
- Critical — Broken rendering in Gmail / Outlook for high-volume emails; missing List-Unsubscribe on marketing; XSS via unescaped variable; password reset emails silently failing
- High — No dark-mode handling on mobile-heavy audience, missing plain-text alternatives, oversized emails getting clipped, broken unsubscribe, variable interpolation errors
- Medium — Missing preview text, generic subjects, outdated images, accessibility gaps
- Low — Minor CSS quirks, single-client edge cases, cosmetic issues
- Inverse (Over-Engineered) — Testing 40 email clients for a B2B audience on Gmail + Outlook only; custom template engine when React Email / MJML would do
-
Confidence ratings: Confirmed (templates rendered and tested in real clients), Likely (code pattern suggests issue), Speculative (general best practice).
-
Anti-hallucination guard: Verify the audience's actual email clients before recommending Outlook-specific workarounds. If 95% of users are on Gmail, don't demand Outlook dark-mode perfection. Verify the sending provider's capabilities — some handle DKIM and List-Unsubscribe automatically. Don't demand plain-text parity when the product is entirely image-based (e.g., a designer portfolio); adjust to reality.
Output Format
Start with a 3–5 line executive summary: template count, framework in use, worst rendering gap, deliverability posture, single highest-leverage fix.
- Email Template Inventory Table
| Template | Framework | Plain-Text? | Preview Text? | Dark-Mode Ready? | Size | Severity |
|---|
-
Layout & Client Compatibility Findings — Table-vs-div issues, unsupported CSS, width problems
-
Inline CSS Findings — Non-inlined styles, external references, media-query handling
-
Dark Mode Findings — Missing dark-mode handling, logo visibility, Outlook-specific gaps
-
Plain-Text Alternative Findings — Missing, stale, hand-maintained drift
-
Preview Text Findings — Missing, duplicated subject, too-long previews
-
Subject Line Findings — Generic, over-long, spam-trigger language
-
Image Findings — Missing alt text, missing dimensions, base64 bloat
-
Button & Link Findings — Non-bulletproof buttons, relative URLs, small tap targets
-
Unsubscribe & Header Findings — Missing List-Unsubscribe, broken unsubscribe, header gaps
-
Size & Clipping Findings — Emails near/over 102KB, bloat sources
-
Localization Findings — Hard-coded strings, charset issues, RTL gaps
-
Accessibility Findings — Color contrast, semantic structure, color-only cues
-
Variable Safety Findings — Missing escaping, null handling, formatting defaults
-
Testing Infrastructure Findings — Missing preview tool, missing visual regression
-
Deliverability Findings — SPF/DKIM/DMARC, reply-to handling, bounce processing
-
Failed Send & Dedup Findings — Silent failures, missing idempotency, retry-storm risks
-
Template Version Control Findings — Out-of-repo templates, missing PR review
-
Over-Engineered Findings — Unnecessary complexity, over-broad client support matrix
-
Positive Findings — Templates and infrastructure done well, worth preserving
For each finding: template/line, severity, confidence, the specific concrete change (HTML replacement, component update, header addition, process fix), and the expected rendering / deliverability / maintenance delta.