import { createClient } from "@mailsai/sdk";
const client = createClient(); // reads MAILS_API_KEY
const result = await client.drafts.send(
"dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
);
console.log(result);from mailsai import create_client
client = create_client() # reads MAILS_API_KEY
result = client.send_draft(
"dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
)
print(result)curl -X POST 'https://api.mails.ai/v1/drafts/dft_01JZX8K3M9Q4P7VN2YB6RTDC0E/send' \
-H "Authorization: Bearer $MAILS_API_KEY" \
-H 'Content-Type: application/json' \
-d '{ "send_at": "2026-06-25T15:30:00.000Z" }'mails drafts send dft_01JABC
mails drafts send dft_01JABC \
--send-at 2026-12-01T09:00:00Z{
"name": "mails_send_draft",
"arguments": {
"draft_id": "dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
"send_at": "2026-06-25T15:30:00.000Z"
}
}{
"id": "dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
"status": "scheduled",
"send_at": "2026-10-04T12:00:00.000Z"
}200 Either the scheduled draft or the sent message.
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.Send a draft
send_at.import { createClient } from "@mailsai/sdk";
const client = createClient(); // reads MAILS_API_KEY
const result = await client.drafts.send(
"dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
);
console.log(result);from mailsai import create_client
client = create_client() # reads MAILS_API_KEY
result = client.send_draft(
"dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
)
print(result)curl -X POST 'https://api.mails.ai/v1/drafts/dft_01JZX8K3M9Q4P7VN2YB6RTDC0E/send' \
-H "Authorization: Bearer $MAILS_API_KEY" \
-H 'Content-Type: application/json' \
-d '{ "send_at": "2026-06-25T15:30:00.000Z" }'mails drafts send dft_01JABC
mails drafts send dft_01JABC \
--send-at 2026-12-01T09:00:00Z{
"name": "mails_send_draft",
"arguments": {
"draft_id": "dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
"send_at": "2026-06-25T15:30:00.000Z"
}
}{
"id": "dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
"status": "scheduled",
"send_at": "2026-10-04T12:00:00.000Z"
}200 Either the scheduled draft or the sent message.
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.Path Parameters
Draft id.
Body Parameters
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.
Headers
Replays the stored response for a repeated key (kept 24 hours), so a retried request never double-sends; the replay carries Idempotent-Replay: true. An error is kept on the key only once the mail has gone out, so a replayed error means it was sent. Once a scheduled send is stored, a failure after that keeps the message's answer on the key instead: the retry answers with the message (201) and raises its message.scheduled if the first request did not. After a failure before either, the same key sends again, as it does after a batch that stored no message and sent no mail.
A test key cannot send or schedule a draft a live key made (403 live_mode_required).
Was this page helpful?