Back to Blog
When Your Emails Need to Be as Good as Your UI: React Email
7 min readAug 24, 20260 views

When Your Emails Need to Be as Good as Your UI: React Email

Sending emails from your application often means dealing with HTML tables, inline styles, and inconsistent rendering across clients. It's a UX nightmare. React Email brings the component model and developer experience of React to building robust, beautiful emails.

FrontendWeb DevelopmentUIToolingReact
Share

by Sunil Band

Emails Are the Wild West of UI

We spend countless hours perfecting our web UIs: responsive layouts, custom component libraries, state management, accessibility. We use frameworks and tools that abstract away browser inconsistencies and give us a predictable development experience. Then, when it comes time to send an email – say, a welcome message, an invoice, or a password reset link – we throw all that out the window.

Suddenly, we're back to the dark ages of web development. Inline styles, <table> layouts, bgcolor attributes, and conditional comments for Outlook. Email clients are notorious for their inconsistent rendering engines and their strict, often ancient, adherence to HTML and CSS standards. It's a brutal experience, and it's why most developers either punt to a service like Mailchimp or build the bare minimum.

But emails are a critical part of your user's experience. They're often the first touchpoint, or a crucial piece of communication that needs to look as professional and well-crafted as your application itself. Copy-pasting ugly HTML templates or painstakingly writing inline CSS is not only soul-crushing but also prone to errors and difficult to maintain. This is where React Email changes the game.

The React Way to Email

React Email brings the familiar, declarative component model of React to email development. Instead of wrestling with raw HTML strings and inline styles, you write React components. This means you get all the benefits of component-based development: reusability, maintainability, and a much more pleasant developer experience. It compiles your React components into a robust, client-compatible HTML email, handling all the nasty bits like inline styles and table structures for you.

It's not just a wrapper around HTML. React Email provides a set of pre-built components that are specifically designed for email clients. Think of them as a highly opinionated, but incredibly effective, design system for emails. They abstract away the complexities of making sure your button renders correctly in Gmail and Outlook, or that your image doesn't get blocked by aggressive spam filters.

Setting Up Your Email Development Environment

Let's get a basic setup going. You'll need Node.js. Initialize a new project and install React Email. Their CLI is pretty handy for getting started.

bash
mkdir my-email-project
cd my-email-project
npm init -y
npm install react-email @react-email/components
npx email init

The npx email init command sets up a few things for you: an emails directory, a package.json script to run the dev server, and a basic example email. This dev server is fantastic; it provides a local preview of your emails, complete with hot reloading. It's like Storybook, but for your emails.

Now, let's open emails/MyEmail.tsx or create a new file, say emails/WelcomeEmail.tsx.

typescript
import {
  Body,
  Button,
  Container,
  Head,
  Html,
  Img,
  Link,
  Preview,
  Section,
  Text,
} from '@react-email/components';
import * as React from 'react';

interface WelcomeEmailProps {
  userName?: string;
  loginLink: string;
}

// Inline styles are generally preferred for emails, but React Email handles inlining from objects or Tailwind classes
const main = {
  backgroundColor: '#ffffff',
  fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif'
};

const container = {
  margin: '0 auto',
  padding: '20px 0 48px',
  width: '580px',
};

const h1 = {
  color: '#333',
  fontSize: '24px',
  fontWeight: 'bold',
  textAlign: 'center' as const,
  margin: '30px 0',
};

const paragraph = {
  color: '#555',
  fontSize: '16px',
  lineHeight: '24px',
  textAlign: 'left' as const,
};

const button = {
  backgroundColor: '#007bff',
  borderRadius: '5px',
  color: '#fff',
  fontSize: '16px',
  fontWeight: 'bold',
  textDecoration: 'none',
  textAlign: 'center' as const,
  display: 'block',
  width: '100%',
  padding: '10px 0'
};

export const WelcomeEmail = ({ userName = 'Valued Customer', loginLink }: WelcomeEmailProps) => (
  <Html>
    <Head />
    <Preview>Welcome to my service, {userName}!</Preview>
    <Body style={main}>
      <Container style={container}>
        <Section style={{ textAlign: 'center' }}>
          {/* A simple logo, imagine this pulled from your CDN */}
          <Img
            src="https://react.email/static/logo-on-dark.png" 
            width="170"
            height="50"
            alt="My Service Logo"
            style={{ margin: '0 auto' }}
          />
        </Section>
        <Section>
          <Text style={h1}>
            Hello {userName},
          </Text>
          <Text style={paragraph}>
            Thank you for signing up for my service! We're excited to have you on board.
          </Text>
          <Text style={paragraph}>
            To get started, please log in to your account:
          </Text>
          <Button style={button} href={loginLink}>
            Log in to your account
          </Button>
          <Text style={paragraph}>
            If you have any questions, feel free to reply to this email.
          </Text>
          <Text style={paragraph}>
            Best regards,
            <br />
            The Team
          </Text>
        </Section>
        <Section style={{ textAlign: 'center', marginTop: '40px' }}>
          <Text style={{ ...paragraph, fontSize: '12px', color: '#999' }}>
            You received this email because you signed up for our service.
          </Text>
          <Link
            href="https://example.com/unsubscribe"
            style={{ ...paragraph, fontSize: '12px', color: '#007bff', textDecoration: 'underline' }}
          >
            Unsubscribe
          </Link>
        </Section>
      </Container>
    </Body>
  </Html>
);

