jsx-email

Build and send responsive HTML emails using React components and TypeScript.

Library
npm
v3.2.1
1,257stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
44/100Fair
Development Activity24
Maintenance4
Community56
Maturity52
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
83/100Excellent
Architecture80
Code Quality78
Innovation82
Learning Curve90

jsx-email provides a set of React components and a rendering pipeline for building email templates with ordinary JSX instead of a proprietary templating DSL. It handles the parts of email development that are normally hand-rolled — Outlook conditional-comment hoisting, CSS inlining, cross-client compatibility quirks, and plain-text generation — so templates written in React and TypeScript render consistently across modern email clients.

The project ships as a small monorepo: the core jsx-email package (components, renderer, CLI) alongside peer plugin packages for inlining, minifying, pretty-printing, cleaning, and URL rewriting, plus a create-mail scaffolding tool for new projects. A bundled CLI and Vite-powered live-reload preview server let developers see rendered output update instantly while editing templates, and built-in caniemail/canispam integrations surface client-compatibility and spam-score warnings during development rather than after send.

What You Get

  • A library of email-safe React components (Button, Section, Row/Column, Head, Img, Tailwind, Barcode, Markdown, Conditional, Raw) that abstract away table-based email layout quirks
  • A render() / renderPlainText() API that compiles JSX into client-safe HTML and text, with Outlook conditional-comment and style-inlining handled automatically
  • A CLI with a live-reloading local preview server (Vite-powered) for iterating on templates visually
  • Built-in email-client compatibility checking (caniemail) and spam-score checking (canispam) surfaced through the CLI
  • A plugin system (separate inline/minify/pretty/clean/url packages) for opting into extra HTML processing without bloating the core import
  • A create-mail scaffolding tool for bootstrapping new email projects with sensible defaults

Common Use Cases

  • Building transactional emails (password resets, receipts, notifications) as versioned React components alongside application code
  • Sending marketing/newsletter templates through providers like AWS SES, Resend, Postmark, SendGrid, or Nodemailer that accept a rendered HTML string
  • Reusing a design system’s existing Tailwind utility classes inside email templates via the bundled Tailwind support
  • Working inside a monorepo where email templates need to build and preview alongside a larger application without extra setup

Under The Hood

Architecture jsx-email is organized as a moonrepo-managed pnpm monorepo (packages/jsx-email core, plus separate plugin-* and create-mail packages), with the core package split into three layers: components (src/components/*.tsx — Button, Section, Row, Column, Tailwind, Barcode, etc., each a plain React component), a renderer pipeline (src/renderer/render.ts → jsxToString → rehype-based post-processing via move-style, conditional, and raw plugins that hoist Outlook conditional comments and inline styles before rehype-stringify produces the final HTML string), and a CLI (src/cli, invoked via cli.js/bin “email”) that wraps esbuild-driven compilation (src/renderer/compile.ts) and a Vite-powered live preview/watch server (vite-reload.ts, vite-static.ts, watcher.ts) for local development. Configuration flows through a single defineConfig/loadConfig/mergeConfig chain (src/config.ts) consumed by both render() and the CLI, and a plugins.ts hook system (callHook/callProcessHook) lets beforeRender/afterRender/process stages be extended by the separate plugin-inline, plugin-minify, plugin-pretty, plugin-clean, and plugin-url packages — so the core render pipeline stays deliberately thin, with most cross-cutting behavior pushed out to peer packages wired in via config rather than hardcoded.

Tech Stack Written in TypeScript targeting Node 22+, jsx-email is a React 19 (peer dependency) component library whose runtime dependencies center on esbuild for JSX/TSX compilation, rehype/rehype-stringify for HTML post-processing, and an extensive UnoCSS/Tailwind stack for utility-class support inside emails. The CLI and preview server layer in Vite with a native file watcher, Radix UI primitives and Zustand for the preview app’s own interface, plus caniemail/canispam for email-client compatibility and spam-score checking, and shiki for code highlighting. Build/task orchestration across the monorepo is handled by moonrepo rather than per-package scripts, with pnpm workspaces (catalog: version pinning) tying the core package to its sibling plugin packages and the create-mail scaffolding tool; CI runs a matrixed test/test-cli/smoke-test/validate/release pipeline, and linting/formatting uses oxlint/oxfmt enforced through husky pre-commit hooks.

Code Quality The core package has an extensive Vitest suite (one test file per component, plus renderer-behavior tests for conditional rendering, style hoisting, and markdown/color-scheme handling), asserting directly against rendered HTML strings and CSS fragments — an appropriate strategy for an HTML-string-output library. Source is fully typed TypeScript with generated declaration files, and the project uses oxlint/oxfmt rather than the more common ESLint/Prettier pairing, wired into pre-commit hooks so style issues are caught before commit. CI runs dedicated test, CLI-test, smoke-test, and validation workflows on every change, indicating a mature quality bar for a community-maintained project.

API Design jsx-email’s core idea is treating email templates as ordinary React components rather than string templates or a bespoke DSL — components like Tailwind, Conditional, Row/Column, and Raw map onto familiar React/Tailwind idioms, while the renderer transparently handles work developers otherwise hand-roll: Outlook conditional-comment hoisting, style inlining, and per-client compatibility checking surfaced through the CLI. The plugin system keeps the base API surface small (render()/renderPlainText() plus a handful of components) while letting teams opt into extra processing without bloating the core import, and the bundled live-reloading preview server gives an edit-and-see-instantly workflow that raw MJML/Handlebars-based approaches typically lack.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search