---
title: "Send with a template"
description: "The stored body supplies the message; the request supplies the envelope and the values."
url: "https://openemail.uk/docs/api/templates/send"
area: "API"
category: "Mailbox"
---

# Send with a template

The stored body supplies the message; the request supplies the envelope and the values.

`POST /templates/{id}/send`

## POST /templates/{id}/send

The stored body supplies the message; the request supplies the envelope and the values.

## Example

Needs `templates:write` AND `emails:send`. Honours `Idempotency-Key` exactly as `POST /emails` does.

**curl**

```
curl -X POST "$OE/templates/order-shipped/send" -H "$AUTH" \
  -H "Content-Type: application/json" -H "Idempotency-Key: order:AC-4192:shipped" \
  -d '{
    "from": "Acme Dispatch <dispatch@acme.com>",
    "to": ["ada@example.com"],
    "version": 5,
    "props": { "orderId": "AC-4192", "customer": "Ada" }
  }'
```

**Response**

```
{
  "object": "email",
  "id": "msg_c5f21cc6…",
  "status": "queued",
  "from": "dispatch@acme.com",
  "subject": "Order AC-4192 is on its way",
  "template": { "id": "order-shipped", "version": 5 }
}
```

> Both scopes, and neither is redundant: `templates:write` because the caller is reaching a stored body, `emails:send` because mail leaves the workspace. A key that may send its own bodies still cannot send somebody else’s template.

> Pin `version` in anything automated. Omitted, you resolve whatever is published at that moment, which is what you want when somebody else owns the copy and not what you want the morning they rewrite it.

> `subject` overrides the template’s own for this message only, and `cancellableForSeconds`, `tracking` and `tags` behave exactly as they do on a plain send.

> `POST /emails` accepts a `template` field that does the same thing, for a caller that already builds messages there. This endpoint exists so that reaching a stored body does not require supplying the shape of a message you are not composing.

## When a send is refused

Props are a contract rather than a suggestion, and every failure below happens before anything is dispatched. The alternative, a message going out with a blank where the order number was, is not reported by anything and cannot be recalled.

| Code | Status | What happened |
| --- | --- | --- |
| `resource_not_found` | 404 | No template on this connection with that id or slug. |
| `template_not_published` | 422 | It exists and has never been published, or the version you named is still a draft. |
| `template_version_not_found` | 422 | You pinned a `version` this template has never had. |
| `missing_template_prop` | 422 | A prop declared `required` was absent, null or empty. |
| `unknown_template_prop` | 422 | You passed a key the version does not declare. The message names the ones it does. |
| `unknown_template_slot` | 422 | The same, for a slot. |
| `invalid_template_prop` | 422 | A value that is not a string, a number or a boolean. An object or an array cannot be substituted into HTML. |

> `param` on these is `template.props.<key>`, so a client can point at the field it got wrong without parsing the message.
