React Email lets you build email templates with React components. No more fighting with HTML tables.
Step 1: Install Dependencies
pnpm add @react-email/components resend
Step 2: Welcome Email Template
// emails/WelcomeEmail.tsx
import {
Html,
Head,
Body,
Container,
Section,
Text,
Button,
Hr,
Img,
Preview,
} from "@react-email/components";
interface WelcomeEmailProps {
name: string;
loginUrl: string;
}
export default function WelcomeEmail({ name, loginUrl }: WelcomeEmailProps) {
return (
<Html>
<Head />
<Preview>Welcome to RCB Software, {name}!</Preview>
<Body style={main}>
<Container style={container}>
<Img
src="https://rcbsoftware.com/logos/logo.png"
width={120}
height={40}
alt="RCB Software"
/>
<Section style={{ marginTop: "32px" }}>
<Text style={heading}>Welcome, {name}!</Text>
<Text style={paragraph}>
Thanks for signing up. We are excited to have you on board.
Here is what you can do next:
</Text>
<Text style={paragraph}>
1. Complete your profile{"\n"}
2. Explore our features{"\n"}
3. Connect your first integration
</Text>
<Button style={button} href={loginUrl}>
Get Started
</Button>
</Section>
<Hr style={hr} />
<Text style={footer}>
RCB Software - Building better web experiences
</Text>
</Container>
</Body>
</Html>
);
}
const main = {
backgroundColor: "#f6f9fc",
fontFamily:
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
};
const container = {
backgroundColor: "#ffffff",
margin: "0 auto",
padding: "40px 20px",
maxWidth: "560px",
borderRadius: "8px",
};
const heading = {
fontSize: "24px",
fontWeight: "bold" as const,
color: "#1a1a1a",
marginBottom: "16px",
};
const paragraph = {
fontSize: "14px",
lineHeight: "24px",
color: "#4a4a4a",
};
const button = {
backgroundColor: "#2563eb",
borderRadius: "8px",
color: "#ffffff",
fontSize: "14px",
fontWeight: "600" as const,
textDecoration: "none",
textAlign: "center" as const,
padding: "12px 24px",
display: "inline-block",
marginTop: "16px",
};
const hr = {
borderColor: "#e5e7eb",
margin: "32px 0",
};
const footer = {
fontSize: "12px",
color: "#9ca3af",
textAlign: "center" as const,
};
Step 3: Order Confirmation Email
// emails/OrderConfirmation.tsx
import {
Html,
Head,
Body,
Container,
Section,
Text,
Row,
Column,
Hr,
Preview,
} from "@react-email/components";
interface OrderItem {
name: string;
quantity: number;
price: number;
}
interface OrderConfirmationProps {
customerName: string;
orderNumber: string;
items: OrderItem[];
total: number;
}
export default function OrderConfirmation({
customerName,
orderNumber,
items,
total,
}: OrderConfirmationProps) {
return (
<Html>
<Head />
<Preview>Order #{orderNumber} confirmed</Preview>
<Body style={main}>
<Container style={container}>
<Text style={heading}>Order Confirmed</Text>
<Text style={paragraph}>
Hi {customerName}, your order #{orderNumber} has been confirmed.
</Text>
<Section style={tableContainer}>
{items.map((item, i) => (
<Row key={i} style={tableRow}>
<Column style={{ width: "60%" }}>
<Text style={itemName}>{item.name}</Text>
<Text style={itemQty}>Qty: {item.quantity}</Text>
</Column>
<Column style={{ width: "40%", textAlign: "right" }}>
<Text style={itemPrice}>
${(item.price * item.quantity).toFixed(2)}
</Text>
</Column>
</Row>
))}
</Section>
<Hr style={hr} />
<Row>
<Column>
<Text style={totalLabel}>Total</Text>
</Column>
<Column style={{ textAlign: "right" }}>
<Text style={totalAmount}>${total.toFixed(2)}</Text>
</Column>
</Row>
</Container>
</Body>
</Html>
);
}
const main = {
backgroundColor: "#f6f9fc",
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
};
const container = {
backgroundColor: "#ffffff",
margin: "0 auto",
padding: "40px 20px",
maxWidth: "560px",
borderRadius: "8px",
};
const heading = { fontSize: "24px", fontWeight: "bold" as const, color: "#1a1a1a" };
const paragraph = { fontSize: "14px", color: "#4a4a4a", lineHeight: "24px" };
const tableContainer = { marginTop: "24px" };
const tableRow = { borderBottom: "1px solid #e5e7eb", padding: "12px 0" };
const itemName = { fontSize: "14px", fontWeight: "600" as const, margin: "0" };
const itemQty = { fontSize: "12px", color: "#9ca3af", margin: "0" };
const itemPrice = { fontSize: "14px", fontWeight: "600" as const, margin: "0" };
const hr = { borderColor: "#e5e7eb", margin: "16px 0" };
const totalLabel = { fontSize: "16px", fontWeight: "bold" as const };
const totalAmount = { fontSize: "16px", fontWeight: "bold" as const };
Step 4: Send Emails with Resend
// lib/email.ts
import { Resend } from "resend";
import WelcomeEmail from "@/emails/WelcomeEmail";
import OrderConfirmation from "@/emails/OrderConfirmation";
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendWelcomeEmail(email: string, name: string) {
await resend.emails.send({
from: "RCB Software <hello@rcbsoftware.com>",
to: email,
subject: `Welcome to RCB Software, ${name}!`,
react: WelcomeEmail({
name,
loginUrl: "https://rcbsoftware.com/dashboard",
}),
});
}
export async function sendOrderConfirmation(
email: string,
order: {
customerName: string;
orderNumber: string;
items: { name: string; quantity: number; price: number }[];
total: number;
}
) {
await resend.emails.send({
from: "RCB Software <orders@rcbsoftware.com>",
to: email,
subject: `Order #${order.orderNumber} Confirmed`,
react: OrderConfirmation(order),
});
}
Step 5: Password Reset Email
// emails/PasswordReset.tsx
import {
Html,
Head,
Body,
Container,
Text,
Button,
Preview,
Section,
} from "@react-email/components";
export default function PasswordReset({
name,
resetUrl,
}: {
name: string;
resetUrl: string;
}) {
return (
<Html>
<Head />
<Preview>Reset your password</Preview>
<Body style={main}>
<Container style={container}>
<Text style={heading}>Reset Your Password</Text>
<Text style={paragraph}>
Hi {name}, we received a request to reset your password.
Click the button below to create a new one.
</Text>
<Section style={{ textAlign: "center", marginTop: "24px" }}>
<Button style={button} href={resetUrl}>
Reset Password
</Button>
</Section>
<Text style={{ ...paragraph, marginTop: "24px", fontSize: "12px", color: "#9ca3af" }}>
This link expires in 1 hour. If you did not request this,
you can safely ignore this email.
</Text>
</Container>
</Body>
</Html>
);
}
const main = { backgroundColor: "#f6f9fc", fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' };
const container = { backgroundColor: "#ffffff", margin: "0 auto", padding: "40px 20px", maxWidth: "560px", borderRadius: "8px" };
const heading = { fontSize: "24px", fontWeight: "bold" as const, color: "#1a1a1a" };
const paragraph = { fontSize: "14px", lineHeight: "24px", color: "#4a4a4a" };
const button = { backgroundColor: "#2563eb", borderRadius: "8px", color: "#ffffff", fontSize: "14px", fontWeight: "600" as const, padding: "12px 24px", textDecoration: "none" };
Step 6: Preview Emails in Development
pnpm add -D react-email
Add to package.json scripts:
{
"scripts": {
"email:dev": "email dev --dir emails"
}
}
pnpm email:dev
This opens a browser UI where you can preview and test all your email templates.
Need Custom Email Systems?
We build transactional email systems, automated sequences, and branded templates that drive engagement. Contact us to get started.