Email templates live in src/lib/email/templates/ and are React components built with @react-email/components.
Existing Templates
| Template | Description |
|---|---|
BaseLayout.tsx | Shared layout wrapper (header, footer, brand name) |
WelcomeEmail.tsx | New user welcome email |
BillingEmail.tsx | Billing and subscription notifications |
ResetPasswordEmail.tsx | Password reset link |
InvitationEmail.tsx | Team invitation email |
BaseLayout
The BaseLayout component provides consistent structure across all emails:
- App name in the header (reads from
env.appNamevia@/lib/config, populated fromNEXT_PUBLIC_APP_NAME) - Centered container with max width of 600px
- Footer with copyright notice
- Preview text for email client snippets
All templates should wrap their content in <BaseLayout>.
Creating a New Template
1. Create the file
touch src/lib/email/templates/NotificationEmail.tsx
2. Define the component
import { Button, Heading, Section, Text } from '@react-email/components';
import { BaseLayout } from './BaseLayout';
interface NotificationEmailProps {
userName: string;
message: string;
actionUrl: string;
}
export function NotificationEmail({ userName, message, actionUrl }: NotificationEmailProps) {
return (
<BaseLayout preview={`New notification for ${userName}`}>
<Heading style={{ fontSize: '24px', fontWeight: '700', color: '#111' }}>
Hi {userName},
</Heading>
<Text style={{ fontSize: '16px', color: '#555', lineHeight: '1.6' }}>{message}</Text>
<Section style={{ textAlign: 'center', margin: '24px 0' }}>
<Button
style={{
backgroundColor: '#111',
borderRadius: '8px',
color: '#fff',
fontSize: '16px',
fontWeight: '600',
padding: '12px 24px',
}}
href={actionUrl}
>
View Details
</Button>
</Section>
</BaseLayout>
);
}
3. Send the email
import { render } from '@react-email/render';
import { enqueueEmail } from '@/lib/jobs';
import { NotificationEmail } from '@/lib/email/templates/NotificationEmail';
const html = await render(
<NotificationEmail
userName="Jane"
message="Your deployment is complete."
actionUrl="https://app.example.com/deployments/42"
/>,
);
await enqueueEmail('[email protected]', 'Deployment complete', html);
Styling Rules
Email clients do not support CSS classes or external stylesheets. Follow these rules:
- Use inline
React.CSSPropertiesobjects for all styling - Keep fonts to web-safe families (Arial, Helvetica, Georgia)
- Use table-based layouts for complex structures (the
@react-email/componentshandle this internally) - Test in multiple email clients — Gmail, Outlook, and Apple Mail render differently
Available Components
Import from @react-email/components:
| Component | Description |
|---|---|
Html | Root <html> element |
Head | <head> for meta tags |
Body | <body> with base styling |
Container | Centered max-width wrapper |
Section | <table> section for layout |
Row | Table row |
Column | Table column |
Text | <p> with email-safe defaults |
Heading | <h1>–<h6> |
Button | CTA button with link |
Link | <a> link |
Img | <img> with alt text |
Hr | Horizontal rule |
Preview | Hidden preview text for email clients |
For the full component API, see the React Email documentation.