Dynamic email templates
Reusable email templates with {{variables}} and conditional blocks. Build them in the visual builder or paste your own HTML, publish, and send by ID — copy changes never need a redeploy.
Merge variables and conditionals
Drop {{first_name}}, {{company}}, or any variable into the subject, HTML, or plain-text body. {{#if}} and {{#unless}} blocks show or hide content per recipient.
Visual builder or your own HTML
Compose from blocks (heading, paragraph, button, image, divider) in the dashboard, start from a preset, or paste HTML rendered by React Email, MJML, or your own build step.
Publish before it can send
Templates are drafts until you publish them, and the send API rejects an unpublished template — so a half-edited draft can never reach a customer.
Send with a template
await poststack.emails.send({
from: 'hello@yourdomain.com',
to: ['user@example.com'],
template_id: 'tpl_abc123def456ghi789',
variables: {
first_name: 'Alice',
company: 'Acme Inc',
login_url: 'https://app.acme.com/login',
},
});Use cases
Reusable transactional content
Welcome emails, password resets, receipts, and order confirmations all live as named templates. Edit copy or styling in the dashboard, re-publish, and every future send picks up the change — no redeploy required.
Designer / developer split
Whoever owns the copy edits the template in the dashboard with a live preview. Developers reference it by ID from application code. The two workflows stay independent.
Personalised without branching code
Pass a greeting name, plan name, or order total as variables and let {{#if}} blocks decide which paragraphs appear — for example, a line that only shows when a coupon code is present.
React Email and MJML teams
Keep authoring in React Email or MJML. Render to HTML in your build, store the output as a PostStack template, and send it by ID from any language or from an AI agent over MCP.
How it works
A PostStack template stores a subject, an HTML body, and an optional plain-text body. Placeholders use double-brace merge tags — `{{first_name}}` — and are filled from the `variables` object you pass on each send; values placed into the HTML body are HTML-escaped, and a variable you do not pass renders as an empty string. Flat conditional blocks are supported: `{{#if coupon}}…{{/if}}` renders its content only when the variable is set and non-empty, and `{{#unless}}` is the inverse. There are no loops or custom helpers, so pre-format lists (for example an order’s line items) into a variable before sending. A few merge tags are filled in by PostStack itself: `{{unsubscribe_url}}` and `{{preferences_url}}` resolve per recipient, and `{{signature}}` inserts the sending mailbox’s signature. Templates are created as drafts; publishing makes them available to the send API, and a send that names an unpublished template is rejected with a 422. Each content change bumps the template’s version number. In the dashboard you can write HTML directly or use the visual builder, which composes the email from typed blocks and stores the block tree alongside the compiled HTML so it round-trips without lossy re-parsing. Templates can be duplicated, started from built-in presets, and previewed with sample variables before you publish. PostStack does not run a React renderer server-side: if you use React Email, call its `render()` function in your build or at send time and store or pass the resulting HTML.
Full parameters, limits, and examples are in the Dynamic email templates documentation.
Frequently asked questions
Do you support React Email?
Yes, as HTML. Render your React Email component with `@react-email/render` and either save the output as a PostStack template or pass it directly as `html` on the send. PostStack does not render React components server-side, so the component itself never needs to run on our infrastructure.
Can non-developers edit templates?
Yes. The dashboard has a block-based visual builder with a live preview, so copy and layout can change without touching code. Developers reference the template by ID, so publishing a change does not require a deploy.
What template syntax is supported?
Double-brace merge tags (`{{variable}}`) plus flat `{{#if variable}}…{{/if}}` and `{{#unless variable}}…{{/unless}}` blocks. It is deliberately small: there are no loops, partials, or custom helpers, and conditionals cannot be nested. Anything more complex is best rendered in your own code and passed in as a variable or as full HTML.
Can I send the same template with different content?
Yes — pass `variables` on every send. The same template renders different output for each recipient, and variables are scoped to the individual send.
What happens if I send a template that is not published?
The API rejects the send with a 422 ("Template is not published"). Unpublishing a template is therefore also a quick way to stop a template from being sent while you fix it.