---
title: "Send a single transactional email"
method: POST
path: "/api/emails"
tags: ["Emails"]
---

# Send a single transactional email

`POST /api/emails`

## Request

- Base URL: `https://api.sendly.now`
- URL: `https://api.sendly.now/api/emails`
- 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 a single transactional email. Accepts a `template` ID or an inline `subject` + `body`. An optional `Idempotency-Key` request header (1–255 chars, 24h TTL) ensures replay safety: the first request wins and a retry carrying the same key AND the same body replays its response. Reusing a key with a DIFFERENT body answers `422 IDEMPOTENCY_KEY_REUSED` — a key names one request, so it is never silently served another request's result.

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

## Headers

- `Idempotency-Key` string: Replay-safety key (24h TTL). Reuse it only to retry the identical request.

## Request body

- SendEmail: Body for POST /api/emails — send a single transactional email. Either `template` or `subject`+`body` is 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`

Email accepted / sent

- SendEmailResponse: Successful response for `POST /api/emails`. `data.emails[i].email` is the queued email id for recipient `i`; poll `GET /api/emails/{id}` for its delivery status.
  - `data` SendEmailData, required: 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
  - `success` true, required

## Other responses

- `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)
