Templates Quickstart
Build email templates as React components and push to AWS SES in minutes.
Build email templates as React components, preview them with hot-reload, and push to AWS SES — all from your codebase.
What you'll build
Time: ~5 minutes
Before you begin, make sure you have:
wraps email init (see the Email Quickstart)wraps auth login)Run the scaffold command from your project root to create the templates directory:
npx @wraps.dev/cli email templates initThis creates the following structure in your project:
wraps/├── wraps.config.ts # Project configuration├── templates/│ └── welcome.tsx # Example template├── brand.ts # Brand kit (colors, fonts, logo)└── _components/ # Shared componentsWhat gets scaffolded?
wraps.config.ts — project config (org, sender address, template directory)brand.ts — shared brand kit for colors, fonts, and logostemplates/welcome.tsx — a working example templateTemplates are React components built with React Email. Each file exports the component as default, plus metadata for the subject line, email type, and preview text. Here is the scaffolded example:
import { Body, Container, Head, Heading, Html, Preview, Section, Text,} from '@react-email/components';import { Footer } from './_components/footer';export const subject = 'Welcome to {{companyName}}, {{firstName}}!';export const emailType = 'transactional' as const;export const previewText = "We're glad to have you on board.";export const testData = { firstName: 'Jane', companyName: 'Acme', unsubscribeUrl: 'https://example.com/unsubscribe',};interface Props { firstName: string; companyName: string; unsubscribeUrl: string;}export default function WelcomeEmail({ firstName, companyName, unsubscribeUrl,}: Props) { return ( <Html> <Head /> <Preview>{previewText}</Preview> <Body style={{ backgroundColor: '#f6f9fc', fontFamily: 'system-ui, sans-serif' }}> <Container style={{ margin: '0 auto', padding: '40px 0', maxWidth: '580px' }}> <Section style={{ backgroundColor: '#fff', borderRadius: '8px', padding: '40px' }}> <Heading style={{ fontSize: '24px', color: '#1f2937' }}> Welcome, {firstName}! </Heading> <Text style={{ fontSize: '16px', color: '#4b5563', lineHeight: '1.6' }}> Thanks for signing up for {companyName}. We're excited to have you on board. </Text> </Section> <Footer unsubscribeUrl={unsubscribeUrl} /> </Container> </Body> </Html> );}Variable interpolation
Use {{variableName}} syntax in the subject export. These are replaced with values from templateData at send time.
Start the local preview server to see your templates rendered in the browser with hot-reload:
npx @wraps.dev/cli email templates preview# Opens http://localhost:3333 with hot-reloadThe preview server watches for file changes and reloads automatically. Test data from the testData export is used to populate the template in the preview UI.
Push your templates to both AWS SES and the Wraps dashboard. Only modified templates are pushed by default:
npx @wraps.dev/cli email templates pushUseful flags
--template welcome — push a single template--dry-run — see what would change without pushing--force — re-push all templates regardless of changesOnce pushed, send emails using the template name and pass dynamic data via the SDK:
import { WrapsEmail } from '@wraps.dev/email';const email = new WrapsEmail();// Sending via the SDK calls SES directly from your AWS account.// You provide the unsubscribe URL — it points at an endpoint you own.// See "Unsubscribe handling" below for the platform-managed alternative.await email.sendTemplate({ from: 'hello@yourdomain.com', to: 'user@example.com', template: 'welcome', templateData: { firstName: 'Alice', companyName: 'Acme', unsubscribeUrl: 'https://yourdomain.com/unsubscribe?token=abc123', },});Template data is merged at send time. Variable placeholders in the subject line (like {{firstName}}) are also replaced automatically.
Every variable accessed on the template's props (including unsubscribeUrl) is compiled into a {{unsubscribeUrl}} placeholder in the template pushed to SES. What fills that placeholder at send time depends on how you send:
@wraps.dev/email calls SES directly from your AWS account. Wraps is not in the path.
unsubscribeUrl in templateData— it points at an endpoint you own.email.suppression).List-Unsubscribe headers are added for you — add them with the headers option if you need RFC 8058 one-click unsubscribe.When the send goes through a Wraps broadcast or workflow step, Wraps handles unsubscribe end-to-end.
{{unsubscribeUrl}} at send time.export const emailType = 'marketing' as const; on the template. That flag also enables RFC 8058 List-Unsubscribe and List-Unsubscribe-Post headers for Gmail/Apple Mail one-click unsubscribe.{{preferencesUrl}} is available alongside {{unsubscribeUrl}} if you prefer a preferences page over a hard unsubscribe.The template file itself is the same for both paths. Mark marketing templates with the emailType flag and reference the placeholder:
export const emailType = 'marketing' as const;// In any marketing template, reference the Wraps-managed placeholder.// When sent via a broadcast or workflow, Wraps generates a signed,// per-recipient URL and substitutes it at send time.<Footer unsubscribeUrl={unsubscribeUrl} />// {{preferencesUrl}} is also auto-injected if you want a// "manage preferences" link instead of a hard unsubscribe.Configuration, brand kits, change detection, and advanced template patterns.
Full GuideAll available methods for sending emails and managing templates programmatically.
View SDK Docs