# HTML validated against common email clients

- **Pattern:** `ab-002465` (`sending-pipeline-infrastructure.template-engine.email-client-compatibility`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002465
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002465)

## Why it matters

Email clients are notoriously inconsistent renderers — Outlook 2016-2019 strips flexbox and CSS grid, Gmail removes unreferenced `<style>` blocks, and Apple Mail handles media queries differently from Yahoo. Templates that render perfectly in the preview pane arrive as broken, unstyled blobs for a meaningful portion of recipients, directly degrading conversion on transactional and marketing sends. The user-experience cost compounds for password resets, receipts, and onboarding flows where a misaligned CTA means an abandoned signup or a support ticket.

## Severity rationale

Medium because broken rendering hurts conversion and trust across a large recipient slice without exposing data or breaking delivery.

## Remediation

Adopt MJML for new templates so the compiler emits table-based, client-safe HTML, or pipe existing HTML through a CSS inliner like `juice` before handing it to the ESP. Wire a Litmus or Email on Acid check into CI against Outlook 2016, Gmail web, and Apple Mail. See `src/emails/` for template organization.

```ts
import mjml2html from 'mjml'
import juice from 'juice'

const { html, errors } = mjml2html(template)
if (errors.length) throw new Error(errors.map(e => e.formattedMessage).join(', '))
const inlined = juice(html)
```

## Detection

- **ID:** `email-client-compatibility`
- **Severity:** `medium`
- **What to look for:** Check whether email templates use a framework or toolchain that produces cross-client compatible HTML. Look for MJML (which compiles to email-safe table-based HTML), Foundation for Emails, or a CSS inliner (`juice`, `inline-css`) applied in the rendering pipeline. Check for known incompatible patterns in raw HTML templates: `display: flex` or `display: grid` without table-based fallback, `position: absolute`, CSS variables, or `<style>` blocks with no inlining step. Also look for a Litmus or Email on Acid project configuration file (`.litmusrc`, integration in CI).
- **Pass criteria:** Email templates use at least 1 framework or tool that produces cross-client compatible HTML (MJML, Foundation for Emails, or a CSS inliner such as `juice` or `inline-css`). Count all incompatible CSS patterns found in templates (flexbox without table fallback, CSS grid, `position: absolute`) — there must be 0. Alternatively, a Litmus or Email on Acid configuration is present.
- **Fail criteria:** Templates are raw HTML with no CSS inlining step and no framework that handles cross-client compatibility. No evidence of email rendering testing tools in the project dependencies. Or incompatible CSS patterns are found.
- **Skip (N/A) when:** All email recipients use a known modern client — confirmed by documented client constraints.
- **Detail on fail:** `"Templates use flexbox layout without table-based fallback — broken in Outlook 2016-2019 (desktop)"` or `"No CSS inliner in dependencies and no email framework — <style> blocks will be stripped by Gmail"`
- **Remediation:** Use MJML for email-safe HTML, or add a CSS inliner:

  ```ts
  // Using MJML — produces table-based HTML compatible with all clients
  import mjml2html from 'mjml'

  const { html, errors } = mjml2html(`
    <mjml>
      <mj-body>
        <mj-section>
          <mj-column>
            <mj-text>Hello {{firstName}}!</mj-text>
          </mj-column>
        </mj-section>
      </mj-body>
    </mjml>
  `)

  if (errors.length > 0) {
    throw new Error(`MJML template errors: ${errors.map(e => e.formattedMessage).join(', ')}`)
  }

  // Or use juice to inline CSS into an existing HTML template
  import juice from 'juice'

  const inlinedHtml = juice(renderedHtml)
  ```

  After implementing, run client rendering tests — send to a Litmus or Email on Acid account, or preview in Gmail, Outlook, and Apple Mail — to verify the output renders correctly across clients.

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-002465
