Install
openclaw skills install @shbernal/email-compatWrite 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 actually 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.
openclaw skills install @shbernal/email-compatEmail clients are not browsers. Outlook on Windows renders with Microsoft Word,
Gmail strips <style> 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 <command> [options]
Everything it prints is JSON.
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 '*'
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.
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.search <query> [--category html|css|image|others] [--limit N]
check <slug> --clients <globs> [--version <v>]
lint --clients <globs> [--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.
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 <div> and <p>.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.Follow these by default and most lint findings never appear.
Layout
<table> for layout. Not <div> + flexbox, not grid — display:flex and
display:grid are unsupported in Outlook Windows and several others.role="presentation" on layout tables so screen readers skip them.float or
position — neither is reliable.<td> via padding, or on spacer rows. Margins are
inconsistent, and padding on <div>/<p> is unreliable in Outlook.CSS
<style> blocks are stripped or ignored in
several clients, notably Gmail in forwarded and clipped messages.<style> block only for what cannot be inlined — media queries and
pseudo-classes — and treat it as progressive enhancement.background-color beats background.position, float, z-index, calc(), custom properties, and web
fonts as anything other than an enhancement with a real fallback.Content
alt on images; many clients block images by default, so the alt
text is the email for those readers.width and height on images, and display:block to kill the
gap under them.Dark mode
prefers-color-scheme is supported in some clients and ignored in others,
and some clients invert colours on their own regardless.#FFFFFF or #000000 where inversion would destroy contrast.Outlook Windows specifically
notes field
gives the specific technique per feature.<!--[if mso]> ... <![endif]--> conditional
comments; other clients ignore them.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.
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.