#Alepha - React Email
#Installation
Part of the alepha package. Import from alepha/react/email.
npm install alepha
#Overview
Write notification and transactional emails as React components.
render() turns a component into the (variables) => Promise<string> that
$notification's body and $email.send() both already accept, so a
template becomes a component and nothing else in the stack changes.
1const WelcomeEmail = (props: { name: string }) => ( 2 <html lang="en"> 3 <body> 4 <h1>Welcome, {props.name}</h1> 5 </body> 6 </html> 7); 8 9class Templates {10 welcome = $notification({11 schema: z.object({ name: z.text() }),12 email: { subject: "Welcome", body: render(WelcomeEmail) },13 });14}
Components come from elsewhere. This module renders; it ships no
components of its own. @react-email/components is the recommended
companion (Outlook-safe tables, <Tailwind>, <Button> with VML
fallbacks) and renders through this unchanged. Install it in the app, not
in the framework.
⚠️ @react-email/render is deliberately NOT used. Measured on
2026-08-27, bundled for workerd: 976 KB raw / 301 KB gzip, and importing
only render changes nothing, because prettier/standalone and
prettier/plugins/html are static top-level imports that do not
tree-shake. That is +134 KB gzip over react-dom/server.edge for a
formatter no production send calls.
A template gets props, not the container. No useI18n() or
useInject() inside an email component: everything arrives as props. The
renderer runs inside a job with no request context, and driving a
recipient's language into the i18n store for the duration of a render is
the shape of bug the notification layer already warns about. Templates
keep using $notification's own translations map.
Plain text is not this module's job. render() returns HTML; the
notification sender derives the text part with EmailTextRenderer from
alepha/email, or uses the text the template declared.