Cross-client HTML email

html-email

A hand-authored, zero-dependency framework built on one principle: never drop support for the oldest clients. Every conditional comment, MSO hack, and VML fallback is documented and linted.

Why use html-email?

Zero dependencies No compiler, no Node_modules required to build. Just vanilla HTML that survives on any client.
Dark mode, 3 ways Support for prefers-color-scheme, Outlook.com specific overrides, and explicit background painting.
28 Quirk Defenses Thoroughly documented fixes for classic Outlook, Gmail clipping, iOS auto-scaling, and more.

See it render

Open, download, or copy the actual email HTML. Both preserve the full cross-client compatibility engineering.

Framework build → The assembled output from framework/ partials, populated with the Northwind Botanicals winter-arrivals campaign.
Open Download
2014 reference campaign → A production template from 2014, content-scrubbed to a fictitious brand, compatibility engineering byte-preserved.
Open Download

Branded templates

Five distinct designs, each rebuilt in the house conventions with a fictitious brand and self-authored generated art. Copy the HTML straight into your ESP, or download it to edit.

Previews

Rendered from the framework build via headless Chrome.

Desktop, light mode
Desktop · light
Desktop, dark mode
Desktop · dark
Mobile, single column
Mobile · stacked

Lint your own email

The linter is zero-dependency and works on any HTML email, whatever built it — MJML, React Email, Maizzle, or hand-written. The default rule set is client behaviour every email is subject to, not this project's conventions.

node framework/build/lint.mjs campaign.html

It checks Gmail's 102 KB clip and 8 KB <style> cap, unbalanced CSS, missing alt/width, MSO conditional balance, the unsubscribe link, and more — with --json and --sarif output for CI.

Build it yourself

Zero dependencies. Assemble the partials and lint the output:

cd framework/build && node build.mjs && node lint.mjs --profile house ../dist/email.html

View on GitHub Pre-send checklist →