export default WelcomeEmail;

Notice how we're using components like Html, Head, Body, Container, Section, Text, Button, Img, and Link from @react-email/components. These are not just generic HTML elements; they are specifically designed and tested to render reliably across a wide range of email clients. For example, the Button component doesn't just render a simple <button> tag, which is often poorly supported in emails. Instead, it renders a more complex table-based structure with inline styles to ensure consistent appearance and clickability.

You can pass props to your email components just like any other React component, making them highly reusable and dynamic. In this example, userName and loginLink are props that would be populated when you send the email.

To see this in action, run npm run email dev in your project. It will open a browser window showing a list of your email components, and clicking on WelcomeEmail will display a live preview. This is invaluable for rapid iteration.

Sending Your React Email

Once you're happy with how your email looks, you need to render it to HTML and then send it. React Email provides the render function for this.

First, you'll need an email sending service or library. For this example, I'll use Nodemailer, which is a popular choice for Node.js applications. Install it:

bash
npm install nodemailer

Then, create a simple script (e.g., send-email.ts):

typescript
import * as React from 'react';
import { render } from '@react-email/render';
import nodemailer from 'nodemailer';
import { WelcomeEmail } from './emails/WelcomeEmail'; // Adjust path as needed

const sendWelcomeEmail = async () => {
  // 1. Render the React component to an HTML string
  const html = render(<WelcomeEmail userName="Sunil Band" loginLink="https://sunilband.com/login" />); 
  const text = render(<WelcomeEmail userName="Sunil Band" loginLink="https://sunilband.com/login" />, {
    plainText: true, // Also generate a plain text version for better deliverability
  });

  // 2. Set up your Nodemailer transporter
  // This example uses Mailtrap for testing, replace with your actual SMTP details
  const transporter = nodemailer.createTransport({
    host: 'smtp.mailtrap.io',
    port: 2525,
    auth: {
      user: 'YOUR_MAILTRAP_USER',
      pass: 'YOUR_MAILTRAP_PASSWORD',
    },
  });

  // 3. Send the email
  try {
    await transporter.sendMail({
      from: '"My Service" <no-reply@example.com>',
      to: 'recipient@example.com',
      subject: 'Welcome to My Service!',
      html: html,
      text: text,
    });
    console.log('Welcome email sent successfully!');
  } catch (error) {
    console.error('Failed to send email:', error);
  }
};

sendWelcomeEmail();

Replace 'YOUR_MAILTRAP_USER' and 'YOUR_MAILTRAP_PASSWORD' with your actual SMTP credentials (e.g., from Mailtrap for testing, or SendGrid, Postmark, etc., for production). This script renders the WelcomeEmail component into both HTML and plain text, then uses Nodemailer to send it. Generating both HTML and plain text versions is crucial for email deliverability and accessibility.

Trade-offs and Considerations

While React Email is a significant leap forward, it's not a silver bullet. The primary trade-off is that you're operating within the constraints of email clients. You can't use arbitrary CSS, JavaScript, or modern HTML features. React Email's components are designed to abstract this away, but it means you're limited to their provided components and the styles they support.

This isn't a limitation of React Email itself, but of the email ecosystem. It does mean that if you have highly custom, bleeding-edge designs, you might still run into some friction. However, for 99% of transactional and marketing emails, React Email's component library covers all the necessary bases and ensures consistent rendering.

Another point is the build process. When you run render, React Email effectively transforms your JSX into a static HTML string. This is a server-side operation, meaning you can't have dynamic client-side interactivity within the email itself (which email clients don't support anyway).

Finally, while the @react-email/components library is excellent, you might find yourself needing to create custom components if your design system is unique. This is straightforward React development, but it means you'll need to be mindful of email client compatibility, just like the library itself is.

Wrapping up

React Email is a game-changer for anyone who has ever dreaded building an email template. It brings the best practices and developer experience of modern web development to a notoriously difficult domain. By letting you use React components, it drastically improves maintainability, reduces errors, and allows you to create emails that are truly an extension of your application's UI quality.

If you're tired of fighting with inline styles and testing across a dozen email clients, give React Email a try. Start by cloning their example repository or running npx email init in a new project. Experiment with the provided components and see how quickly you can build a professional-looking email. Then, integrate it with your existing email sending service. You'll wonder how you ever lived without it.

More from the blog
Available for projectsReady to make something fun 🎈

Ready to build the next system?Wanna build something awesome together?

Currently accepting high-impact opportunities in frontend engineering and scalable web applications.Got a cool idea rattling around? Let's grab a virtual coffee and turn it into something people love. ☕