Rendered email CSS allowlist / deny-list gate backed by vendored caniemail data.
Validates rendered email HTML against a curated subset of caniemail.com support data for the Phase 86 locked client set: Gmail web, new Outlook web, and Apple Mail on macOS.
The policy is read from priv/sigra/email/caniemail-allowlist.json at
compile time — no network access occurs during CI. Call lint/1 from ExUnit
tests to fail the build when rendered HTML uses unsupported CSS constructs.
Usage in ExUnit
test "email CSS passes caniemail lint" do
email = Emails.suspicious_login_email(user, details)
assert :ok = Sigra.Email.CssLint.lint(email.html_body)
endScope
- Clients: Gmail web, new Outlook web (Microsoft 365), Apple Mail macOS
- Residual (documented, not waived): Legacy Outlook desktop Word-engine is partially addressed by the deny-list but is explicitly out-of-scope per D-86-09. Microsoft EOL: October 2026.
- Policy source: vendored
priv/sigra/email/caniemail-allowlist.json(MIT-licensed caniemail data, curated 2026-04-26)
See 86-CONTEXT.md D-86-02, D-86-03, D-86-09 for full rationale.
Summary
Functions
Returns the vendored caniemail policy map.
Lints rendered email HTML against the vendored caniemail policy.
Functions
@spec allowlist() :: map()
Returns the vendored caniemail policy map.
The map has three top-level keys:
"clients"— list of client identifiers this policy applies to"allow_css"— CSS properties safe to use in inline styles"deny_css"— CSS property patterns that break layout in one or more clients
Lints rendered email HTML against the vendored caniemail policy.
Returns :ok when no violations are found.
Returns {:error, [String.t()]} with a list of human-readable violation
descriptions when deny-listed CSS constructs are detected.
This function is intentionally simple and pattern-based — it does not parse the CSS AST. That is sufficient for the deny-list constructs that matter (they produce large, obvious substrings in inline styles).
Examples
iex> Sigra.Email.CssLint.lint("<div style='background-color: #fff;'>Hi</div>")
:ok
iex> Sigra.Email.CssLint.lint("<div style='display: flex;'>Hi</div>")
{:error, ["display:flex or display:flex found (not supported by Gmail web / Outlook web)"]}