import { createClient } from "@mailsai/sdk";
const client = createClient(); // reads MAILS_API_KEY
const result = await client.drafts.create({
agent: "hello",
to: "jordan@example.com",
subject: "Following up on order #10473",
body_text: "Just confirming your order arrived.",
});
console.log(result);from mailsai import create_client
client = create_client() # reads MAILS_API_KEY
result = client.create_draft(
agent="hello",
to="jordan@example.com",
subject="Following up on order #10473",
body_text="Just confirming your order arrived.",
)
print(result)curl -X POST 'https://api.mails.ai/v1/drafts' \
-H "Authorization: Bearer $MAILS_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"agent": "hello",
"to": "jordan@example.com",
"subject": "Following up on order #10473",
"body_text": "Just confirming your order arrived."
}'mails drafts create --to jordan@example.com \
--subject "Following up" --text "Just checking in."{
"name": "mails_create_draft",
"arguments": {
"agent": "hello",
"to": "jordan@example.com",
"subject": "Following up on order #10473",
"body_text": "Just confirming your order arrived."
}
}{
"id": "dft_01JZXB5N7P9R1T3V5X7Z9A1C3E",
"agent_id": "agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9",
"to": ["jordan@example.com"],
"subject": "Following up on order #10473",
"body_text": "Just confirming your order arrived.",
"status": "draft",
"created_at": "2026-06-24T19:00:00.000Z",
"updated_at": "2026-06-24T19:00:00.000Z"
}201 The created draft.
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).
422 Unprocessable — agent paused, recipient suppressed,
a recipient at test.mails.ai other than
reply@test.mails.ai (unknown_test_address), or
abuse guard.
500 Internal server error.Create a draft
send_at is in the future.import { createClient } from "@mailsai/sdk";
const client = createClient(); // reads MAILS_API_KEY
const result = await client.drafts.create({
agent: "hello",
to: "jordan@example.com",
subject: "Following up on order #10473",
body_text: "Just confirming your order arrived.",
});
console.log(result);from mailsai import create_client
client = create_client() # reads MAILS_API_KEY
result = client.create_draft(
agent="hello",
to="jordan@example.com",
subject="Following up on order #10473",
body_text="Just confirming your order arrived.",
)
print(result)curl -X POST 'https://api.mails.ai/v1/drafts' \
-H "Authorization: Bearer $MAILS_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"agent": "hello",
"to": "jordan@example.com",
"subject": "Following up on order #10473",
"body_text": "Just confirming your order arrived."
}'mails drafts create --to jordan@example.com \
--subject "Following up" --text "Just checking in."{
"name": "mails_create_draft",
"arguments": {
"agent": "hello",
"to": "jordan@example.com",
"subject": "Following up on order #10473",
"body_text": "Just confirming your order arrived."
}
}{
"id": "dft_01JZXB5N7P9R1T3V5X7Z9A1C3E",
"agent_id": "agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9",
"to": ["jordan@example.com"],
"subject": "Following up on order #10473",
"body_text": "Just confirming your order arrived.",
"status": "draft",
"created_at": "2026-06-24T19:00:00.000Z",
"updated_at": "2026-06-24T19:00:00.000Z"
}201 The created draft.
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).
422 Unprocessable — agent paused, recipient suppressed,
a recipient at test.mails.ai other than
reply@test.mails.ai (unknown_test_address), or
abuse guard.
500 Internal server error.Body Parameters
Which agent sends the draft: its name or agt_ id. Left out: the agent a key is tied to, else the workspace's only agent, or a new one named agent when there is none and the key may create agents (the manage scope; otherwise 403 insufficient_scope). With several agents and a key tied to none, it is required (400 missing_field).
Who the draft goes to: one address, or a list of 1 to 50. It is stored and returned as a list.
Addresses to copy when the draft is sent, up to 50.
Addresses to blind-copy when the draft is sent, up to 50. They appear in none of the email's headers.
Subject line, 1 to 998 characters. A draft without one is sent with an empty subject.
Plain-text body, up to 1,000,000 characters. A draft can be saved without a body.
HTML body, up to 1,000,000 characters. A draft can be saved without a body.
The address replies to the sent draft should go to. Left out, replies go to the agent's receiving_address.
Id of the message this one answers (msg_… or rcv_…), named in the email's In-Reply-To header. Once sent, the draft joins its thread when the same agent sent or received it. Left out, it starts a new thread.
Schedule the draft to send at this time: an ISO 8601 UTC time ending in Z, in the future (400 invalid_field otherwise). It needs the send scope. Left out, the draft waits until it is sent.
Up to 10 name-value labels, copied onto the message when the draft is sent; they are not part of the email.
Opt in to RFC 8058 one-click unsubscribe: the message carries List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click headers, so the recipient's mail app shows an Unsubscribe button. One click suppresses the address for your whole workspace: every later send to it from any of your agents is refused with recipient_suppressed until you allowlist it (POST /v1/suppression/allow). Turn it on for newsletters, digests and other recurring mail. Leave it off (the default) for password resets, sign-in links, receipts and anything else the recipient must keep receiving.
Needs exactly one to recipient and no cc or bcc.
Scheduling sends the draft at that time, so a send_at needs the send scope: a key with only draft gets 403 insufficient_scope. A draft cannot carry attachments (422 invalid_field, param attachments); send files with POST /v1/messages.
Response
Draft id (dft_…).
Id (agt_…) of the agent the draft is sent from, chosen when it was created.
The draft's recipients, always as a list, even when one address was given.
The draft's Cc addresses. Absent when cc was never given; [] when it was given empty or a PATCH emptied it.
The draft's Bcc addresses, who receive it but appear in none of its headers. Absent when bcc was never given; [] when it was given empty or a PATCH emptied it.
The draft's subject. Absent when none was given; the draft is then sent with an empty subject.
The draft's plain-text body. Absent when none was given.
The draft's HTML body. Absent when none was given.
The address replies should go to, as given on create; absent when none was.
Id of the message this draft answers (msg_… or rcv_…), as given on create; absent when none was.
The thread the draft's message joined (thrd_…), written when the draft is sent: the thread of the message named by sent_message_id, also when the send could not be fully recorded after that message was stored (see error_message). Absent until it is sent, when a send could not be recorded far enough to store its message (no sent_message_id), once that thread is deleted, and on drafts sent before this field was filled in.
Name-value labels saved with the draft and copied onto the message when it is sent. Absent when none were given.
The time the draft is scheduled for (UTC); it stays after the draft is sent. Absent when it was never scheduled or was unscheduled with send_at: null.
Whether the draft is sent with RFC 8058 one-click unsubscribe headers (list_unsubscribe on create or update; off by default). One click suppresses the recipient for the whole workspace.
draft: saved, not scheduled. scheduled: waiting for send_at. sending: being sent now. sent: see sent_message_id. failed: the send failed, see error_message. canceled: a scheduled reply whose conversation was deleted before it went out. Only draft and scheduled drafts can be edited or sent.
Id (msg_…) of the message the draft became when it was sent. Absent on a draft not yet sent; a sent draft whose send could not be fully recorded (see error_message) can lack it too.
Why the draft is failed or canceled. On a sent draft it reports a send that went out but could not be fully recorded. Absent otherwise.
When the draft was created (UTC).
When the draft last changed: an edit, a new schedule, or a status change as it is sent.
Was this page helpful?