██████╗ ██████╗ ███████╗████████╗ ██████╗██████╗ █████╗ ███████╗████████╗
██╔══██╗██╔═══██╗██╔════╝╚══██╔══╝██╔════╝██╔══██╗██╔══██╗██╔════╝╚══██╔══╝
██████╔╝██║ ██║███████╗ ██║ ██║ ██████╔╝███████║█████╗ ██║
██╔═══╝ ██║ ██║╚════██║ ██║ ██║ ██╔══██╗██╔══██║██╔══╝ ██║
██║ ╚██████╔╝███████║ ██║ ╚██████╗██║ ██║██║ ██║██║ ██║
╚═╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
Postcraft is a collection of high-quality, unstyled components for creating beautiful, responsive emails with React and TypeScript.
✨ Features 🧰 Tech Stack 🚀 Getting Started 📦 Packages ✍️ Editor 🔌 Integrations 🛠️ CLI
| Postcraft is a collection of high-quality, unstyled components for creating beautiful email templates using React and TypeScript. We handle inconsistencies across Gmail, Apple Mail, Outlook, and other email clients — so you can focus on content. |
💡 Why Postcraft? We believe email is an extremely important communication medium. It's time to stop developing emails like it's 2010 and rethink how email can be done in 2026 and beyond.
| 🧱 Component-based Reusable React components |
🎨 Tailwind CSS Email-safe utility presets |
📱 Responsive Works on every screen size |
🌙 Dark mode aware Automatic theme handling |
| ✍️ Visual Editor Drag-and-drop @postcraft/editor |
🔌 Provider Ready Resend, Nodemailer, SendGrid, & more |
🧪 Fully Typed First-class TypeScript support |
🚀 CLI Included postcraft dev / postcraft export |
This monorepo is built with the following stack.
💡 All logos above are the official brand marks of each respective project. Hover over any icon to see the technology name.
This monorepo is organized into the following packages:
| Package | Version | Description |
|---|---|---|
postcraft |
Core React components for building email templates | |
@postcraft/render |
Transform React components into HTML email templates | |
@postcraft/editor |
Rich text editor built on Tiptap & ProseMirror | |
create-postcraft |
Scaffold a new Postcraft project in seconds | |
@postcraft/ui |
Shared UI components used across the monorepo | |
@responsive-email/postcraft |
Responsive email layout components |
flowchart LR
Compose["Compose email in JSX"] --> Tailwind["<Tailwind> wraps tree & scans className"]
Tailwind --> Inline["Inline-able rules → element style attributes"]
Tailwind --> Head["Non-inline-able rules → <style> in <Head>"]
Tailwind --> Downlevel["Downlevel for Gmail, Outlook, Apple Mail"]
Inline --> Render["Rendered to email-ready HTML"]
Head --> Render
Downlevel --> Render
Render --> Send["Send via Resend, Nodemailer, SendGrid, ..."]
flowchart LR
Cli["postcraft dev / postcraft export"] --> Scan["Scan ./emails directory"]
Scan --> Meta["Resolve files, dirs & dependencies"]
Meta --> Build["esbuild-bundle templates"]
Build --> Render["Render each template to HTML / plain text"]
Dev["postcraft dev"] --> Server["Start Next.js preview server"]
Server --> WS["Socket.IO hot-reload on file change"]
WS --> Live["Live preview in browser at localhost:3000"]
Export["postcraft export"] --> Out["Write static .html output to ./out"]
flowchart LR
Edit["Drag-and-drop email in @postcraft/editor"] --> JSON["ProseMirror / TipTap JSON document"]
JSON --> Serialize["EmailNode / EmailMark serializer"]
Serialize --> Postcraft["Render to Postcraft components"]
Postcraft --> Compose["composeEmail() → HTML + plain text"]
Compose --> Export["Export or send"]
flowchart LR
ReactComp["React email component"] --> Runtime{"Runtime?"}
Runtime -->|"Node.js"| RenderNode["@postcraft/render (node)"]
Runtime -->|"Edge / Browser"| RenderEdge["@postcraft/render (edge / browser)"]
RenderNode --> ReadableStream["react-dom/server ReadableStream"]
RenderEdge --> ReadableStream
ReadableStream --> Html["DOCTYPE-ready HTML string"]
ReadableStream --> Text["Plain text alternative"]
Html --> Providers["Send via any ESP"]
Text --> Providers
flowchart TB
Browser["Browser / Next.js preview"]
Core["postcraft core components"]
Editor["@postcraft/editor rich text editor"]
Renderer["@postcraft/render React → HTML"]
Tailwind["Email-safe Tailwind CSS engine"]
TipTap["TipTap + ProseMirror"]
Responsive["@responsive-email/postcraft layouts"]
Ui["@postcraft/ui shared UI"]
Cli["postcraft CLI"]
Providers["Resend · Nodemailer · SendGrid · Mailgun · Postmark · AWS SES · Plunk · Scaleway · MailerSend"]
Browser -->|"Preview templates"| Core
Cli -->|"dev / export / build / start"| Browser
Cli -->|"esbuild-bundle + render"| Renderer
Editor -->|"EmailNode / EmailMark"| Core
Editor -->|"Document model"| TipTap
Core -->|"Inline styles & <head> rules"| Tailwind
Core -->|"Shared primitives"| Ui
Responsive -->|"Compose"| Core
Renderer -->|"HTML / plain text"| Providers
Ui -->|"Preview server"| Browser
- Node.js
>= 20.0.0 - pnpm
>= 11.0.0(or npm / yarn / bun)
Scaffold a new project in seconds:
npx create-postcraft@latest
cd my-email-project
npm install
npm run devThe dev server starts at http://localhost:3000 with a live preview interface for your email templates.
Add Postcraft to an existing project:
npm install postcraft
# or
pnpm add postcraft
# or
yarn add postcraftimport {
Html,
Head,
Body,
Container,
Heading,
Text,
Button,
Preview,
Tailwind,
pixelBasedPreset,
} from "postcraft";
interface WelcomeEmailProps {
name: string;
verificationUrl: string;
}
const tailwindConfig = {
presets: [pixelBasedPreset],
};
export default function WelcomeEmail({
name,
verificationUrl,
}: WelcomeEmailProps) {
return (
<Html lang="en">
<Tailwind config={tailwindConfig}>
<Head />
<Body className="bg-gray-100 font-sans">
<Preview>Welcome to Postcraft — Verify your email</Preview>
<Container className="max-w-xl mx-auto p-8">
<Heading className="text-2xl font-bold text-gray-900">
Welcome, {name}!
</Heading>
<Text className="text-base text-gray-600 mt-4">
Thanks for signing up. Please verify your email address to get
started.
</Text>
<Button
href={verificationUrl}
className="bg-blue-600 text-white px-6 py-3 rounded-md block text-center no-underline box-border mt-6"
>
Verify Email Address
</Button>
</Container>
</Body>
</Tailwind>
</Html>
);
}
WelcomeEmail.PreviewProps = {
name: "Giorgi",
verificationUrl: "https://postcraft.dev/verify/abc123",
} satisfies WelcomeEmailProps;Convert your React email component to an HTML string ready for sending:
import { render } from "@postcraft/render";
import { WelcomeEmail } from "./emails/welcome";
const html = await render(
<WelcomeEmail name="Giorgi" verificationUrl="https://example.com/verify" />,
);
const text = await render(
<WelcomeEmail name="Giorgi" verificationUrl="https://example.com/verify" />,
{ plainText: true },
);A set of standard, cross-client compatible components to help you build beautiful emails without dealing with table-based layouts.
| Component | Description |
|---|---|
Html |
Root HTML wrapper with lang attribute |
Head |
Email head element for meta, styles, fonts |
Body |
Main body wrapper |
Container |
Centered content wrapper (max-width: 37.5em) |
Section |
Interior content block for grouping |
Row |
Horizontal row for multi-column layouts |
Column |
Column within a Row |
| Component | Description |
|---|---|
Preview |
Inbox preview text (always first in Body) |
Heading |
h1–h6 heading elements |
Text |
Paragraph text blocks |
Button |
Styled call-to-action link button |
Link |
Inline hyperlinks |
Img |
Responsive image component |
Hr |
Horizontal divider |
| Component | Description |
|---|---|
Tailwind |
Tailwind CSS support for emails |
Font |
Custom web font loading |
Markdown |
Render Markdown content in emails |
CodeBlock |
Syntax-highlighted code blocks |
CodeInline |
Inline code formatting |
Postcraft provides a rich text email editor built on TipTap and ProseMirror. It serializes content to Postcraft components and exports email-ready HTML and plain text.
| Feature | Description |
|---|---|
| 🧠 Bubble Menu | Contextual formatting toolbar on selection |
| 🎛️ Inspector | Property editing panel for selected elements |
| ⚡ Slash Commands | Type / to quickly insert elements |
| 🎨 Theming | Built-in themes (basic, minimal) with CSS customization |
| 📐 Column Layouts | Drag-and-drop multi-column email structures |
| 🔗 Link Editing | Inline link management |
| 📤 Email Export | composeEmail() to export email-ready HTML |
| 🖼️ Image Upload | Built-in image upload support |
npm install @postcraft/editorimport { EmailEditor, type EmailEditorRef } from "@postcraft/editor";
import "@postcraft/editor/themes/default.css";
import { useRef } from "react";
export function MyEditor() {
const ref = useRef<EmailEditorRef>(null);
return (
<EmailEditor
ref={ref}
content="<p>Start typing your email...</p>"
theme="basic"
/>
);
}| Import | Contents |
|---|---|
@postcraft/editor |
Main EmailEditor component and top-level API |
@postcraft/editor/core |
Serializer, types, and event bus |
@postcraft/editor/extensions |
35+ TipTap extensions for email elements |
@postcraft/editor/ui |
Bubble menus, slash command, inspector |
@postcraft/editor/plugins |
ProseMirror plugins |
@postcraft/editor/utils |
Shared utilities |
Emails built with Postcraft can be sent with any email service provider:
| Provider | Example |
|---|---|
| Resend | examples/resend |
| Nodemailer | examples/nodemailer |
| SendGrid | examples/sendgrid |
| MailerSend | examples/mailersend |
| Mailgun | examples/mailgun |
| Postmark | examples/postmark |
| AWS SES | examples/aws-ses |
| Plunk | examples/plunk |
| Scaleway | examples/scaleway |
Example: Sending with Resend
import { Resend } from "resend";
import { WelcomeEmail } from "./emails/welcome";
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send({
from: "Acme <onboarding@resend.dev>",
to: ["user@example.com"],
subject: "Welcome to Acme!",
react: (
<WelcomeEmail name="Giorgi" verificationUrl="https://example.com/verify" />
),
});Postcraft ships with a powerful CLI to streamline your email development workflow.
postcraft/
├── apps/
│ ├── demo/ # Demo email templates showcase
│ ├── docs/ # Documentation site (Mintlify)
│ └── web/ # Marketing website (Next.js)
├── benchmarks/ # Performance benchmarks
│ └── tailwind/
├── examples/ # Email service provider integrations
│ ├── aws-ses/
│ ├── mailersend/
│ ├── mailgun/
│ ├── nodemailer/
│ ├── plunk/
│ ├── postmark/
│ ├── resend/
│ ├── scaleway/
│ └── sendgrid/
├── packages/
│ ├── create-email/ # Scaffolding CLI (npx create-postcraft)
│ ├── editor/ # Rich text visual editor
│ ├── postcraft/ # Core email components & CLI
│ ├── render/ # React → HTML renderer
│ ├── responsive-email-postcraft/ # Responsive email components
│ ├── tsconfig/ # Shared TypeScript configs
│ └── ui/ # Shared UI components (preview server)
├── playground/ # Interactive component playground
├── scripts/ # Build & release automation scripts
└── skills/ # AI agent skills for email development
└── postcraft/
# Clone the repository
git clone https://github.com/GiorgiKavtaradze-prog/postcraft.git
cd postcraft
# Install all dependencies
pnpm install
# Build all packages
pnpm build
# Run all tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Lint the codebase
pnpm lint
# Auto-fix linting issues
pnpm lint:fixTo avoid rebuilding after every change when working on the CLI:
# Link the dev version globally
pnpm link ./dev -g
# Use it just like the regular CLI
postcraft-dev [command] [flags]We welcome contributions from the community! Please read our Contributing Guide before getting started.
- 🐛 Found a bug? Open an issue
- 💡 Have an idea? Start a discussion
- 🔧 Want to contribute code? Read our Contributing Guide
Please read our Security Policy to learn how to report security vulnerabilities responsibly.
This project is licensed under the MIT License — see the LICENSE.md file for details.
Built with ❤️ by Giorgi Kavtaradze and the Postcraft community
