> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useboom.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Email templates

> Read, create and update email templates over MCP or the API — as builder blocks or as HTML.

Email templates are what a journey's `SEND_EMAIL` node sends. You can author
them in the app's builder, or from an agent or script with five tools (each is
also a REST endpoint):

| Tool | Endpoint | Does |
| - | - | - |
| `email_templates_list` | `GET $BASE/email-templates` | Every template, draft and published, with its status, mode and variables |
| `email_templates_get` | `GET $BASE/email-templates/{templateId}` | One template in full — edit it and send it back |
| `email_templates_create` | `POST $BASE/email-templates` | Create a template as a draft |
| `email_templates_update` | `PATCH $BASE/email-templates/{templateId}` | Rename, change subject/senders/content, publish or unpublish |
| `email_templates_preview` | `POST $BASE/email-templates/{templateId}/preview` | Render it with a real event's data and read back what a recipient would get. Nothing is sent |

A template is written one of two ways, and you send exactly one:

* **`document`** — the builder's blocks: `heading`, `text`, `button`, `image`,
  `divider`, `spacer`, `html`, `social`, `footer`, plus `container` (a framed
  card) and `columns` (side by side). Styling is optional; what you leave out
  takes the builder's defaults.
* **`html`** — your own markup. It is sanitized on save: scripts, event handlers
  and external stylesheets are removed, and the response lists what was removed
  in `removed`.

Boom renders the deliverable HTML and plain text itself. Variables use the
`{{path}}` grammar in the subject and the body — `{{customer.name}}`,
`{{person.<attribute>}}`, `{{engagement.chatLink}}` — and resolve at send; see
[Template variables](/template-variables) for what a path can be. A template's
`variables` lists each path once, even when it is written both `{{x}}` and
`{{ x }}`; both spellings render.

```json theme={null}
{
  "name": "Recordatorio de pago",
  "subject": "Hola {{customer.name}}, tu pago vence pronto",
  "document": {
    "body": { "language": "es", "preheader": "Evita recargos" },
    "blocks": [
      { "type": "heading", "text": "Tu pago vence el viernes" },
      { "type": "text", "text": "Hola {{customer.name}}, aún tienes un saldo pendiente." },
      { "type": "button", "text": "Pagar ahora", "href": "https://example.com/pay" },
      { "type": "footer", "text": "Empresa S.A. de C.V., Ciudad de México" }
    ]
  }
}
```

The same template as HTML is `{ "name": …, "subject": …, "html": "<table>…</table>" }`.

## Sending one

A template sends through a journey. Build it on an email initiative with a
`SEND_EMAIL` step that points at the PUBLISHED template (`journeys_email_templates`
lists those, along with whether your domain and sender are ready), then launch
the initiative, which publishes the journey. Then enroll people:

* **Directly:** `initiatives_participants_add` with an `email` for each person.
* **On behavior:** give the journey a `cdp_event` trigger, and every time that
  event is recorded for a person with an email (`cdp_events_record`), they are
  enrolled.

People on your Do Not Contact list are skipped either way.

## Rules worth knowing

* **New templates are drafts.** A journey can only send a `PUBLISHED` template;
  publish with `email_templates_update` and `"status": "PUBLISHED"`.
* **Changing a published template needs `"confirm": true`.** Journeys reference
  the template itself, so an edit changes what they send from their next send,
  and setting it back to `DRAFT` makes those sends fail. Call without `confirm`
  first to see the refusal.
* **Unknown fields are rejected, not ignored**, so a typo such as `background`
  for a button's `bg` fails with a validation error instead of quietly taking
  the default.
* **Blocks → HTML is one way.** Sending `html` to a block template converts it;
  an HTML template does not accept a `document` again.
* A footer block goes at the top level of the email, not inside a container or a
  column. Omit `unsubscribeLabel` for the document language's default link text,
  or send `""` for no unsubscribe link (transactional email).
* Not available here yet: test sends, image upload (use an image URL you host,
  or one from the builder's library), and deleting a template.

## Preview with a real event

`email_templates_preview` renders a template the way a journey triggered by an
event would send it, without sending anything. Name the event one way:

* `latestEventName` — the most recent event with that name, e.g.
  `"payment_due"`; add `personExternalId` for that person's most recent one.
* `eventExternalId` — the id your backend sent the event with.
* `eventId` — Boom's id, from `cdp_events_list`.

```json theme={null}
{ "latestEventName": "payment_due", "personExternalId": "cus_123" }
```

The event's properties fill `event.*` (and `engagement.workflowState.*`),
including inside Liquid tags, so loops and conditions render as they will in
the real email. When the event names a person, `customer.*` and `person.*`
come from that person, as in the email the journey would send; fields your
organization marked sensitive stay hidden from an assistant. The response has
the `subject`, `html` and `text`, plus:

* `unresolved` — the paths of variables that came out blank. A blank `event.*` variable
  usually means the event doesn't carry that property.
* `liquidError` — set when the Liquid failed to render.
* `redactedKeys` — event properties your organization marked sensitive. An
  assistant (MCP) always sees them masked; an API key sees real values.
* `event` — which event was used (`null` without one, when sample values are
  used instead).

`values` overrides any path with fixed text (`{ "customer.name": "Ana" }`), and
`bindings` previews the email as a journey **Send email** step that remaps its
variables.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.