@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: render to { html, text }, then pass those to emails.send.Install
Add the package alongside the Node SDK you'll send with. React is a peer dependency — react ^18 or ^19 (with react-dom) must already be in your project.
Author 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>
);
}EmailLayout— branded wrapper (logo header, content, footer with optional unsubscribe). Props:preview,logoUrl,brandName,footerText,unsubscribeUrl, andchildren.logoUrldefaults toSENDARA_LOGO_URLandbrandNameto"Sendara".BrandButton— amber CTA. Props:href(required),children(the label), andvariant("primary"default or"secondary").sendaraTheme— thecolors,fonts, andradiustokens behind the components, exported so you can match the palette in your own JSX.SENDARA_LOGO_URLis the hosted logo, andSendaraThemeis the token type.
Rendering
Three async functions turn an element into deliverable markup. Each takes the instantiated component (JSX) as its first argument and returns a Promise — await them.
render(element, options?)→Promise<string>— the bulletproof HTML.renderText(element)→Promise<string>— the plaintext part.renderEmail(element, options?)→Promise<{ html, text }>— both at once (aRenderedEmail).
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.
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.{ html, text } across a broadcast or batch send — rendering is pure, so you only pay for it once.