Skip to main content
Emailens
Blog
PK
·Founder, Emailens
Mar 4, 2026·10 min read

React Email: The Complete Guide to Building Emails in JSX

React Email lets you write emails with React components instead of fighting with raw HTML tables. Here's everything you need to know, from setup to production deployment.

Quick Answer: Building Production Emails with React

React Email brings modern React components and TypeScript to email authoring. Always use table-backed primitives (<Row> and <Column>) instead of Flexbox or CSS Grid. Rely on <Button> and <Container> for bulletproof centering, and test the compiled output in real client engines because the local React dev server runs on modern browser Chromium, not Word or Gmail's sanitizer.

Why React Email exists

HTML email development has been stuck in 2003. You write <table> layouts, inline every style, and test across a dozen clients that each interpret CSS differently. React Email replaces this with a component-based workflow: you write JSX, and it compiles to the table-based HTML that email clients expect.

The key insight is that React Email components like Row and Column compile to tables automatically, so you get flexbox-like ergonomics without the compatibility issues that come with actual flexbox.

Setup

Terminal
4 lines
npm install @react-email/components react-email

# or with bun
bun add @react-email/components react-email

React Email provides a dev server (email dev) for local preview. For production rendering, use the render() function to compile JSX to an HTML string.

Core components

React Email ships a small set of components that each compile to email-safe HTML. Here's what each one does:

Html

Root wrapper. Sets DOCTYPE and xmlns.

Head

Contains <meta> tags, <title>, and embedded styles.

Body

Wraps all visible content. Accepts style prop for background color.

Container

Centers content with a max-width. Compiles to a centered <table>.

Row / Column

Table-based grid. Use instead of flexbox or CSS grid.

Section

Groups content blocks. Renders as a <table> row.

Text

Paragraph element with email-safe defaults.

Img

Image with required width/height for Outlook. Always include alt text.

Link

Anchor tag with target="_blank" default.

Button

Call-to-action button using a padded <a> tag for maximum client support.

Hr

Horizontal rule using a <table> border trick for consistency.

A complete example

Here's a welcome email using all the core components. Note the inline styles. React Email supports style objects, not CSS classes:

welcome-email.tsx
44 lines
import {
  Html, Head, Body, Container,
  Row, Column, Text, Img, Button, Hr
} from '@react-email/components';

export default function WelcomeEmail({ name }: { name: string }) {
  return (
    <Html>
      <Head />
      <Body style={{ backgroundColor: '#f6f6f6', fontFamily: 'Arial, sans-serif' }}>
        <Container style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
          <Img
            src="https://example.com/logo.png"
            width="120"
            height="36"
            alt="Company Logo"
          />
          <Text style={{ fontSize: '24px', fontWeight: 'bold', marginTop: '24px' }}>
            Welcome, {name}!
          </Text>
          <Text style={{ color: '#666', lineHeight: '1.6' }}>
            We're glad you're here. Here's what you can do next:
          </Text>
          <Button
            href="https://example.com/dashboard"
            style={{
              backgroundColor: '#000',
              color: '#fff',
              padding: '12px 24px',
              borderRadius: '6px',
              textDecoration: 'none',
            }}
          >
            Go to Dashboard
          </Button>
          <Hr style={{ borderColor: '#eee', margin: '24px 0' }} />
          <Text style={{ fontSize: '12px', color: '#999' }}>
            You received this because you signed up at example.com
          </Text>
        </Container>
      </Body>
    </Html>
  );
}

Styling rules

Email clients have inconsistent CSS support. Follow these rules to avoid surprises:

  • Always use inline styles: Gmail strips <style> blocks entirely
  • No flexbox or grid: Outlook ignores both. Use Row/Column instead
  • Set explicit width/height on images: prevents layout shifts in Outlook
  • Use web-safe font stacks: custom fonts via @font-face are unsupported in many clients
  • Avoid shorthand properties: some clients parse margin: 10px 20px differently

Conditional rendering

Because React Email is just React, you get conditional rendering and loops for free. This is one of its biggest advantages over raw HTML templates:

Conditional content
32 lines
// Conditional content based on props
export default function NotificationEmail({
  type,
  items,
}: {
  type: 'welcome' | 'invoice';
  items?: { name: string; price: string }[];
}) {
  return (
    <Html>
      <Body>
        <Container>
          {type === 'welcome' && (
            <Text>Welcome to our platform!</Text>
          )}

          {type === 'invoice' && items && (
            <>
              <Text>Here's your invoice:</Text>
              {items.map((item, i) => (
                <Row key={i}>
                  <Column>{item.name}</Column>
                  <Column style={{ textAlign: 'right' }}>{item.price}</Column>
                </Row>
              ))}
            </>
          )}
        </Container>
      </Body>
    </Html>
  );
}

Testing across clients

The React Email dev server only shows how your email looks in a browser. It won't catch the CSS properties that Outlook silently drops, the styles Gmail strips, or the dark mode transforms Apple Mail applies.

Emailens can take your React Email JSX source directly. It compiles, transforms per-client, and flags every compatibility issue with fix snippets in React Email syntax.

Pro tip: If using Tailwind with React Email, read our breakdown on fixing Tailwind v4 media query bugs in Gmail, and learn how to handle Outlook ghost tables for complex nested grids. Hitting build errors or unexpected Outlook spacing? Our React Email & JSX Email debugging guide covers withMargin gaps, renderWhitespace crashes, and px-to-pt conversion bugs with exact fixes.

Frequently Asked Questions

Why use React Email instead of traditional HTML email templates?

React Email allows you to build templates using reusable component architecture, TypeScript type safety, props, and conditional logic. It then compiles clean, table-based HTML compatible with legacy clients like Outlook and Gmail.

Does React Email automatically inline CSS styles?

Yes. When you use the @react-email/render utility with inline styling or @react-email/tailwind, it inlines critical CSS directly onto HTML elements to ensure mobile email clients don't lose formatting.

Why do my React Email templates look different in Outlook?

Outlook for Windows renders emails with the Microsoft Word engine rather than a browser. Flexbox, CSS Grid, and certain CSS padding/margin properties are ignored. React Email uses table-based <Row> and <Column> primitives to mitigate this, but complex layouts still require ghost tables and VML.

How do I preview and test React Email templates locally?

You can run 'email dev' to view templates in the local React Email browser previewer. However, to test true rendering across 21+ real client engines (Gmail sanitizer, Outlook Word engine), you should test the rendered HTML in Emailens.

Test your React Email across 21 clients

Paste your JSX and get a compatibility report with React Email-specific fix snippets.

Preview your email

Free plan, 30 previews/day

Sources & Primary References:

Reviewed by Philippe KAM · Last updated: Mar 4, 2026

PK

Philippe KAM

Founder & Lead Engineer at Emailens

Building next-generation email preview and QA infrastructure for developers. Focused on reverse-engineering rendering engines across Outlook (Word MSO & New Outlook), Gmail, and Apple Mail to eliminate email rendering bugs before dispatch.