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...
Design & media
Email Compatibility
Try itWrite 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.
| Verdict | Severity | What to do |
|---|---|---|
supported | — | Use it. |
unsupported | error | It will not render. Use a fallback. |
mitigated | warning | Works with a documented workaround. Read notes — this is where the useful detail lives. |
untested | unknown | Nobody 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'sfeatureup there for itstitle,url,positionsandlast_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_countis 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_countis 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'sverdictthere.
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, noborder-radius, no background images without VML, unreliablepaddingonand.outlook.outlook-com— Outlook.com webmail. A normal browser engine. Almost nothing in common with the above despite the name.outlook.macos— versions2011,2016, then16.80(the rewritten "new Outlook"), which behaves entirely differently from the older ones.gmail.desktop-webmailvsgmail.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:flexanddisplay:gridare 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
floatorposition— 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-colorbeatsbackground. - Avoid
position,float,z-index,calc(), custom properties, and web fonts as anything other than an enhancement with a real fallback.
Content
- Always set
alton images; many clients block images by default, so the alt text is the email for those readers. - Set explicit
widthandheighton images, anddisplay:blockto 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-schemeis supported in some clients and ignored in others, and some clients invert colours on their own regardless.- Do not use pure
#FFFFFFor#000000where inversion would destroy contrast. - Test transparent PNGs against both backgrounds.
Outlook Windows specifically
- Rounded corners and background images need VML. The linter's
notesfield 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
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.
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...
Draft, reply, send, forward, and schedule email
Verify email addresses with the BounceBan API. Single and bulk email verification specializing in catch-all (accept-all) and SEG-protected emails, fast email...
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...