_emailmd_

Linting

Catch deliverability, accessibility, and readability problems before you send.

Rendering tells you the email works. Linting tells you whether it will land well. lint() checks an email for problems that render fine but hurt it in practice: missing alt text, http:// links, Gmail's 102KB clip limit, generic link text, spam-trigger phrases, and more.

import { lint } from 'emailmd';

const findings = await lint(markdown);
// [{ rule: 'image-alt', severity: 'warning',
//    message: 'Image is missing alt text — …', line: 12 }]

Each finding carries a machine-readable rule id, a severity, a human-readable message, and the 1-based line in the source markdown. See the API reference for the full signature.

Severities

  • warning: likely a real problem. Fix these before sending.
  • suggestion: worth a look, but often intentional (a transactional email may deliberately skip the unsubscribe link, for example).

Rules

RuleSeverityChecks
image-altwarningImages without alt text
insecure-linkwarningLinks or image sources using http://
gmail-clipwarningMinified HTML over 102KB (Gmail clips the message)
renderwarningRender warnings, folded in so one call surfaces everything
image-formatwarning / suggestionSVG and data: images, stripped by most clients (warning); WebP/AVIF, broken in Outlook desktop (suggestion)
link-textsuggestionGeneric link text ("click here", "here", "link")
preheader-missingsuggestionNo preheader in frontmatter
preheader-lengthsuggestionPreheader longer than ~100 characters (inbox previews truncate)
unsubscribesuggestionNo unsubscribe link anywhere in the rendered output
spam-wordssuggestionCommon spam-filter trigger phrases ("act now", "100% free", …)
placeholder-imagesuggestionImages or hero backgrounds on placeholder hosts (picsum.photos, placehold.co, wsrv.nl, …)

Template tokens are respected throughout: a {{tracking_url}} link is never flagged insecure, and [Unsubscribe]({{unsubscribe_url}}) satisfies the unsubscribe check.

In the CLI

emailmd lint runs the same checks from the terminal and prints findings with line numbers:

emailmd lint input.md

The exit code is 1 when warnings are found, so it slots into CI; suggestions alone exit 0 unless you pass --strict. See CLI → Linting.

In the Builder

Pass the lint prop to <EmailmdBuilder /> (or the lint option to useEmailmd) and findings surface live alongside render warnings as you type.

On this page