Skip to main content

Our email CSS engine is open source. Give it a star on GitHub 

Emailens
Blog

React Email Guide: Build JSX Emails That Hold Up in Outlook

Build with React Email's table-backed components such as Row, Column and Button rather than flexbox, then check the rendered HTML in real clients, because the dev preview runs in a browser, not in Outlook or Gmail.

The checker needs a computer screen.

A free account opens all 21 clients and keeps your checks for 7 days. Create a free account →

Philippe Kam, founder of Emailens · Published 4 Mar 2026 · Updated 28 Oct 2026

@emailens/engine 0.18.22 · data last changed 10 Nov 2026

Part of the HTML email guide · all guides

React Email lets you write emails with React components instead of hand-writing HTML tables. This guide covers setup, the components and the HTML they compile to, styling that survives email clients, rendering to an HTML string, and testing the result in real inboxes.

What React Email does

HTML email development still means <table> layouts, inline styles on every element, and testing 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.

Components like Row and Column compile to tables automatically, so you get flexbox-like ergonomics without the compatibility issues that come with actual flexbox. If you prefer markup over JSX, the MJML guide covers the main alternative.

Install React Email and run the preview server

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, the render() function compiles JSX to an HTML string (see below).

React Email components and the HTML they compile to

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 React Email template

Here's a welcome email using 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 React Email for Gmail and Outlook

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

  • Always use inline styles: Gmail keeps a <style> block only in the head and within a size limit, and its apps drop it for accounts that are not Google accounts
  • 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
  • Give the colour its own property: Outlook Classic drops a whole background shorthand it cannot parse, colour included, so set background-color on its own (Outlook fallbacks)

Using Tailwind through React Email's <Tailwind> component? Version 4 breaks breakpoints in Gmail; see fixing Tailwind v4 media queries in Gmail. For multi-column layouts that must hold in Outlook, see Outlook ghost tables.

Props, conditions and loops

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>
  );
}

Render React Email to HTML with render()

To send a template, call render() from @react-email/render on the component and hand the HTML string it returns to your email provider. The pretty option indents the output so you can read it. renderAsync() was the v2 API and is deprecated in React Email v3 and later.

Test React Email templates in real email 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. For the full pre-send routine, see how to test HTML emails.

Spacing gaps in Outlook or words running together after render? The React Email and jsx-email troubleshooting guide covers withMargin, renderWhitespace and pxToPt with exact fixes.

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.

How do I turn a React Email template into an HTML string?

Call render() from @react-email/render with your component, for example await render(<WelcomeEmail name="Ada" />), and send the HTML string it returns through your email provider. renderAsync() was the v2 API and is deprecated in React Email v3 and later.

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.

Your next question

Also useful: HTML email checker · Test React Email templates · Check Resend emails in 21 clients

Paste the email that broke.

The checker needs a computer screen.

Get new email CSS fixes by email, or follow by RSS.