★ Community Edition ★Price: Free



The Mailing Room

A transactional receipt component in React Email, ready to send

A ready-to-ship React Email receipt component with a typed props interface that renders order line items and totals, and survives Gmail and Outlook.

An order receipt is the one email almost every commerce or SaaS stack has to send correctly, and the one most codebases hand-roll badly: an inline-styled table that looks fine in the browser preview and falls apart the moment Gmail strips a tag or Outlook renders it through Word. This is a working receipt component built on React Email's own components, ready to drop into a Next.js or React codebase and render straight to HTML.

The component

TSX
import {
  Body,
  Column,
  Container,
  Head,
  Hr,
  Html,
  Img,
  Link,
  Preview,
  Row,
  Section,
  Text,
} from "@react-email/components";

interface ReceiptItem {
  name: string;
  qty: number;
  unitPrice: number;
}

interface OrderReceiptProps {
  orderId: string;
  date: string;
  customerName: string;
  items: ReceiptItem[];
  subtotal: number;
  tax: number;
  total: number;
  currency: string;
  supportEmail: string;
  companyName: string;
  companyAddress: string;
  logoUrl?: string;
}

const money = (value: number, currency: string) =>
  new Intl.NumberFormat("en-GB", { style: "currency", currency }).format(value);

export function OrderReceipt({
  orderId,
  date,
  customerName,
  items,
  subtotal,
  tax,
  total,
  currency,
  supportEmail,
  companyName,
  companyAddress,
  logoUrl,
}: OrderReceiptProps) {
  return (
    <Html>
      <Head />
      <Preview>Your receipt for order {orderId}, total {money(total, currency)}</Preview>
      <Body style={styles.body}>
        <Container style={styles.container}>
          {logoUrl ? (
            <Img src={logoUrl} width="120" alt={companyName} style={styles.logo} />
          ) : (
            <Text style={styles.brand}>{companyName}</Text>
          )}

          <Text style={styles.heading}>Thanks for your order, {customerName}</Text>
          <Text style={styles.meta}>
            Order {orderId} placed on {date}
          </Text>

          <Section style={styles.itemsHeader}>
            <Row>
              <Column style={styles.thLeft}>Item</Column>
              <Column style={styles.thRight}>Qty</Column>
              <Column style={styles.thRight}>Unit</Column>
              <Column style={styles.thRight}>Total</Column>
            </Row>
          </Section>

          {items.map((item, idx) => (
            <Section key={idx} style={styles.itemRow}>
              <Row>
                <Column style={styles.tdLeft}>{item.name}</Column>
                <Column style={styles.tdRight}>{item.qty}</Column>
                <Column style={styles.tdRight}>{money(item.unitPrice, currency)}</Column>
                <Column style={styles.tdRight}>
                  {money(item.unitPrice * item.qty, currency)}
                </Column>
              </Row>
            </Section>
          ))}

          <Hr style={styles.hr} />

          <Section style={styles.totals}>
            <Row>
              <Column style={styles.tdLeft}>Subtotal</Column>
              <Column style={styles.tdRight}>{money(subtotal, currency)}</Column>
            </Row>
            <Row>
              <Column style={styles.tdLeft}>Tax</Column>
              <Column style={styles.tdRight}>{money(tax, currency)}</Column>
            </Row>
            <Row>
              <Column style={styles.tdLeftBold}>Total</Column>
              <Column style={styles.tdRightBold}>{money(total, currency)}</Column>
            </Row>
          </Section>

          <Hr style={styles.hr} />

          <Text style={styles.footer}>
            Questions about this order? Reply to this email or contact{" "}
            <Link href={`mailto:${supportEmail}`} style={styles.link}>
              {supportEmail}
            </Link>
            .
          </Text>
          <Text style={styles.footer}>
            {companyName}, {companyAddress}
          </Text>
        </Container>
      </Body>
    </Html>
  );
}

const styles = {
  body: { backgroundColor: "#f4f4f5", fontFamily: "Helvetica, Arial, sans-serif" },
  container: {
    backgroundColor: "#ffffff",
    margin: "0 auto",
    padding: "32px",
    maxWidth: "480px",
  },
  logo: { marginBottom: "16px" },
  brand: { fontSize: "16px", fontWeight: 700, marginBottom: "16px" },
  heading: { fontSize: "18px", fontWeight: 700, margin: "0 0 4px" },
  meta: { fontSize: "13px", color: "#71717a", margin: "0 0 24px" },
  itemsHeader: { borderBottom: "1px solid #e4e4e7", paddingBottom: "6px" },
  itemRow: { borderBottom: "1px solid #f4f4f5", padding: "6px 0" },
  thLeft: { fontSize: "11px", color: "#71717a", textAlign: "left" as const },
  thRight: { fontSize: "11px", color: "#71717a", textAlign: "right" as const },
  tdLeft: { fontSize: "13px", textAlign: "left" as const },
  tdRight: { fontSize: "13px", textAlign: "right" as const },
  tdLeftBold: { fontSize: "14px", fontWeight: 700, textAlign: "left" as const },
  tdRightBold: { fontSize: "14px", fontWeight: 700, textAlign: "right" as const },
  totals: { padding: "8px 0" },
  hr: { borderColor: "#e4e4e7", margin: "16px 0" },
  footer: { fontSize: "12px", color: "#71717a", margin: "0 0 4px" },
  link: { color: "#3f3f46", textDecoration: "underline" },
};

export default OrderReceipt;

How to install

Install the components package into an existing React or Next.js project (npm install @react-email/components), save the code above as emails/OrderReceipt.tsx, and render it to HTML with render() from @react-email/render at the point you actually send:

TSX
import { render } from "@react-email/render";
import { OrderReceipt } from "./emails/OrderReceipt";

const html = await render(<OrderReceipt {...orderProps} />);

Hand the resulting html string to your sender of choice. Resend accepts JSX directly and calls render() for you internally; any other SMTP or API provider takes the plain HTML string the same way.

How to read the output

Every visual style is set through the components' own style props rather than a linked or <style> block stylesheet, which is what makes this survive Gmail's tag stripping and Outlook's Word rendering engine: there is nothing external for either client to drop. The Preview line is the text shown in the inbox list before the email is opened, keep it short and specific, it is wasted real estate if it just repeats the subject.

A safety note

This is a pure presentational component: it renders whatever items and totals it is given and performs no calculation, validation or payment logic of its own, so the numbers must already be correct before they reach it. It pairs with the React Email pick on this shelf, which is the framework this component is built on; install that first if you have not already.

  • Transactional email
  • React Email
  • Template