---
title: "Send a batch of emails"
method: POST
path: "/api/emails/batch"
tags: ["Emails"]
---

# Send a batch of emails

`POST /api/emails/batch`

## Request

- Base URL: `https://api.sendly.now`
- URL: `https://api.sendly.now/api/emails/batch`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `better-auth.session_token`
  - OAuth 2 (authorization code, authorization URL `https://app.sendly.now/api/auth/oauth2/authorize`, token URL `https://app.sendly.now/api/auth/oauth2/token`, scopes: `emails:send`)

Send up to 100 emails in one request. Returns 207 Multi-Status if any entry failed, or 200 if all succeeded. Per-entry results are reported in the `data` array.

The whole batch is ONE idempotent unit: an `Idempotency-Key` replayed with the same entry list replays the same per-index results, and replaying it with an edited list answers `422 IDEMPOTENCY_KEY_REUSED` rather than returning results for indexes the new body no longer has.

Requires the `emails:send` scope — Send emails from your verified domains.

## Headers

- `Idempotency-Key` string

## Request body

- BatchSendBody: Batch send wrapper. Up to 100 entries.
  - `emails` SendEmail[], required
    - `attachments` object[]
      - `content` string, required
      - `contentId` string
      - `contentType` string, required
      - `disposition` 'attachment' | 'inline'
      - `filename` string, required
    - `bcc` string[]
    - `body` string
    - `cc` string[]
    - `data` object: Arbitrary JSON value (string, number, boolean, null, array, or object).
    - `from` union
      - string, email
      - object
        - `email` string, email, required
        - `name` string
    - `headers` object: Extra header fields to add to the message, as name → value. A name must be an RFC 5322 field-name (printable ASCII, no spaces or colons) and must not be one Sendly writes itself: From, Sender, Reply-To, To, Cc, Bcc, Subject, Date, Message-ID, MIME-Version, Content-Type, Content-Transfer-Encoding, Content-Disposition, Return-Path, DKIM-Signature, DomainKey-Signature, Received, Authentication-Results, List-Unsubscribe, List-Unsubscribe-Post, and any X-SES-*, X-Sendly-*, Resent-* or ARC-* header. A reserved name, in any letter case, fails validation and nothing is sent.
    - `name` string
    - `reply` string, email
    - `subject` string
    - `subscribed` boolean
    - `tags` string[]
    - `template` string, uuid
    - `to` union, required
      - string, email
      - object
        - `email` string, email, required
        - `name` string
      - union[]
        - union
          - string, email
          - object
            - `email` string, email, required
            - `name` string

## Response `200`

All entries sent

- BatchSendResponse: Multi-status response for `POST /api/emails/batch`. HTTP 207 if any entry failed, else 200.
  - `data` BatchEntryResult[], required
    - `data` SendEmailData: Result of a send (`executeSendEmail`): one `emails` entry per recipient — a single request with an array `to` fans out to several — plus the send `timestamp`.
      - `emails` SendEmailRecipientResult[], required
        - `contact` object, required
          - `email` string, email, required
          - `id` string, uuid, required
        - `email` string, uuid, required
      - `timestamp` string, date-time, required: ISO 8601 datetime string
    - `error` object
      - `code` string, required
      - `message` string, required
    - `index` integer, required
    - `status` 'ok' | 'error', required
  - `success` boolean, required

## Other responses

- `207`: Partial success — at least one entry failed
- `400`: Validation error, or `TOO_MANY_UNIQUE_TEMPLATES` — a new account submitted more distinct message bodies in one request than content review allows.
- `401`: Unauthorized — missing or invalid auth
- `403`: Forbidden — insufficient permissions, project disabled, or `CONTENT_REJECTED`: the message was flagged by automated content review and was not sent.
- `409`: `CONFLICT` — a request with this `Idempotency-Key` is still in flight. Retry shortly.
- `422`: `IDEMPOTENCY_KEY_REUSED` — this `Idempotency-Key` was already used for a request with a different body. Reuse a key only to retry the identical request; otherwise send a new key.
- `429`: Rate limit or billing limit exceeded
- `500`: Internal server error
- `503`: `CONTENT_REVIEW_UNAVAILABLE` — content review could not run for this new account, so the message was not accepted. Safe to retry after a short delay.

---

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