@sendaramail/react-email lets you write emails the same way you write your app: as React components. It is a thin layer over @react-email/components with three additions: a curated set of re-exported building blocks, an async render family that returns both HTML and plaintext, and a few Sendara-branded components and ready-made templates. The output is inline-styled, table-based markup that survives Outlook, Gmail, and Apple Mail, so you keep JSX ergonomics without hand-tuning for every client.
sendara Node SDK to render { html, text }, then pass those values to emails.send.Install
Add the package beside the Node SDK that you send with. React is a peer dependency. Your project needs react ^18 or ^19.
npm install @sendaramail/react-email
# also install the Node SDK to send: npm install sendaraAuthor an email in JSX
An email is just a component that returns JSX. The curated re-exports cover every primitive you need: Html, Head, Body, Container, Section, Row, Column, Text, Heading, Button, Img, Hr, Link, Preview, plus Font and Tailwind. Style with inline style objects. They get inlined into bulletproof markup at render time.
import {
Html,
Head,
Body,
Container,
Section,
Heading,
Text,
Button,
Hr,
} from "@sendaramail/react-email";
export function Welcome({ name, url }: { name: string; url: string }) {
return (
<Html lang="en">
<Head />
<Body style={{ backgroundColor: "#fdfcfa", fontFamily: "sans-serif" }}>
<Container style={{ maxWidth: 560, margin: "0 auto", padding: 32 }}>
<Section>
<Heading style={{ fontSize: 22 }}>Welcome, {name} π</Heading>
<Text>Thanks for signing up. Confirm your address to get going.</Text>
<Button
href={url}
style={{
backgroundColor: "#d97706",
borderRadius: 10,
color: "#fff",
padding: "12px 24px",
}}
>
Confirm email
</Button>
</Section>
<Hr style={{ borderColor: "#e8e3da", margin: "24px 0" }} />
<Text style={{ color: "#6b6457", fontSize: 12 }}>Sent with Sendara.</Text>
</Container>
</Body>
</Html>
);
}@sendaramail/react-email instead.Sendara-branded building blocks
Skip the boilerplate with the ink/amber-themed components. Wrap your content in EmailLayout for a logo header, padded content area, and footer. Use BrandButton for the CTA. The same email as above, branded:
import {
EmailLayout,
BrandButton,
Heading,
Text,
} from "@sendaramail/react-email";
export function Welcome({ name, url }: { name: string; url: string }) {
return (
<EmailLayout preview={`Welcome aboard, ${name}`} unsubscribeUrl="https://acme.com/unsub">
<Heading>Welcome, {name} π</Heading>
<Text>Thanks for signing up. Confirm your address to get started.</Text>
<BrandButton href={url}>Confirm email</BrandButton>
</EmailLayout>
);
}EmailLayoutis a branded wrapper with a logo header, content area, and footer with an optional unsubscribe link. Props:preview,logoUrl,brandName,footerText,unsubscribeUrl, andchildren.logoUrldefaults toSENDARA_LOGO_URLandbrandNameto"Sendara".BrandButtonrenders an amber CTA. Props:href(required),children(the label), andvariant("primary"default or"secondary").sendaraThemeexposes thecolors,fonts, andradiustokens behind the components so you can match the palette in your own JSX.SENDARA_LOGO_URLis the hosted logo, andSendaraThemeis the token type.
Render a component to HTML
Three async functions turn an element into deliverable markup. Each takes the instantiated component (JSX) as its first argument and returns a Promise, so await them.
render(element, options?)βPromise<string>with the bulletproof HTML.renderText(element)βPromise<string>with the plaintext part.renderEmail(element, options?)βPromise<{ html, text }>with both parts at once (aRenderedEmail).
import { renderEmail } from "@sendaramail/react-email";
import { Welcome } from "./emails/Welcome";
// Both parts in one call. Best deliverability.
const { html, text } = await renderEmail(
<Welcome name="Ada" url="https://acme.com/verify?token=abc" />,
);renderEmail in almost every case. A multipart message with both an html and a text part lands better and renders in text-only clients. RenderOptions and RenderedEmail are exported types if you need them.Ready-made templates
Two common transactional emails ship pre-built and branded. Render them like any component. Pass props, get markup.
import { renderEmail, VerificationEmail } from "@sendaramail/react-email";
const { html, text } = await renderEmail(
<VerificationEmail
userName="Ada"
verificationUrl="https://app.acme.com/verify?token=β¦"
code="481920"
expiresInMinutes={15}
brandName="Acme"
/>,
);VerificationEmail
Email confirmation with a verify button and an optional one-time code.
ReceiptEmail
An itemized purchase receipt. ReceiptLineItem is exported for typing your items array.
End-to-end: author β render β send
The full flow ties the two packages together. Author the JSX, render to { html, text } with renderEmail, then hand both parts to the Node SDK's emails.send({ from, to, subject, html, text }).
import { Sendara } from "sendara";
import { renderEmail } from "@sendaramail/react-email";
import { Welcome } from "./emails/Welcome";
const sendara = new Sendara(process.env.SENDARA_API_KEY!);
// 1. Author JSX β 2. render to { html, text }.
const { html, text } = await renderEmail(
<Welcome name="Ada" url="https://acme.com/verify?token=abc" />,
);
// 3. Hand both parts to the Node SDK's emails.send.
const { id } = await sendara.emails.send({
from: "[email protected]", // must be on a verified domain
to: "[email protected]",
subject: "Welcome to Acme",
html,
text,
});
console.log(id); // msg_a1b2c3from address must be on a verified domain. Sends are idempotent. The SDK attaches a generated idempotency_key so retries never double-send. See the Send email guide for the rest of emails.send.