Build Email Templates
Templates are reusable email designs. Build one with the visual editor, then send it to any audience from a campaign — or one-to-one via the public API.
Cross-client compatibility: templates compile through react-email (the same library Resend ships) so the final HTML works across Gmail, Outlook, Apple Mail, Yahoo, and mobile clients without you hand-rolling table-based markup.
When to use a template
- Sending the same email shape repeatedly (order confirmations, OTP codes, password resets)
- Marketing campaigns where the design should be consistent across sends
- Anything you want non-developers on your team to update without redeploying
For one-off sends with bespoke HTML, the public API /email/send endpoint takes inline HTML directly — no template needed.
Open the editor
Email → Templates → New template.
A blank template opens with three default blocks (heading, text, footer) so you have something to edit immediately.
Editor layout
Three panes:
┌──────────────┬─────────────────────────────────┬──────────────┐
│ LEFT │ CENTER │ RIGHT │
│ │ │ │
│ Block │ Live HTML preview │ Selected │
│ palette + │ (debounced 600ms after │ block's │
│ ordered │ every edit, rendered through │ properties │
│ block list │ the email-renderer sidecar) │ │
│ │ │ │
└──────────────┴─────────────────────────────────┴──────────────┘Top bar: template name + Save button + mobile/desktop preview toggle.
Subject line: shown above the editor in its own input. Subject is a property of the template, not a block.
Available blocks
| Block | What it does |
|---|---|
| Heading | H1 / H2 / H3 with bold styling. Use for section titles |
| Text | Paragraph — plain prose. Supports {{variable}} substitution |
| Image | Image with src, alt text, and width. Use absolute HTTPS URLs |
| Button | CTA button with custom background colour. Set href + text |
| Divider | Horizontal rule between sections |
| Spacer | Blank vertical space — set height in pixels |
| Footer | Auto-injects company name, address, and unsubscribe link. Required for compliance |
Click a block in the palette to add it to the bottom of your layout. Click any block in the layout list to select it; its properties appear in the right pane. Use the up/down chevrons to reorder.
Variables
Use {{variable_name}} syntax anywhere in your subject, headings, or text.
Variables are substituted per recipient at send-time. For campaigns, the values come from contact attributes (e.g., {{first_name}} resolves to each contact’s first name). For public API sends, the values come from the variables object in your request payload.
Reserved variables
These are always available — no need to set them:
| Variable | Value |
|---|---|
{{recipient_email}} | The recipient’s email address |
{{unsubscribe_url}} | Auto-injected by the Footer block |
Unknown variables
Render as empty strings rather than failing the send. This makes optional fields safe — {{coupon_code}} shows nothing for recipients without a coupon.
Live preview
The preview pane re-renders 600ms after your last edit (debounced). It calls the email-renderer sidecar through our backend, so what you see is the actual cross-client HTML that gets shipped to recipients.
Mobile preview: click the mobile/desktop icon in the top bar to toggle. The preview pane resizes to 375px (mobile) or full-width (desktop) so you can confirm responsive behaviour.
Save + test send
Click Save to persist your template. The save also pre-compiles the final HTML so per-recipient sends don’t have to re-render — they just substitute variables into the snapshot.
Save before sending: variable substitution + sending uses the last saved version of the template. If you change a template but don’t save, the change won’t appear in sends. Click Save before testing.
To test a saved template, the easiest path is:
- Send a one-off campaign to a single contact (yourself)
- Or via API:
POST /api/v1/public/email/send-templatewithtemplate_id+ your email
Compliance: the Footer block
Every email must include sender identification + an unsubscribe mechanism. The Footer block handles this automatically — it renders:
{{sender_company_name}}
{{sender_address}}
UnsubscribeSet the company name + mailing address in the Footer block’s properties. The unsubscribe link is auto-generated per recipient by the email-sender at send-time (HMAC-signed token).
Don’t delete the Footer block. Sending without it means your emails will fail Gmail / Yahoo’s policy checks and likely land in spam. CAN-SPAM (US), GDPR (EU), and DPDP (India) all require sender identification + a working unsubscribe path.
Editing an existing template
Click any template card in Email → Templates to reopen the editor.
Already used in a campaign? Editing a template doesn’t change emails that have already been sent. It only affects FUTURE sends from this template. So you can safely tweak a template after a campaign launches without breaking the ones that already went out.
If you want a totally different design without losing the original, duplicate: click the template, change the name, then re-save → currently this requires copy-paste of the JSON; full duplicate-as-action button lands in a future sprint.
Deleting a template
Trash icon on the template card → confirm. Past sends keep their already-rendered HTML; future campaigns can no longer reference this template.
Best practices
- Width: 600px for the body container is the email industry standard — most clients render this cleanly without scrollbars
- Images: host them on a public CDN (DigitalOcean Spaces, Cloudflare R2, S3). Don’t link to your private app URLs — many email clients block authenticated image fetches
- Alt text: always set
alton images. ~50% of inbox previews block images by default; alt text is what shows - Buttons: use one primary CTA per email. Multiple CTAs hurt click-through rate
- Plain text fallback: don’t worry about it — we auto-generate a plaintext version from your blocks. Recipients on text-only mail clients see a clean version
- Test on mobile: ~70% of marketing email opens are on mobile. Toggle to mobile preview before saving
Limits
- Max 200 templates per account — this is generous; reach out if you need more
- No custom CSS in this version — block properties cover ~95% of typical email styling. Sprint 6+ may add an “advanced HTML” block for power users
- No drag-drop — reorder via the up/down arrows in the block list. Drag-drop adds 30 KB+ of JS for marginal UX gain