# Email templates and campaigns

URL: https://docs.spacerun.co/docs/platform/guides/email-campaigns

> Version a template, build an audience, test, launch or schedule, and inspect delivery results.

Prerequisites: configured outbound email, `email.read`/`email.write`, `email.publish` for template publication and `email.send` for sends. Examples use [apiRequest](https://docs.spacerun.co/docs/platform/guides/quickstart). Use a controlled test audience before selecting real recipients.

## Create a template version

```ts
await apiRequest("/v1/admin/email/templates", {
  method: "POST", body: JSON.stringify({ key: "release-update", name: "Release update", kind: "broadcast", subject: "Release news" }),
});
const draft = await apiRequest("/v1/admin/email/templates/release-update/draft", {
  method: "POST", body: JSON.stringify({ subject: "Release news", html: "<p>Release news</p>", textBody: "Release news" }),
});
await apiRequest("/v1/admin/email/templates/release-update/publish", {
  method: "POST", body: JSON.stringify({ version: Number(draft.version) }),
});
```

Use [previewEmailTemplate](https://docs.spacerun.co/docs/platform/reference/email-templates/previewEmailTemplate) and [sendEmailTemplateTest](https://docs.spacerun.co/docs/platform/reference/email-templates/sendEmailTemplateTest) before publishing. Test sends use a positive version number and optionally a recipient/variables. Publication is 204. Template keys and versions are different identifiers.

## Build an audience and campaign

[createEmailAudience](https://docs.spacerun.co/docs/platform/reference/email-audiences/createEmailAudience) accepts a static audience or a dynamic audience with a filter. Populate static members through [setEmailAudienceMembers](https://docs.spacerun.co/docs/platform/reference/email-audiences/setEmailAudienceMembers); preview the resolved recipient count before sending.

```ts
const audience = await apiRequest("/v1/admin/email/audiences", {
  method: "POST", body: JSON.stringify({ name: "Release test audience", kind: "static" }),
});
const campaign = await apiRequest("/v1/admin/email/campaigns", {
  method: "POST", body: JSON.stringify({ name: "Release update", template_key: "release-update", audience_id: audience.id, vars: {} }),
});
const launched = await apiRequest(`/v1/admin/email/campaigns/${campaign.id}/launch`, { method: "POST" });
console.log(launched.total);
```

Fill and verify the audience before the launch call; the empty example audience is not a recipient list. [scheduleEmailCampaign](https://docs.spacerun.co/docs/platform/reference/email-campaigns/scheduleEmailCampaign) takes `scheduled_at`; use an explicit ISO timestamp for the intended instant. Campaign states include draft, scheduled, sending, paused, sent, cancelled and failed.

## Observe and recover

Use [getEmailCampaignProgress](https://docs.spacerun.co/docs/platform/reference/email-campaigns/getEmailCampaignProgress) and [listEmailCampaignDeliveries](https://docs.spacerun.co/docs/platform/reference/email-campaigns/listEmailCampaignDeliveries) to inspect queued/sent/failed deliveries. Accepted or queued is not delivered. Pause/resume/cancel affect campaign processing; cancellation cannot unsend messages already delivered. Follow the reference's state restrictions rather than retrying invalid transitions.

Recipients can unsubscribe through the public email endpoints; those responses include HTML/plain OAuth-independent error shapes where documented. Template rollback selects an existing version for future use and does not alter already sent mail. If SMTP is unconfigured, treat it as an operational dependency and inspect delivery status rather than reporting success from a launch response alone.
