Skip to main content
Back to Blog
Tutorials
3 min read
November 8, 2024

How to Build Email Templates with React Email

Create beautiful transactional email templates with React Email. Welcome emails, receipts, notifications, and sending with Resend.

Ryel Banfield

Founder & Lead Developer

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.

emailReact Emailtransactional emailResendtutorial

Ready to Start Your Project?

RCB Software builds world-class websites and applications for businesses worldwide.

Get in Touch

Related Articles