@postwave/email-react
v0.1.0
Published
JSX → MJML compiler for email components. Compose responsive, dark-mode-aware emails as React-style components and ship them through any ESP.
Maintainers
Readme
@postwave/email-react
A small JSX → MJML compiler for email components. Postwave's lighter
equivalent of react-email, designed so an LLM agent (Claude Code,
Cursor, etc.) can write email in the React it already knows and have it
render to email-safe HTML — without the agent needing to learn MJML.
MIT licensed. Layer 2 of the Postwave open-core architecture (see
LICENSE-BOUNDARY.md).
Install
npm install @postwave/email-react react react-dom
# or
pnpm add @postwave/email-react react react-domYou also need a TypeScript runtime if you want to render .tsx files
directly via the CLI:
npm i -D tsxPrimitives
| Component | MJML output |
| ----------- | ---------------------------------------- |
| Email | <mjml><mj-head/><mj-body/></mjml> root |
| Section | <mj-section> |
| Column | <mj-column> |
| Text | <mj-text> |
| Heading | <mj-text> with heading defaults |
| Button | <mj-button> |
| Image | <mj-image> |
| Divider | <mj-divider> |
| Spacer | <mj-spacer> |
| Link | inline <a> styled for email |
| SocialRow | <mj-social> + one element per item |
| Footer | A common unsubscribe footer block |
All primitives accept the underlying MJML attributes via camelCase or
kebab-case props. For example, Section accepts backgroundColor and
emits background-color="…".
Render API
import { renderToHtml, renderToMjml, Email, Section, Column, Text } from "@postwave/email-react";
const tree = (
<Email preview="A preview line">
<Section>
<Column>
<Text>Hello world.</Text>
</Column>
</Section>
</Email>
);
// Just the MJML source:
const mjml: string = renderToMjml(tree);
// Compiled email-safe HTML + warnings:
const { html, errors } = renderToHtml(tree, {
validationLevel: "soft",
minify: false,
});renderToHtml returns { html, mjml, errors } where errors is the
array of non-fatal warnings emitted by the underlying MJML compiler.
CLI
The package ships a postwave-email-render binary:
# Default: compile to HTML on stdout
postwave-email-render ./Welcome.tsx
# Or just emit the intermediate MJML
postwave-email-render ./Welcome.tsx --out mjmlThe component file must default-export either a React element or a zero-arg function returning one.
For .tsx files you typically run via tsx:
npx tsx node_modules/.bin/postwave-email-render ./Welcome.tsxIntegration with the Postwave MCP server
If you are running @postwave/mcp-server
inside Claude Code (or any other MCP host), this package gives the agent
a clean path from "draft an email" to "preview + send":
- Agent writes
Welcome.tsxusing the primitives above. - Agent calls
renderToHtml(or thepostwave-email-renderCLI) to get email-safe HTML. - Agent calls the MCP tool
render_preview_htmlwith that HTML — gets back per-client screenshots from Inbox Reality. - Agent calls
predict_placementto get the predicted Primary / Promotions / Spam split. - When the user is happy, the agent calls
campaign_createwith the MJML (orsend_test_emailwith the HTML for a one-off transactional preview).
The two new MCP prompts email-from-jsx and email-from-markdown walk
the agent through this end-to-end.
Using from Claude Code
Once you have the MCP server connected:
"Generate a 3-section welcome email at
emails/Welcome.tsx, then preview it across Gmail and Outlook, and finally save it as a draft campaign for thewelcome-listaudience."
Claude will:
- Scaffold
emails/Welcome.tsxwith@postwave/email-reactprimitives (you can also pre-scaffold viapostwave generate email --name Welcome). - Run
renderToHtmlon it. - Call
render_preview_htmlfor Gmail + Outlook. - Call
campaign_createwith the rendered MJML.
Why a new package?
- Smaller surface area than
react-email. We only need the dozen primitives that map cleanly to MJML, not a full set of mail-client hacks. - Owns the JSX → MJML lowering. Agents are already great at JSX. MJML, less so. We want the model to write the easy thing and have the package do the boring transform.
- MIT, no Postwave-specific runtime dependency. Drop into any project that needs MJML.
