Maizzle builds the HTML.
21 clients rewrite it.
Emailens lints the HTML your Maizzle build writes and tells you what Outlook, Gmail and 19 other clients will do to it. Two commands. Runs locally. No account.
npm install -D @emailens/cli
npx maizzle build
npx emailens lint 'build_local/*.html' Findings with a client, a line, and a reason
This is an excerpt of the output for a template that centers a card with max-w-[600px] and lays out two buttons with flex and gap-4. The command exits non-zero when it finds an error.
build_local/welcome.html
error spam missing-unsubscribe No unsubscribe link found; required by CAN-SPAM and GDPR.
warn 14:36 outlook-windows,outlook-windows-legacy display:flex Outlook (New) does not support "display:flex".
warn 14:51 outlook-windows,outlook-windows-legacy,yahoo-mail+3 gap Outlook (New) does not support "gap".
warn 10:106 outlook-windows,outlook-windows-legacy max-width Outlook only honours max-width on a table.
warn 10:124 outlook-windows,outlook-windows-legacy+1 border-radius Outlook (New) does not support "border-radius". The gap between your preview and the inbox
Maizzle inlines whatever Tailwind generates. It does not know which utilities an email client will honour. These are findings from a template written the way you would write a web page.
flex Outlook on Windows does not support display:flex, so two buttons in a row stack or collapse. It needs a table, or a conditional table for Outlook.
gap-4 Not supported in Outlook on Windows, Yahoo Mail and several others. The space between the items disappears.
max-w-[600px] Outlook only honours max-width on a table it actually reads. On a div, the card runs the full width of the window.
rounded-xl, p-8 Outlook on Windows drops border-radius, and keeps padding on table cells only.
The email as a whole
Missing unsubscribe link, missing physical address, low contrast in dark mode: the things spam filters and readers notice.
Block the pull request that breaks Outlook
The same two commands, on the runner. No API key, no quota, no network call to Emailens.
One thing to get right: lint the build, not the source
# build_local is where "maizzle build" writes by default.
# Point the lint at whatever build.output.path is in your config.
npx emailens lint 'build_production/**/*.html' A source template compiled on its own has no project around it: no Tailwind config, no layouts, no components. In our test the classes produced no CSS and the lint came back nearly clean.
GitHub Actions
# .github/workflows/email-lint.yml
name: Email lint
on:
pull_request:
paths: ["emails/**"]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npx maizzle build
- run: npx emailens lint 'build_local/**/*.html' Your AI writes the email. Emailens checks it.
Add the MCP server and Claude Code or Cursor can lint the template it just wrote, read the findings, and fix them before you review the diff.
$ claude mcp add emailens -- npx -y @emailens/mcp Common questions
Does Emailens replace Maizzle? +
No. Maizzle is how you write and build the email. Emailens checks the HTML it produces against 21 email clients. You keep your templates, your Tailwind config, and your sending provider.
Do I need an account or an API key? +
No. The CLI runs the open-source @emailens/engine on your machine or your CI runner. There is no quota and nothing is uploaded. An account is only needed for hosted screenshots, share links, and the REST API.
Can I lint a source template directly? +
You can, with --format maizzle and @maizzle/framework@5 installed beside the CLI (a .vue file needs version 6). It compiles that one file with no project around it, so layouts, components and your Tailwind config are not applied. For a real project, lint the build output.
Does it work with Maizzle 5 and Maizzle 6? +
Yes. Both write plain HTML, and that is what Emailens reads. The version only matters if you lint source files directly.
Are the suggested fixes written for Maizzle? +
In the hosted preview and the engine, yes. Send the template with format maizzle and a fix comes back in Tailwind classes: width utilities inside an Outlook conditional table in place of flexbox, padding utilities on the children in place of gap.
How is the score calculated? +
Each client gets a score from 0 to 100. The headline score is the worst client, not an average, because an email that renders in twenty clients and breaks in Outlook is a broken email.
Lint your next template
Runs locally. No signup required.
$ npx maizzle build && npx emailens lint 'build_local/*.html' Using something else? Lint React Email templates or Lint MJML templates