# Postmark server-side templates vs React Email rendered in your app

> Postmark can store templates and fill them with Mustachio. Rendering React Email in your app keeps templates in the repo, typed and reviewed. How to choose, and what each costs.

Postmark has a real template system. You design a template in the dashboard, call `sendEmailWithTemplate` with an alias and a model, and Postmark fills it in. It also ships good starter templates.

The other option: write templates as React Email components, render them to HTML and text in your app, and send the result with `sendEmail`.

Both work. They put the template in different places, and that decides who can change it and how.

## Postmark templates

```ts
await client.sendEmailWithTemplate({
  From: from,
  To: to,
  TemplateAlias: "receipt",
  TemplateModel: { reference, total, lines },
  MessageStream: "outbound",
});
```

Pros:

- Non-developers can edit copy without a deploy.
- Layouts are shared across templates.
- Postmark can validate and preview with test data.

Costs:

- **The template is not in your repo.** No diff, no review, no history next to the code that fills it.
- **The model is untyped.** Rename `total` to `amount` in code and the template renders an empty cell. Nothing fails.
- **Environments drift.** Staging and production servers each hold their own copy. Someone fixes a typo in one.
- **Logic lives in Mustachio.** Loops and conditionals are fine. Currency formatting by locale is not.

## React Email in the app

```tsx
await sendEmail({
  to,
  subject: `Receipt ${reference}`,
  react: ReceiptEmail({ reference, paidAt, currency, lines, total, locale }),
});
```

`sendEmail` renders the component with `@react-email/render` twice: once to HTML, once with `plainText: true`. Both go to Postmark as `HtmlBody` and `TextBody`.

Pros:

- **Typed props.** A missing field is a compile error.
- **Reviewed like code.** A copy change is a pull request.
- **One source for every environment.**
- **Real formatting.** `Intl.NumberFormat` and `Intl.DateTimeFormat` with the recipient's locale.
- **Local preview** with `email dev` (the `react-email` CLI) and realistic `PreviewProps`.

Costs:

- A copy change needs a deploy.
- Rendering costs a few milliseconds per send. Render once per message, not per recipient.

## How to choose

- Engineers own the emails, and the emails carry money, links or tokens: **render in the app.** Receipts and sign-in links should never break silently because a model field was renamed.
- Marketing owns the copy and changes it weekly: **Postmark templates** can make sense, usually on a broadcast stream.
- Mixing is fine. Keep each template in exactly one place. A receipt that exists both as a component and as a Postmark template will drift.

## If you use Postmark templates anyway

- Keep the aliases in one constants file.
- Type the model yourself: `satisfies ReceiptModel` at each call site.
- Push templates from the repo with the Templates API (`/templates/push` copies between servers) instead of editing each server by hand.
- Always send a text body. Postmark templates support a text version. Fill it.

---

Agentic Boilerplate: A Next.js repo your agent already knows. Free during launch, then $99 once.

- Site map for agents: https://agenticboilerplate.com/llms.txt
- Public API: https://agenticboilerplate.com/openapi.json
- Contact: agenticstudio@gmail.com
