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.
Medium because broken rendering hurts conversion and trust across a large recipient slice without exposing data or breaking delivery.
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.
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)
ID: sending-pipeline-infrastructure.template-engine.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:
// 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.