---
title: "Send up to 100 messages"
method: POST
path: "/v1/email/batch"
tags: ["Sending"]
---

# Send up to 100 messages

`POST /v1/email/batch`

## Request

- Base URL: `https://api.sendora.se`
- URL: `https://api.sendora.se/v1/email/batch`
- Auth: HTTP bearer

Accepts an array of messages and answers one result per message, in order: accepted with its id, or refused with the same error the single send would give. The Idempotency-Key is required. A retry under the same key sends nothing twice: every item accepted before is answered again with replayed set, and only the items that failed are attempted again.

## Headers

- `idempotency-key` string, required

## Request body

- object[]
  - `from` union, required: The sender. Its domain must be a verified sending domain of the server.
    - string, email
    - object
      - `email` string, email, required
      - `name` string, nullable: A display name of up to 200 characters.
  - `streamId` string, uuid: The stream of this server the message goes on; the default transactional stream when absent.
  - `to` union[], required: Recipients; at most 50 across to, cc and bcc.
    - union: An address as a plain string, or an object with the address and a display name.
      - string, email
      - object
        - `email` string, email, required
        - `name` string, nullable: A display name of up to 200 characters.
  - `cc` union[]: Copied recipients, shown in the message.
    - union: An address as a plain string, or an object with the address and a display name.
      - string, email
      - object
        - `email` string, email, required
        - `name` string, nullable: A display name of up to 200 characters.
  - `bcc` union[]: Blind-copied recipients.
    - union: An address as a plain string, or an object with the address and a display name.
      - string, email
      - object
        - `email` string, email, required
        - `name` string, nullable: A display name of up to 200 characters.
  - `subject` string, required: The subject line.
  - `text` string: The plain-text part. At least one of text and html is required.
  - `html` string: The HTML part.
  - `headers` object: Custom headers by name, at most 20. Sendora writes these itself, so a message may not set them: From, Sender, To, Cc, Bcc, Subject, Date, Message-ID, MIME-Version, Return-Path, Received, Delivered-To, DKIM-Signature, DomainKey-Signature, Authentication-Results, Received-SPF, and any name that starts with Content-, Resent-, ARC- or X-Kumo.
  - `attachments` object[]: At most 20. A message with its attachments encoded may be at most 10 MB.
    - `name` string, required
    - `content` string, byte, required
    - `contentType` string
    - `contentId` string, nullable
  - `tag` string, nullable: A label of up to 100 characters, returned with the message and its events.
  - `metadata` object: Up to 20 key-value pairs of your own, returned with the message and its events.

## Response `200`

Every message answered on its own; the batch as a whole never fails halfway.

