Docs/Sending email

Sending with templates

A template is stored email content you send by ID. Instead of inlining the subject and body on every POST /v1/email, you reference a template and let Anypost supply them.

How templates work

A template has a name, a subject, and a body. It also has a lifecycle worth understanding before you create one.

Every template keeps two slots: a published version and an optional draft. Sends always use the published version. Edits land in the draft and change nothing until you publish them. A newly created template has only a draft, so it has no sendable content until its first publish.

This means a template is only usable for sending once it has been published at least once, and editing a live template never disturbs mail already going out under it.

Authoring format

A template body is authored one of two ways, set by its kind when you create the template:

  • markdown, the recommended format. You write the body in emailmd, a markdown dialect built for email. A few lines of markdown compile to a responsive, well-styled message, with no HTML boilerplate to write or maintain. The dashboard's markdown editor includes an AI assistant that drafts and revises emailmd from a plain description.
  • html, a raw HTML body. Use it when you need full control of the markup, or are bringing an existing HTML design across.

kind is fixed when the template is created and cannot be changed later. To switch formats, create a new template.

Whichever format you pick, the plain-text body is derived automatically: Anypost generates a plain-text alternative so recipients whose mail client cannot render HTML still get a readable message. You never supply text yourself.

Create a template

Create a template in the dashboard, or with POST /v1/templates:

curl https://api.anypost.com/v1/templates \
  -H "Authorization: Bearer $ANYPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Welcome email",
    "kind": "markdown",
    "subject": "Welcome to Acme, {{first_name}}",
    "markdown": "# Welcome\n\nHi {{first_name}}, your account is ready."
  }'

For a raw-HTML template, pass "kind": "html" with an html body instead.

The name must be unique within your team. The {{first_name}} placeholders are optional; see Personalize with placeholders below.

The response is the new template:

{
  "id": "template_550e8400-e29b-41d4-a716-446655440000",
  "name": "Welcome email",
  "kind": "markdown",
  "has_draft": true,
  "published_at": null
}

The subject and body you supplied were stored as the template's draft. published_at is null, so the template cannot be used to send yet. Publish it first.

Publish a template

Publishing promotes the draft into the published slot:

curl -X POST https://api.anypost.com/v1/templates/template_550e8400.../publish \
  -H "Authorization: Bearer $ANYPOST_API_KEY"

The response shows published_at set and has_draft back to false. The template is now sendable. A template with no draft to publish returns 422.

Send with a template

Send with a template by passing template_id to POST /v1/email in place of a body:

curl https://api.anypost.com/v1/email \
  -H "Authorization: Bearer $ANYPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": ["[email protected]"],
    "template_id": "template_550e8400-e29b-41d4-a716-446655440000",
    "variables": { "first_name": "Alex" }
  }'

The subject and both body parts come from the template's published content. The response and behavior are otherwise identical to any other send; see Send a single email.

Two rules govern a templated send:

  • A template send carries no inline body. template_id cannot be combined with text or html. A request with both is rejected with 422: a send has one body source, not two.
  • subject is optional, and overrides the template. Omit it and the template's subject is used. Supply it and your value wins for that send, which is how you vary the subject without forking the template.

Personalize with placeholders

A template body and subject can contain {{ placeholder }} markers. Pass a variables object on the send and Anypost substitutes the values before delivery, so one template serves many recipients.

"variables": { "first_name": "Alex", "plan": "Pro" }

A send with no variables is delivered exactly as stored, with no substitution, so a template whose literal text happens to contain {{ }} is never mangled. Placeholder syntax, nesting, and the size limits are covered in Variables & personalization.

Edit a published template

Editing is a two-step cycle: update the draft, then publish it.

curl -X PATCH https://api.anypost.com/v1/templates/template_550e8400.../draft \
  -H "Authorization: Bearer $ANYPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Welcome aboard, {{first_name}}",
    "markdown": "# Welcome aboard\n\nHi {{first_name}}, welcome to Acme."
  }'

This creates the draft if there is none and updates it otherwise. The published version is untouched, so sends keep using the old content until you run POST /v1/templates/{id}/publish again. Discard a draft you do not want with DELETE /v1/templates/{id}/draft.

To rename a template, PATCH /v1/templates/{id} with a new name. Body content cannot be changed on that path: it is draft-versioned, and the draft endpoint is the only way to change it.

Managing templates

OperationEndpoint
List templatesGET /v1/templates
Retrieve oneGET /v1/templates/{id}
View the draftGET /v1/templates/{id}/draft
DuplicatePOST /v1/templates/{id}/duplicate
RenamePATCH /v1/templates/{id}
DeleteDELETE /v1/templates/{id}

A duplicate starts as a new, unpublished template seeded from the source's content, so it must be published before use. A team may hold up to 500 templates.

When a templated send fails

A send that references a template can fail validation before any mail is queued. Each returns 400 with a validation_error; see API conventions for the error shape.

ProblemCause
Template not foundNo template with that ID exists for your team.
Template has no published contentThe template exists but was never published. Publish a draft first.
subject is requiredNeither the request nor the template supplied a subject.

Where to go next