Send Email
POST/email/campaign
Send emails to contacts for business campaigns or automated emails.
Metadata
You can optionally attach a metadata object to the send. Metadata is echoed back on every webhook event generated for that send, allowing you to associate webhook events with your own entities such as order IDs, tenant IDs, or internal campaign identifiers.
Example:
{
"subject": "Your order shipped",
"body": "<html>...</html>",
"sender": {
"from": {
"name": "Shop",
"email": "orders@shop.com"
}
},
"recipients": {
"to": [
{
"email": "ann@example.com"
}
]
},
"campaignId": "order_shipped_SO-1001",
"metadata": {
"order_id": "SO-1001",
"tenant_id": "acme"
}
}
The metadata is available in every webhook event generated for the send.
Per-recipient metadata
A batch that shares one subject, body and sender but needs a different identifier per message sets metadata on the recipient as well. The two maps are merged and the recipient's keys win:
{
"subject": "Your order shipped",
"body": "<html>Hi [FIRST_NAME]</html>",
"sender": {
"from": {
"name": "Shop",
"email": "orders@shop.com"
}
},
"campaignId": "order_shipped",
"metadata": {
"tenant_id": "acme",
"app": "checkout"
},
"recipients": {
"to": [
{
"email": "ann@example.com",
"attributes": { "FIRST_NAME": "Ann" },
"metadata": { "order_id": "SO-1" }
},
{
"email": "bob@example.com",
"attributes": { "FIRST_NAME": "Bob" },
"metadata": { "order_id": "SO-2" }
}
]
}
}
Ann's webhook events carry {"tenant_id": "acme", "app": "checkout", "order_id": "SO-1"} and Bob's the same with SO-2. A recipient that omits metadata inherits the request-level map unchanged, so the two shapes can be mixed in one request.
The merged map must not exceed 10 keys, and at most 500 recipients per request may carry their own metadata. Requests that break either rule are rejected with 412 before any email is sent.
Metadata is scoped to the campaignId. If the same campaignId is used by multiple requests, they share the same metadata and the latest value replaces the previous value — including every per-recipient entry, so reusing a campaignId across batches discards the earlier batch's recipient metadata. To keep metadata isolated, use a unique campaignId for each batch or omit campaignId and use the generated requestId.
Request
Header Parameters
When set to true, tracking links in the email hide the destination inside an opaque, tamper-proof token instead of exposing it as a readable redirectUrl query parameter. This keeps destination URLs out of the message body where blocklist scanners can read them. Link wrapping is off unless this header is sent with true — there is no account-level default.
- application/json
Body
required
- Array [
- ]
headers object
Additional headers to be added to the email.
Unsubscribe URL for the email, in angle brackets. Supplying it overrides the default unsubscribe header TinyEmail generates, and TinyEmail adds no unsubscribe link of its own to your HTML.
For RFC 8058 one-click unsubscribe you must send both this header and List-Unsubscribe-Post, and the URL here must accept a POST. This header alone does not enable one-click.
Header names are matched exactly and are case-sensitive: send List-Unsubscribe, not list-unsubscribe.
For more information, visit the email sender guidelines.
Set to List-Unsubscribe=One-Click to advertise RFC 8058 one-click unsubscribe. Only meaningful alongside a List-Unsubscribe URL that accepts a POST.
Send this together with your own List-Unsubscribe. Supplying one without the other advertises a capability the other header does not back.
metadata object
Optional metadata to associate with the send. The metadata is returned in every webhook event generated for the send.
Metadata is scoped to the campaignId. If campaignId is not provided, the generated requestId is used instead. Every recipient in the request shares this map; a recipient that needs its own values sets metadata on itself as well, and the two are merged with the recipient's keys winning.
Maximum 10 key/value pairs. Keys can be up to 64 characters and values up to 256 characters. Values must be flat strings, numbers, or booleans; numbers and booleans are converted to strings. Nested objects, arrays, and null values are not supported.
Keys are normalized to lowercase snake_case. For example, OrderID becomes order_id. Keys that normalize to the same name are rejected.
sender object
from object
replyTo object
recipients object
to object[]
attributes object
metadata object
Optional metadata for this recipient only, merged over the request-level metadata in every webhook event generated for this recipient. Where both define the same key, the recipient's value wins.
Use this when one request sends the same email to many people who each need a different identifier — one order_id per recipient, for example. A recipient that omits metadata receives the request-level map unchanged.
This is not attributes: attributes are merge tags rendered into the email body and are never echoed on webhooks, while metadata is never rendered into the email and is always echoed.
The same limits apply as to the request-level map, and the merged result must not exceed 10 keys — 10 in total, not 10 per level. At most 500 recipients in one request may carry their own metadata; recipients relying only on the request-level map are not counted.
When true, TinyEmail adds no tracking of its own to this request: links are not rewritten, and the open-tracking pixel is not inserted.
This is a single switch covering both. There is no way to disable click tracking while keeping open tracking, or the reverse.
It applies to the whole request. It cannot be set per recipient.
Responses
- 202
- 400
- 401
- 405
Successful operation
- application/json
- Schema
- Example (from schema)
Schema
{
"requestId": "833c5151-5a98-4bad-a30f-7cc816352b7a",
"message": "SUCCESS"
}
Bad Request
- application/json
- Schema
- Example (from schema)
Schema
{
"message": "Some error message"
}
API key is missing or invalid
Method Not Allowed