Design & media

Email Compatibility

Try it

Write and verify HTML email that renders correctly across email clients. Use whenever building, editing, or reviewing an HTML email, an email template, or a transactional message, and whenever a question involves Outlook, Gmail, Apple Mail, or "will this render in email". Covers what CSS and HTML each client supports, backed by caniemail.com data. Provides the layout rules that keep an email compatible in the first place, then lints the finished markup and reports only what breaks, per client, with workarounds. Not for sending mail, deliverability, SPF/DKIM/DMARC, or ESP choice.

What it does

Write and verify HTML email that renders correctly across email clients. Use whenever building, editing, or reviewing an HTML email, an email template, or a transactional message, and whenever a question involves Outlook, Gmail, Apple Mail, or "will this render in email". Covers what CSS and HTML each client supports, backed by caniemail.com data. Provides the layout rules that keep an email compatible in the first place, then lints the finished markup and reports only what breaks, per client, with workarounds. Not for sending mail, deliverability, SPF/DKIM/DMARC, or ESP choice.

The skill document

HTML email compatibility

Email clients are not browsers. Outlook on Windows renders with Microsoft Word, Gmail strips `` blocks in some contexts, and support for anything modern is patchy and undocumented. This skill covers both halves of the problem: write markup that survives, then verify it against real data.

scripts/caniemail.mjs queries the caniemail.com dataset. Node 22+ and nothing else — no dependencies, no install step. It works offline against a bundled dataset snapshot, and says so when it does.

node scripts/caniemail.mjs  [options]

Everything it prints is JSON.

The loop

Write using the rules below, then always lint before calling it done. The rules prevent the common failures; the linter catches the rest.

# 1. Find the slug — they are not guessable.
node scripts/caniemail.mjs search "rounded corners"
#    -> css-border-radius

# 2. Decide how to build it.
node scripts/caniemail.mjs check css-border-radius --clients outlook.windows,gmail.*

# 3. Lint the finished email.
node scripts/caniemail.mjs lint --html draft.html --clients '*'

Reading a verdict

Four verdicts, and collapsing them is how confidently wrong advice happens.

VerdictSeverityWhat to do
supportedUse it.
unsupportederrorIt will not render. Use a fallback.
mitigatedwarningWorks with a documented workaround. Read notes — this is where the useful detail lives.
untestedunknownNobody has tested it. This is not evidence of support, and not evidence against it. Avoid it, or test it yourself.

untested is the one that matters most. It is not a soft unsupported and not a soft supported; roughly a sixth of the whole matrix has no data at all. Never report an untested feature as working.

Also check last_test_date and staleness. Some entries have not been retested in five years, and the tool tells you when a verdict is old enough to distrust.

Reading a lint finding

A finding carries only what its verdict decides: feature, severity, verdict, clients_affected, client_count, notes and feature_notes. One feature usually produces two or three of them, because it can fail differently in different clients.

  • features — a legend on the result keyed by slug. Look the finding's feature up there for its title, url, positions and last_test_date. These are facts about the feature and where your markup uses it, so they are the same for every finding naming it.
  • positions (in the legend) — every place the feature is used, as "line:col-line:col". occurrence_count is the true total; the list stops at ten, so when the two disagree there are more than you can see.
  • clients_affected — compressed against the clients you asked for. "*" means all of them, "outlook.*" means all the ones you asked for in that family. client_count is always the exact number, so you never have to expand them.
  • guidance — a second legend, keyed by verdict rather than by feature. Look up the finding's verdict there.

Commands

search  [--category html|css|image|others] [--limit N]
check   --clients  [--version ]
lint   --clients  [--html FILE] [--css FILE] [--no-untested]
clients

--clients takes comma-separated family.platform globs. Wildcards work on either segment: outlook.windows, outlook.*, *.ios, or * for all 48.

lint reads stdin as HTML when given neither --html nor --css, so cat draft.html | node scripts/caniemail.mjs lint --clients '*' works.