- object: Every message answered on its own; the batch as a whole never fails halfway.
  - `results` union[], required: One result per message, in request order.
    - union
      - object: The message was accepted for delivery.
        - `messageId` string, uuid, required: The id the message log, the events and the webhooks refer to.
        - `status` 'accepted', required
        - `submittedAt` string, date-time, required: When the message was accepted.
        - `test` boolean, required: True when the server is a test server: the message goes through everything but delivery, and nobody receives it.
        - `index` integer, required: The position of the message in the request.
        - `replayed` boolean, required: True when an earlier request under the same key already sent this item.
      - object: The message does not match what a send takes.
        - `error` 'invalid_request', required
        - `message` string, required: What went wrong, for a person to read.
        - `issues` object[], required: One entry per invalid field.
          - `path` string, required: The field, dotted, such as to.0.email; empty when the whole body is wrong.
          - `message` string, required
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: The From domain is not a verified sending domain of this server.
        - `error` 'from_domain_not_verified', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: The streamId names no stream of this server.
        - `error` 'stream_not_found', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: The stream is archived and takes no new messages.
        - `error` 'stream_archived', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: Sendora has paused the stream after complaints; it takes no messages until support has resumed it.
        - `error` 'stream_paused', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: An inbound stream receives mail; it takes no messages and has no suppression list. Name a transactional or broadcast stream.
        - `error` 'stream_not_sendable', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: A message on a broadcast stream must carry {{ unsubscribe_url }} in every part it has.
        - `error` 'unsubscribe_placeholder_missing', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: On a broadcast stream Sendora writes the List-Unsubscribe pair itself, so a message may not carry one.
        - `error` 'list_unsubscribe_reserved', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: One or more recipients are on the suppression list of the stream.
        - `error` 'recipient_suppressed', required
        - `message` string, required: What went wrong, for a person to read.
        - `streamId` string, uuid, required: The stream whose suppression list refused the send.
        - `suppressed` object[], required: Each refused address, lower-cased, with the reason it is on the list.
          - `address` string, required
          - `reason` 'hard_bounce' | 'spam_complaint' | 'manual' | 'unsubscribe', required
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: Addresses at simulator.sendora.se act out an outcome on a test server; a live server never sends to them.
        - `error` 'test_address_on_live_server', required
        - `message` string, required: What went wrong, for a person to read.
        - `addresses` string[], required: The recipients at simulator.sendora.se, each once.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: The Idempotency-Key was already used for a different request.
        - `error` 'idempotency_key_mismatch', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: More was sent within a minute than the limit allows.
        - `error` 'rate_limited', required
        - `message` string, required: What went wrong, for a person to read.
        - `scope` 'account' | 'server' | 'test', required: Whose limit it is: `account` for the account's, `server` for the server's own, `test` for the cap the account's test servers share.
        - `limit` integer, required: Emails per minute allowed for that scope.
        - `retryAfter` integer, required: Seconds until the next send is accepted; also sent as the Retry-After header.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: The monthly cap of the account, the server or the test servers is used up.
        - `error` 'monthly_cap_reached', required
        - `message` string, required: What went wrong, for a person to read.
        - `scope` 'account' | 'server' | 'test', required: Whose limit it is: `account` for the account's, `server` for the server's own, `test` for the cap the account's test servers share.
        - `cap` integer, required: Emails the scope may send in a calendar month, in UTC.
        - `used` integer, required: Emails sent this month, the refused send not counted.
        - `resetsAt` string, date-time, required: When the month counter resets.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: Sending is disabled for everyone for the moment; retry after the seconds in Retry-After.
        - `error` 'sending_disabled', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: The account is paused by Sendora.
        - `error` 'account_paused', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: The account is closed, or not yet approved for a live server's sends or an inbound stream.
        - `error` 'account_not_active', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: The account's first payment has not arrived, or an unpaid charge has stopped live sending.
        - `error` 'payment_required', required
        - `message` string, required: What went wrong, for a person to read.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required
      - object: The send's price would take what the account owes for emails past its limit; `unpaidOre`, `limitOre`, `priceOre`, `retryAfter`.
        - `error` 'unpaid_limit_reached', required
        - `message` string, required: What went wrong, for a person to read.
        - `unpaidOre` integer, required: What the account owes for emails before this send, in hundredths of a krona, excluding VAT.
        - `limitOre` integer, required: The most the account may owe for emails, in hundredths of a krona, excluding VAT.
        - `priceOre` integer, required: This send's price, in hundredths of a krona, excluding VAT.
        - `retryAfter` integer, nullable, required: Seconds to wait while a charge under way makes room, as in the Retry-After header; null when no charge under way would.
        - `index` integer, required: The position of the message in the request.
        - `status` 'error', required

## Other responses

- `400`: The body, the query or a header does not match what the route takes, or the Idempotency-Key header is missing.
- `401`: The key is missing, malformed or revoked.
- `402`: The account's first payment has not arrived, or an unpaid charge has stopped live sending.
- `403`: The key is of the other kind, the account is paused, closed or not yet approved for a live server's sends, or a connected app may not do this here.
- `413`: The body exceeds 10 MB.
- `503`: Sending is disabled for everyone for the moment; retry after the seconds in Retry-After.

---

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