Getting Started with React Email
Build maintainable email templates using React components instead of tangled HTML tables.
James O'Brien
Email Engineer
Why React Email Exists
Building email templates with raw HTML is painful. You're writing nested tables six levels deep, inlining every style, wrapping things in MSO conditional comments, and fighting rendering bugs across dozens of clients. The result is fragile, hard-to-maintain code that nobody wants to touch.
React Email solves this by letting you write email templates using React components. You get component reusability, proper version control, TypeScript support, and a development experience that feels like building a web app. Under the hood, React Email compiles your components into the battle-tested HTML and inline CSS that email clients require.
It's not a visual builder — it's a developer tool. If your team writes React, React Email will feel immediately natural. If your team doesn't write code, this isn't the right tool.
Setting Up a React Email Project
Getting started takes about two minutes. You need Node.js 18+ installed.
# Create a new React Email project
npx create-email@latest
# Or add to an existing project
npm install react-email @react-email/components -E
If you're starting fresh, create-email scaffolds a project with example templates, a preview server, and the necessary configuration. If you're adding React Email to an existing Next.js or Node project, install the packages directly.
Your project structure will look like this:
my-email-project/
emails/
welcome.tsx
receipt.tsx
password-reset.tsx
package.json
tsconfig.json
Each file in the emails/ directory is a React component that exports a default function — your email template.
Creating Your First Email Template
Here's a complete welcome email template using React Email's built-in components:
import {
Html,
Head,
Preview,
Body,
Container,
Section,
Text,
Button,
Hr,
Img,
Link,
} from "@react-email/components";
interface WelcomeEmailProps {
userName: string;
loginUrl: string;
}
export default function WelcomeEmail({ userName, loginUrl }: WelcomeEmailProps) {
return (
<Html>
<Head />
<Preview>Welcome to our platform, {userName}!</Preview>
<Body style={main}>
<Container style={container}>
<Img
src="https://yourdomain.com/logo.png"
width={120}
height={40}
alt="Company Logo"
/>
<Section style={section}>
<Text style={heading}>Welcome, {userName}!</Text>
<Text style={paragraph}>
We're excited to have you on board. Your account is set up and
ready to go. Click the button below to log in and get started.
</Text>
<Button style={button} href={loginUrl}>
Log In to Your Account
</Button>
</Section>
<Hr style={hr} />
<Text style={footer}>
If you didn't create this account, you can safely ignore this email.
</Text>
</Container>
</Body>
</Html>
);
}
const main = {
backgroundColor: "#f6f9fc",
fontFamily:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif",
};
const container = {
backgroundColor: "#ffffff",
margin: "0 auto",
padding: "20px 0 48px",
marginBottom: "64px",
maxWidth: "560px",
};
const section = {
padding: "0 48px",
};
const heading = {
fontSize: "24px",
fontWeight: "bold" as const,
color: "#1a1a1a",
margin: "0 0 16px",
};
const paragraph = {
fontSize: "16px",
lineHeight: "1.6",
color: "#4a4a4a",
margin: "0 0 24px",
};
const button = {
backgroundColor: "#2563eb",
borderRadius: "6px",
color: "#ffffff",
fontSize: "16px",
fontWeight: "bold" as const,
textDecoration: "none",
textAlign: "center" as const,
display: "block",
padding: "12px 24px",
};
const hr = {
borderColor: "#e6ebf1",
margin: "32px 0",
};
const footer = {
color: "#8898aa",
fontSize: "12px",
lineHeight: "1.5",
padding: "0 48px",
};
Notice how this looks like a normal React component. Props for dynamic content, style objects for CSS, and readable JSX instead of nested HTML tables. React Email handles the conversion to email-safe HTML when you render it.
Component Library Overview
React Email provides a set of components specifically designed for email rendering. Each one compiles to the appropriate HTML structure for cross-client compatibility:
- Html: The root element. Sets the doctype and lang attribute.
- Head: Renders the
<head>element. Use it to include meta tags and style blocks. - Preview: Sets the preview text (the snippet shown next to the subject line in most clients). This is rendered as hidden text at the top of the email body.
- Body: The
<body>element with sensible defaults for margin and padding. - Container: A centered, max-width wrapper. Compiles to a table-based centering pattern.
- Section: A semantic grouping element. Renders as a table row internally.
- Row and Column: For multi-column layouts. Row creates a table row; Column creates table cells. These handle the fluid hybrid pattern internally.
- Text: A paragraph element with email-safe defaults for margin and line-height.
- Link: An anchor tag with proper styling defaults. Accepts
hrefand standard link props. - Button: A call-to-action button that renders as a padded, styled link — not a
<button>element (which doesn't work in email). - Img: An image element with the required attributes for email (
display: block,border: 0, width/height attributes). - Hr: A horizontal rule with consistent rendering across clients.
Previewing Your Emails
React Email includes a built-in development server that lets you preview your templates in the browser with hot reload:
# Start the preview server
npx email dev
This opens a browser window at localhost:3000 where you can see all your email templates, switch between them, view the rendered HTML source, and even send test emails directly from the UI. The preview server watches your files and updates in real-time as you edit.
The preview is rendered using your browser's engine, which is closer to Apple Mail and iOS Mail than to Outlook or Gmail. For production testing, you still need to use tools like Litmus or Email on Acid to see how your templates render across all clients.
Sending Emails via API
React Email produces HTML strings that you can send through any email API. Here's an example using Resend, which has native React Email support:
import { Resend } from "resend";
import WelcomeEmail from "./emails/welcome";
const resend = new Resend("re_your_api_key");
await resend.emails.send({
from: "onboarding@yourdomain.com",
to: "user@example.com",
subject: "Welcome to Our Platform!",
react: WelcomeEmail({
userName: "Alex",
loginUrl: "https://yourdomain.com/login",
}),
});
Resend accepts the React component directly via the react property. For other providers, you'll need to render the component to an HTML string first:
import { render } from "@react-email/render";
import WelcomeEmail from "./emails/welcome";
const html = await render(
WelcomeEmail({
userName: "Alex",
loginUrl: "https://yourdomain.com/login",
})
);
// Now send 'html' via SendGrid, SES, Postmark, or any other provider
await sendgrid.send({
from: "onboarding@yourdomain.com",
to: "user@example.com",
subject: "Welcome to Our Platform!",
html: html,
});
The render function converts your React component tree into the final email HTML string with all styles inlined and the proper table structures generated.
Limitations and Caveats
React Email is a powerful tool, but it doesn't magically make email CSS work like web CSS. Keep these limitations in mind:
- Not all CSS properties are supported. Flexbox, Grid,
position, and many modern CSS features don't work in email clients. React Email's components abstract away some of this, but you still need to think in terms of email rendering constraints. - Test in real clients. The browser preview is a starting point, not the final word. Always test rendered output in Gmail, Outlook, and Apple Mail at minimum.
- Learning curve for email constraints. If your developers have never worked with email HTML, they'll still need to learn why certain patterns exist — why everything uses tables internally, why styles must be inlined, why
max-widthneeds MSO fallbacks. React Email makes the syntax nicer, but understanding email rendering is still essential. - Build step required. React Email templates need to be compiled before sending. This adds a build step to your deployment pipeline. For simple transactional emails, this is trivial. For complex marketing emails with many variants, plan your build process accordingly.
When to Use React Email
React Email is an excellent choice when your team already writes React, you want templates in version control alongside your application code, you value type safety and component reusability, and you're sending primarily transactional or programmatically generated emails. It's less suitable for marketing teams that need visual editors, or for teams that don't have React developers. For those teams, a traditional ESP with a drag-and-drop builder is still the better option.
James O'Brien
Email Engineer
Full-stack engineer focused on transactional email infrastructure. Maintainer of several open-source email testing tools.