Back to browse
GitHub Repository

Email compatibility engine - analyze HTML against 250+ CSS rules across 15 clients, score compatibility, detect spam, check accessibility, simulate dark mode.

8 starsTypeScript

Open-sourced an email QA lib 8 checks across 12 clients in 1 audit call

by tikkatenders·Mar 3, 2026·1 point·2 comments

AI Analysis

●●●BangerSolve My ProblemShip It

Drop-in email QA library replacing $500/month SaaS audits with open-source depth.

Strengths
  • 250+ CSS properties tested per client with per-client fix snippets—not a generic linter, actually specific.
  • AI auto-fix integration: generates framework-aware code (React Email, MJML) for failing checks, not just warnings.
  • 574 passing tests, real spam heuristics (SpamAssassin + GDPR), handles transactional exemptions—production-grade rigor.
Weaknesses
  • Email client compatibility testing is hard; reliance on 12 pre-recorded client profiles means edge cases slip through.
  • No live send/render verification—scores are static analysis, not proof of actual inbox delivery.
Target Audience

Email developers, marketing engineers, SaaS founders shipping transactional email.

Similar To

Litmus · Stripo · MJML Studio

Post Description

Hey HN, I built this because I think $500 for litmus just to check whether my emails would break in Outlook. After Sinch acquired them and pushed prices even higher, I started wondering how much of that could be a library instead of a SaaS dashboard. Turns out: most of it.

@emailens/engine is a single npm package that runs 8 analysis passes on your email HTML in one call:

1. CSS compatibility: 250+ properties checked against 12 email clients, with per-client scores (0–100). Each warning includes severity, the specific client, and a fix snippet tailored to your framework (React Email, MJML, Maizzle, or plain HTML).

2. Spam scoring: 45+ heuristic signals modeled after SpamAssassin, CAN-SPAM, and GDPR. Catches caps ratio, hidden text, URL shorteners, missing unsubscribe (with transactional email exemption), deceptive links, image-to-text ratio, and more.

3. Accessibility: WCAG contrast, alt text, heading hierarchy, layout table roles, small text, missing lang attribute.

4. Link validation: broken hrefs, insecure HTTP, javascript: protocols, deceptive URLs, empty mailto/tel, generic link text.

5. Image analysis: missing dimensions, oversized data URIs, WebP/SVG in email, tracking pixels, missing display:block.

6. Inbox preview: subject/preheader truncation per client, Gmail clipping detection (102KB threshold).

7. Domain deliverability: SPF, DKIM, DMARC, MX, and BIMI DNS validation. No external dependencies, uses node:dns/promises.

8. Template variables: catches unresolved merge tags across Handlebars, ERB, Mailchimp, Salesforce, etc.

The engine parses the HTML once and shares the DOM across all analyzers, running all 8 checks is basically the cost of one parse. Framework-aware fixes are where it gets interesting. Every CSS warning comes with a fix snippet tailored to your framework:

React Email JSX → component-level fixes (e.g., VML components for Outlook border-radius) MJML → <mj-*> element suggestions Maizzle → utility class alternatives Plain HTML → inline CSS / VML fallbacks

Fixes are classified as css (simple property swap) or structural (needs HTML restructuring). For structural issues, there's an AI fix layer, the engine builds a context-rich prompt from the warnings, scores, and original source, and delegates to whatever LLM you provide. It's BYOK: you pass a provider function, the engine handles the prompt engineering.

React Email compilation runs in a sandboxed environment (isolated-vm for true heap isolation on servers, node:vm for local/CLI use, or QuickJS via WASM). Maizzle blocks filesystem-accessing PostHTML directives at validation time. MJML uses the standard compiler. There's also a CSS transformation layer, not just flagging issues, but rewriting the HTML per client. Inlines <style> blocks for Gmail, strips unsupported properties for Outlook, and can simulate dark mode (full inversion for Gmail Android, partial for Apple Mail, none for Outlook Windows). 574 tests covering all of the above. MIT licensed. No accounts, no dashboards, no vendor lock-in.

I'd love feedback on:

The API surface, does auditEmail() (all-in-one) vs createSession() (selective checks, shared parse) make sense as the two entry points?

The scoring formula: 100 - (errors × 15) - (warnings × 5) - (info × 1), too aggressive? Too lenient?

Missing email clients or checks you'd want to see?

Repo: https://github.com/emailens/engine

Docs: https://docs.emailens.dev

If you'd rather not wire it up yourself: https://emailens.dev

Similar Projects