check --version pins a specific client version instead of the newest, and works with globs: check css-border-radius --clients outlook.* --version 2016 answers "does this work in Outlook 2016", which is usually the real question. Clients with no such version on record come back untested, with versions_on_record showing what they do have — only a version no requested client has is an error. The pin is echoed once as version_requested on the result, not on every entry.

Clients worth knowing

These are different rendering engines, not variants of one product:

  • outlook.windows — the Word renderer. The strictest target by far. No flexbox, no grid, no border-radius, no background images without VML, unreliable padding on and.
  • outlook.outlook-com — Outlook.com webmail. A normal browser engine. Almost nothing in common with the above despite the name.
  • outlook.macos — versions 2011, 2016, then 16.80 (the rewritten "new Outlook"), which behaves entirely differently from the older ones.
  • gmail.desktop-webmail vs gmail.mobile-webmail — different support, particularly around media queries and embedded styles.

Writing email that survives

Follow these by default and most lint findings never appear.

Layout

  • Use for layout. Not + flexbox, not grid — display:flex and display:grid are unsupported in Outlook Windows and several others.
  • Set role="presentation" on layout tables so screen readers skip them.
  • Fixed width, 600px or narrower. Use nested tables rather than float or position — neither is reliable.
  • Spacing goes on via `padding`, or on spacer rows. Margins are inconsistent, and `padding` on/`` is unreliable in Outlook.

CSS

  • Inline every style that matters. `` blocks are stripped or ignored in several clients, notably Gmail in forwarded and clipped messages.
  • Keep a `` block only for what cannot be inlined — media queries and pseudo-classes — and treat it as progressive enhancement.
  • No shorthand you can avoid: background-color beats background.
  • Avoid position, float, z-index, calc(), custom properties, and web fonts as anything other than an enhancement with a real fallback.

Content

  • Always set alt on images; many clients block images by default, so the alt text is the email for those readers.
  • Set explicit width and height on images, and display:block to kill the gap under them.
  • Never rely on an image alone to carry meaning or a call to action.
  • Include a plain-text alternative part.

Dark mode

  • prefers-color-scheme is supported in some clients and ignored in others, and some clients invert colours on their own regardless.
  • Do not use pure #FFFFFF or #000000 where inversion would destroy contrast.
  • Test transparent PNGs against both backgrounds.

Outlook Windows specifically

  • Rounded corners and background images need VML. The linter's notes field gives the specific technique per feature.
  • Wrap Outlook-only markup in <!--[if mso]> ... <![endif]--> conditional comments; other clients ignore them.

Scope

This covers rendering only — whether markup displays correctly. It says nothing about deliverability, SPF/DKIM/DMARC/BIMI, list management, or choosing between ESPs. Those are different problems with different tools.

Data freshness

The dataset is fetched from caniemail.com and cached for 24 hours. Every result carries a data_source field naming which copy answered — live, cache, or bundled — with a warning when it is not the live one. Pass --offline to skip the network deliberately, or --refresh to force a fetch.

Related skills

Use when the user asks to "build the email HTML", "make this email responsive", "fix dark-mode rendering", or "QA the email across clients"; produces the cod...

Build a transactional HTML email that renders correctly across Gmail, Outlook, and Apple Mail, with a plain-text alternative and dark-mode support. Use when writing or editing the HTML/text body of an email, or creating a reusable Drin template with variables. Covers the table-based layout rules, inlined styles, bulletproof buttons, preheader, and Drin's {{handlebars}} variable/section syntax.

1 installs

Use when Codex, Hermes, OpenClaw, Claude Code, Cowork, or another AI agent needs to plan, review, implement, audit, or improve email work focused on responsi...

3 installs

Verify email addresses with the BounceBan API. Single and bulk email verification specializing in catch-all (accept-all) and SEG-protected emails, fast email...

1 installs

Use when Codex, Hermes, OpenClaw, Claude Code, Cowork, or another AI agent needs to plan, review, implement, audit, or improve email work focused on repo-awa...

1 installs