---
title: "Send a draft"
method: POST
path: "/v1/drafts/{id}/send"
tags: ["Drafts"]
---

# Send a draft

`POST /v1/drafts/{id}/send`

## Request

- Base URL: `https://api.mails.ai`
- URL: `https://api.mails.ai/v1/drafts/{id}/send`
- Auth: HTTP bearer

**Requires scope:** `send`. Sends a draft immediately, or schedules it when the request body supplies a future `send_at`. A test key cannot send or schedule a draft a live key made (403 `live_mode_required`).

## Path parameters

- `id` string, required

## Headers

- `Idempotency-Key` string

## Request body

- SendDraftRequest
  - `send_at` string, date-time: Send the draft at this time instead of now: an ISO 8601 UTC time ending in `Z`, in the future (400 `invalid_field` otherwise). Left out, the draft is sent at once.

## Response `200`

Either the scheduled draft or the sent message.

- union
  - object
    - `id` string, required: Id of the draft that was scheduled (`dft_…`).
    - `status` 'scheduled', required: `scheduled`: nothing was sent in this call; the draft goes out at `send_at`.
    - `send_at` string, date-time, required: When the draft will be sent (UTC).
  - object
    - `id` string, required: Id of the draft (`dft_…`), not of the message it became: that is `message_id`.
    - `status` 'sent', required: `sent`: the draft was sent in this call. With a test key it is recorded but not transmitted.
    - `message_id` string, required: Id of the message the draft became (`msg_…`); the draft keeps it as `sent_message_id`.
    - `thread_id` string: The thread the message was filed in (`thrd_…`): that of the message named by `in_reply_to_message_id` when it is this agent's, otherwise a new one. A test send starts its own thread rather than join one holding live mail.
    - `sent_at` string, date-time: When the message was sent: the time of this call.
    - `refused_recipients` string[]: The recipients the email service refused while it took the message for the others, as on a sent message. The draft is still sent. Present only when there were any.

## Other responses

- `400`: Invalid request — malformed JSON or a field failed validation. Also `feature_not_enabled` when this server has a feature switched off (custom domains before they are available).
- `401`: Missing or invalid API key.
- `403`: The API key lacks the required scope (`insufficient_scope`), or the token belongs to an app connected by sign-in and this operation is closed to connected apps (`connected_app_not_allowed`).
- `404`: Resource not found in this workspace, or the agent a send names is archived (`agent_archived`).
- `409`: Conflict — duplicate resource, an in-progress idempotent request, a draft or scheduled message that started sending while it was being changed, or a thread deleted for good while one of its messages is being sent (`duplicate_resource`); or an agent name more than one agent has (`agent_name_conflict`: use the agent's id); or a status change on an archived agent, since archiving cannot be undone (`agent_archived`).
- `422`: Unprocessable — agent paused, recipient suppressed, a recipient at test.mails.ai other than reply@test.mails.ai (`unknown_test_address`), or abuse guard.
- `429`: Rate or quota limit exceeded. The body's `resets_at` and `retry_after_seconds` say when the request can succeed. A `Retry-After` header is sent only when that is 60 seconds or less; a longer wait (an hourly, daily or monthly cap) sends none, so retry at `resets_at` or raise the limit instead of sleeping.
- `500`: Internal server error.
- `502`: The email service the mail goes out through did not confirm it took it (`upstream_error`), so it is recorded as not sent. The message is a fixed sentence naming the request id to quote to support@mails.ai; the service's own error is never returned. When the service refuses every recipient as undeliverable the answer is 422 `recipient_suppressed` instead, and when it is only not taking more mail for now, 503 `upstream_unavailable`.
- `503`: Temporarily unavailable, and nothing was done. On a send: the email service is not taking more mail right now (`upstream_unavailable`), so nothing was sent; send it again after the seconds in `Retry-After`.

---

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