---
title: "Send one email to many recipients"
method: POST
path: "/mailboxes/{address}/send-batch"
tags: ["Mail"]
---

# Send one email to many recipients

`POST /mailboxes/{address}/send-batch`

## Request

- Base URL: `https://faivelo.com/api/v1`
- URL: `https://faivelo.com/api/v1/mailboxes/{address}/send-batch`
- Auth: HTTP bearer

Sends one templated email to many recipients in a single call. `{{field}}` tokens in `subject`, `text` and `html` are filled from each recipient's `fields` (a missing field renders empty; HTML values are escaped). Faivelo queues the batch, sends it at the plan's pace and tracks every recipient: the response is immediate (`202`) with the batch and each recipient as `queued`; poll `GET /mailboxes/{address}/send-batch/{id}` or listen to the `email.delivered` / `email.bounced` / `email.complained` webhooks, which carry `batch_id`. Every recipient counts against the monthly send allowance like a single send. The whole batch is accepted or refused: more recipients than the plan's per-call cap (`422 batch_too_large`; `GET /usage` reports the cap as `batch.recipientsPerCall`) or than the remaining allowance (`403 send_limit_reached`) queues nothing. Per-call caps: Free agents tier 20, Growth/Pro/Business 100, Developer 200, Scale 1,000 (the larger of the mail plan's and the Agents plan's applies; Starter has none). `idempotencyKey` is required: a repeat with the same key returns the original batch (`replayed: true`) instead of sending again. Requires scope `mail:send`; agent keys may only use mailboxes they were granted.

## Path parameters

- `address` string, required

## Request body

- SendBatchRequest: One templated email for many recipients. `subject`, `text` and `html` may contain `{{field}}` tokens, filled per recipient from `fields`.
  - `subject` string, required: Subject line; may contain `{{field}}` tokens
  - `text` string: Plain-text body; may contain `{{field}}` tokens. Required unless `html` is given.
  - `html` string: HTML body; may contain `{{field}}` tokens (values are HTML-escaped). Required unless `text` is given.
  - `replyTo` string: Reply-To address — replies go here instead of the sending mailbox
  - `fromName` string: From display name for this batch only; the mailbox's stored name is unchanged
  - `recipients` object[], required: One entry per recipient, up to the plan's per-call cap. Duplicate addresses are sent once.
    - `email` string, email, required
    - `fields` object: Values for this recipient's `{{field}}` tokens. A field the templates use but this recipient lacks renders empty and is listed in `missingFields`.
  - `idempotencyKey` string, required: Required. Unique to this batch (derive it from the event, not a timestamp): a repeat with the same key returns the original batch instead of sending again; the same key with a different request is a 422.
  - `labels` string[]: Free-form tags kept on the batch and echoed in its status and webhook events

## Response `202`

Batch queued (or 200 with `replayed: true` when the idempotency key matched an earlier batch)

- object
  - `success` boolean
  - `data` SendBatch: A bulk send and the state of every recipient
    - `id` string: Pass to GET /mailboxes/{address}/send-batch/{id}
    - `mailbox` string
    - `subject` string
    - `status` 'queued' | 'sending' | 'completed' | 'failed': `failed` when the account stopped the batch (quota spent mid-batch, a pause); the per-recipient rows say which were sent
    - `replyTo` string
    - `fromName` string: The batch's own From name, when one was given
    - `hint` string: Present when the email went out with no display name, so recipients saw only the address. Says how to set one.
    - `labels` string[]
    - `counts` object
      - `total` integer
      - `queued` integer
      - `sent` integer
      - `delivered` integer
      - `bounced` integer
      - `complained` integer
      - `failed` integer
    - `recipients` object[]
      - `email` string
      - `status` 'queued' | 'sending' | 'sent' | 'delivered' | 'bounced' | 'complained' | 'failed'
      - `messageId` string: The Message-ID of this recipient's email, once sent
      - `error` string: Why this recipient failed
      - `sentAt` string, date-time
      - `deliveredAt` string, date-time
      - `bouncedAt` string, date-time
      - `missingFields` string[]: Template fields this recipient had no value for (rendered empty)
    - `error` string: Why the batch stopped early
    - `createdAt` string, date-time
    - `completedAt` string, date-time
    - `replayed` boolean: Present and true when the idempotency key matched an earlier batch: this is that batch, nothing new was queued

## Other responses

- `401`: Missing or invalid API key
- `402`: The account's plan does not include the API (`plan_required`)
- `403`: The key lacks the required scope
- `404`: Resource not found
- `422`: More recipients than the plan's per-call cap (`batch_too_large`), or the idempotency key was used with a different request
- `429`: Rate limit exceeded

---

[API](https://skmtc.dev/faivelo/apis/faivelo-api.md) · [All operations](https://skmtc.dev/faivelo/apis/faivelo-api/llms.txt) · [OpenAPI document](https://skmtc.dev/faivelo/apis/faivelo-api/revisions/a7413ddea5d1?raw)
