Skip to main content
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

const result = await client.drafts.update(
  "dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  {
    subject: "Quick follow-up on your order #10473",
  },
);
console.log(result);
{
  "id": "dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "agent_id": "agt_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "to": ["jordan@example.com"],
  "cc": ["jordan@example.com"],
  "bcc": ["jordan@example.com"],
  "subject": "<subject>",
  "body_text": "<body_text>",
  "body_html": "<body_html>",
  "reply_to": "jordan@example.com",
  "in_reply_to_message_id": "msg_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "thread_id": "thrd_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "tags": [{ "name": "<name>", "value": "<value>" }],
  "send_at": "2026-10-04T12:00:00.000Z",
  "list_unsubscribe": false,
  "status": "draft",
  "sent_message_id": "msg_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "error_message": "<error_message>",
  "created_at": "2026-10-04T12:00:00.000Z",
  "updated_at": "2026-10-04T12:00:00.000Z"
}

Update a draft

Edits a draft or scheduled draft.
PATCH/v1/drafts/{id}scope · manage or draft
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

const result = await client.drafts.update(
  "dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  {
    subject: "Quick follow-up on your order #10473",
  },
);
console.log(result);
{
  "id": "dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "agent_id": "agt_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "to": ["jordan@example.com"],
  "cc": ["jordan@example.com"],
  "bcc": ["jordan@example.com"],
  "subject": "<subject>",
  "body_text": "<body_text>",
  "body_html": "<body_html>",
  "reply_to": "jordan@example.com",
  "in_reply_to_message_id": "msg_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "thread_id": "thrd_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "tags": [{ "name": "<name>", "value": "<value>" }],
  "send_at": "2026-10-04T12:00:00.000Z",
  "list_unsubscribe": false,
  "status": "draft",
  "sent_message_id": "msg_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "error_message": "<error_message>",
  "created_at": "2026-10-04T12:00:00.000Z",
  "updated_at": "2026-10-04T12:00:00.000Z"
}

Path Parameters

idstringrequired

Draft id.

Body Parameters

tostring | string[]

Replaces the recipients: one address, or a list of up to 50. Left out, they stay as they are.

ccstring[]

Replaces the Cc list, up to 50 addresses; [] empties it. Left out, it stays as it is.

bccstring[]

Replaces the Bcc list, up to 50 addresses; [] empties it. Left out, it stays as it is.

subjectstring

Replaces the subject, 1 to 998 characters. Left out, it stays as it is.

body_textstring

Replaces the plain-text body, up to 1,000,000 characters. Left out, it stays as it is.

body_htmlstring

Replaces the HTML body, up to 1,000,000 characters. Left out, it stays as it is.

send_atstring | null

A future time (ISO 8601, UTC, ending in Z) schedules the draft, and null unschedules it back to draft; left out, the schedule stays as it is. Setting a time needs the send scope, and a time not in the future is a 400.

list_unsubscribeboolean

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.

Setting a future send_at schedules it; clearing it returns to draft. A draft that starts sending while it is being changed answers 409 duplicate_resource. Without the send scope a key can neither schedule a draft nor change a scheduled one, except to unschedule it with send_at: null (403 insufficient_scope). A draft that failed only because its agent was paused or archived when it came due can be changed too: a new send_at schedules it again once a paused agent is resumed (422 agent_paused until then; 404 agent_archived for an archived agent, as archiving cannot be undone), and any other change makes it a draft again. A draft cannot carry attachments (422 invalid_field, param attachments). A test key cannot change a draft a live key made (403 live_mode_required).

Response

idstring

Draft id (dft_…).

agent_idstring

Id (agt_…) of the agent the draft is sent from, chosen when it was created.

tostring[]

The draft's recipients, always as a list, even when one address was given.

ccstring[]

The draft's Cc addresses. Absent when cc was never given; [] when it was given empty or a PATCH emptied it.

bccstring[]

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.

subjectstring

The draft's subject. Absent when none was given; the draft is then sent with an empty subject.

body_textstring

The draft's plain-text body. Absent when none was given.

body_htmlstring

The draft's HTML body. Absent when none was given.

reply_tostring

The address replies should go to, as given on create; absent when none was.

in_reply_to_message_idstring

Id of the message this draft answers (msg_… or rcv_…), as given on create; absent when none was.

thread_idstring

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.

tagsobject[]

Name-value labels saved with the draft and copied onto the message when it is sent. Absent when none were given.

Show propertiesHide properties
namestring

The tag's name, as given on the send, reply or draft.

valuestring

The tag's value, as given; it may be an empty string.

send_atstring

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.

list_unsubscribeboolean

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.

statusstring

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.

One of: draft, scheduled, sending, sent, failed, canceled

sent_message_idstring

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.

error_messagestring

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.

created_atstring

When the draft was created (UTC).

updated_atstring

When the draft last changed: an edit, a new schedule, or a status change as it is sent.

Was this page helpful?