
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.
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.
mkdir my-email-project
cd my-email-project
npm init -y
npm install react-email @react-email/components
npx email initThe 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.
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:
npm install nodemailerThen, create a simple script (e.g., send-email.ts):
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.

When Your UI Needs to Break the Flat Screen: React and 3D with React Three Fiber
We've been building UIs on flat screens for decades. But what happens when you need something more? When data visualization demands depth, or an interactive product showcase needs a real sense of presence? React Three Fiber is the tool that lets you bring the full power of Three.js into your React a

When Your State Management Needs to Stop Thinking in Actions and Start Mutating
Many state management libraries force you into an 'actions and reducers' pattern. While powerful, it often adds unnecessary boilerplate for simple updates. Sometimes, you just need to directly modify state, and mutators offer a more ergonomic and intuitive approach, especially for deeply nested data

When Next.js Cache Components Refuse to Build Your App
Next.js 16.3 introduced 'Cache Components' to optimize server-side rendering, but getting them to work can be a headache. I spent a frustrating afternoon debugging why a simple page wouldn't build, only to uncover some subtle yet critical design considerations. It turns out, this feature forces you


















