Skip to content
machinemail

Drafts

Drafts (unsent messages a person can send or delete) and scheduled sends (send_at).

MethodPathSummary
GET/v0/draftsList Drafts
GET/v0/drafts/{draft_id}Get Draft
GET/v0/inboxes/{inbox_id}/draftsList Drafts
POST/v0/inboxes/{inbox_id}/draftsCreate Draft
GET/v0/inboxes/{inbox_id}/drafts/{draft_id}Get Draft
PATCH/v0/inboxes/{inbox_id}/drafts/{draft_id}Update Draft
DELETE/v0/inboxes/{inbox_id}/drafts/{draft_id}Delete Draft
POST/v0/inboxes/{inbox_id}/drafts/{draft_id}/sendSend Draft
GET/v0/pods/{pod_id}/draftsList Drafts in Pod
GET/v0/pods/{pod_id}/drafts/{draft_id}Get Draft in Pod
GET/v0/pods/{pod_id}/inboxes/{inbox_id}/draftsList Drafts in Pod
POST/v0/pods/{pod_id}/inboxes/{inbox_id}/draftsCreate Draft in Pod
GET/v0/pods/{pod_id}/inboxes/{inbox_id}/drafts/{draft_id}Get Draft in Pod
PATCH/v0/pods/{pod_id}/inboxes/{inbox_id}/drafts/{draft_id}Update Draft in Pod
DELETE/v0/pods/{pod_id}/inboxes/{inbox_id}/drafts/{draft_id}Delete Draft in Pod
POST/v0/pods/{pod_id}/inboxes/{inbox_id}/drafts/{draft_id}/sendSend Draft in Pod

List Drafts

http
GET /v0/drafts

Drafts of every inbox in scope, newest first. The labels filter is not supported.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_read.

Query parameters

limitinteger
Maximum number of items to return. Default 50, maximum 500; larger values are capped.
page_tokenstring
next_page_token from the previous page.
beforestring (date-time)
Only drafts created before this time.
afterstring (date-time)
Only drafts created after this time.
ascendingboolean
Sort oldest first.

Response

200 A page of drafts (application/json)

countintegerRequired
Number of items returned.
limitinteger
Maximum number of items per page. Default 50, maximum 500; larger values are capped.
next_page_tokenstring
Page token for pagination. Absent on the last page.
draftsDraftItem[]Required
Ordered by created_at, newest first unless ascending is set.

Each item of drafts is a DraftItem:

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation.
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references.
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/drafts" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "drafts": [
    {
      "inbox_id": "agent@machinemail.dev",
      "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
      "labels": ["UNREAD"],
      "to": ["customer@example.com"],
      "cc": ["team@example.com"],
      "bcc": ["audit@example.com"],
      "subject": "Order #1042",
      "preview": "Thanks for the quick reply.",
      "attachments": [
        {
          "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
          "filename": "invoice.pdf",
          "size": 2048,
          "content_type": "application/pdf",
          "content_disposition": "string",
          "content_id": "string"
        }
      ],
      "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "send_status": "scheduled",
      "send_at": "2026-10-01T12:00:00.000Z",
      "updated_at": "2026-10-01T12:00:00.000Z",
      "client_id": "my-client-id",
      "reply_to": ["agent@machinemail.dev"],
      "text": "Thanks for the quick reply.",
      "html": "<p>Thanks for the quick reply.</p>",
      "references": ["string"],
      "created_at": "2026-10-01T12:00:00.000Z",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
    }
  ]
}

Get Draft

http
GET /v0/drafts/{draft_id}

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_read.

Path parameters

draft_idstringRequired
ID of the draft.

Response

200 The draft (application/json)

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation (idempotency key).
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references (set from in_reply_to).
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Each item of attachments is a Attachment:

attachment_idstringRequired
ID of the attachment.
filenamestring
Filename of the attachment.
sizeintegerRequired
Size of the attachment in bytes.
content_typestring
Content type of the attachment.
content_dispositionstring
Content disposition of the attachment (inline or attachment).
content_idstring
Content ID of the attachment.

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/drafts/drf_01k6x3b7hn0000e1n7qv3z6g8j" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
  "labels": ["UNREAD"],
  "to": ["customer@example.com"],
  "cc": ["team@example.com"],
  "bcc": ["audit@example.com"],
  "subject": "Order #1042",
  "preview": "Thanks for the quick reply.",
  "attachments": [
    {
      "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
      "filename": "invoice.pdf",
      "size": 2048,
      "content_type": "application/pdf",
      "content_disposition": "string",
      "content_id": "string"
    }
  ],
  "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "send_status": "scheduled",
  "send_at": "2026-10-01T12:00:00.000Z",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "client_id": "my-client-id",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "references": ["string"],
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
}

List Drafts

http
GET /v0/inboxes/{inbox_id}/drafts

Drafts of the inbox, newest first. The labels filter is not supported.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_read.

Path parameters

inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).

Query parameters

limitinteger
Maximum number of items to return. Default 50, maximum 500; larger values are capped.
page_tokenstring
next_page_token from the previous page.
beforestring (date-time)
Only drafts created before this time.
afterstring (date-time)
Only drafts created after this time.
ascendingboolean
Sort oldest first.

Response

200 A page of drafts (application/json)

countintegerRequired
Number of items returned.
limitinteger
Maximum number of items per page. Default 50, maximum 500; larger values are capped.
next_page_tokenstring
Page token for pagination. Absent on the last page.
draftsDraftItem[]Required
Ordered by created_at, newest first unless ascending is set.

Each item of drafts is a DraftItem:

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation.
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references.
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/drafts" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "drafts": [
    {
      "inbox_id": "agent@machinemail.dev",
      "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
      "labels": ["UNREAD"],
      "to": ["customer@example.com"],
      "cc": ["team@example.com"],
      "bcc": ["audit@example.com"],
      "subject": "Order #1042",
      "preview": "Thanks for the quick reply.",
      "attachments": [
        {
          "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
          "filename": "invoice.pdf",
          "size": 2048,
          "content_type": "application/pdf",
          "content_disposition": "string",
          "content_id": "string"
        }
      ],
      "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "send_status": "scheduled",
      "send_at": "2026-10-01T12:00:00.000Z",
      "updated_at": "2026-10-01T12:00:00.000Z",
      "client_id": "my-client-id",
      "reply_to": ["agent@machinemail.dev"],
      "text": "Thanks for the quick reply.",
      "html": "<p>Thanks for the quick reply.</p>",
      "references": ["string"],
      "created_at": "2026-10-01T12:00:00.000Z",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
    }
  ]
}

Create Draft

http
POST /v0/inboxes/{inbox_id}/drafts

With send_at the draft is scheduled: a background worker sends it at that time (send_status: scheduled). A scheduled send that fails sets send_status: failed and is not retried.

Reply drafts: set in_reply_to to a message ID in this inbox; recipients are not filled in for you. Forward drafts (forward_of) and reply_all are not supported.

A message can have at most 50 recipients (deployment default; MachineMail staff can change it, and the error message states the cap in force): to, cc and bcc together, each address counted once. An unclaimed sandbox inbox can have at most 5 (deployment default). More is a 400 validation error with param: "to". The cap is checked when the draft is created or updated, and again when it is sent: a scheduled draft over the cap at send time gets send_status: failed.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_create.

Path parameters

inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).

Request body

Content type: application/json.

labelsstring[]
Labels of the draft.
reply_tostring | string[]
Reply-to addresses: one address or a list.
tostring | string[]
Recipient addresses: one address or a list.
ccstring | string[]
CC addresses: one address or a list.
bccstring | string[]
BCC addresses: one address or a list.
subjectstring
Subject.
textstring
Plain text body.
htmlstring
HTML body.
attachmentsSendAttachment[]
Attachments, sent with the draft. Each needs content or url; a url is fetched when the draft is sent.
in_reply_tostring
ID of a message in this inbox to reply to: the sent message gets its In-Reply-To and References headers.
send_atstring (date-time) | null
Schedule the draft: it is sent automatically at this time (send_status: scheduled). null or absent: not scheduled.
client_idstring
Idempotency key: a create with a client_id already used in the organization returns that draft with 200.

Each item of attachments is a SendAttachment:

filenamestring
Filename of the attachment. Defaults to the last segment of url.
content_typestring
Content type of the attachment. Defaults to the Content-Type of the url response.
content_disposition"inline" | "attachment"
Content disposition of the attachment.
content_idstring
Content ID, for inline images referenced as cid: in the HTML body.
contentstring
Base64 encoded content of the attachment.
urlstring
URL the API downloads the attachment from: public http(s) only, no redirects, at most 25 MB, 20 second timeout.

Response

200 A draft with this client_id already exists; it is returned unchanged. (application/json)

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation (idempotency key).
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references (set from in_reply_to).
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Each item of attachments is a Attachment:

attachment_idstringRequired
ID of the attachment.
filenamestring
Filename of the attachment.
sizeintegerRequired
Size of the attachment in bytes.
content_typestring
Content type of the attachment.
content_dispositionstring
Content disposition of the attachment (inline or attachment).
content_idstring
Content ID of the attachment.

201 Created (application/json)

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation (idempotency key).
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references (set from in_reply_to).
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Each item of attachments is a Attachment:

attachment_idstringRequired
ID of the attachment.
filenamestring
Filename of the attachment.
sizeintegerRequired
Size of the attachment in bytes.
content_typestring
Content type of the attachment.
content_dispositionstring
Content disposition of the attachment (inline or attachment).
content_idstring
Content ID of the attachment.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X POST "https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/drafts" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "customer@example.com",
  "subject": "Order #1042",
  "text": "Thanks for the quick reply."
}'
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
  "labels": ["UNREAD"],
  "to": ["customer@example.com"],
  "cc": ["team@example.com"],
  "bcc": ["audit@example.com"],
  "subject": "Order #1042",
  "preview": "Thanks for the quick reply.",
  "attachments": [
    {
      "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
      "filename": "invoice.pdf",
      "size": 2048,
      "content_type": "application/pdf",
      "content_disposition": "string",
      "content_id": "string"
    }
  ],
  "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "send_status": "scheduled",
  "send_at": "2026-10-01T12:00:00.000Z",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "client_id": "my-client-id",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "references": ["string"],
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
}

Get Draft

http
GET /v0/inboxes/{inbox_id}/drafts/{draft_id}

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_read.

Path parameters

inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).
draft_idstringRequired
ID of the draft.

Response

200 The draft (application/json)

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation (idempotency key).
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references (set from in_reply_to).
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Each item of attachments is a Attachment:

attachment_idstringRequired
ID of the attachment.
filenamestring
Filename of the attachment.
sizeintegerRequired
Size of the attachment in bytes.
content_typestring
Content type of the attachment.
content_dispositionstring
Content disposition of the attachment (inline or attachment).
content_idstring
Content ID of the attachment.

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/drafts/drf_01k6x3b7hn0000e1n7qv3z6g8j" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
  "labels": ["UNREAD"],
  "to": ["customer@example.com"],
  "cc": ["team@example.com"],
  "bcc": ["audit@example.com"],
  "subject": "Order #1042",
  "preview": "Thanks for the quick reply.",
  "attachments": [
    {
      "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
      "filename": "invoice.pdf",
      "size": 2048,
      "content_type": "application/pdf",
      "content_disposition": "string",
      "content_id": "string"
    }
  ],
  "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "send_status": "scheduled",
  "send_at": "2026-10-01T12:00:00.000Z",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "client_id": "my-client-id",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "references": ["string"],
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
}

Update Draft

http
PATCH /v0/inboxes/{inbox_id}/drafts/{draft_id}

Fields you omit are unchanged; null clears a field. in_reply_to cannot be changed.

A message can have at most 50 recipients (deployment default; MachineMail staff can change it, and the error message states the cap in force): to, cc and bcc together, each address counted once. An unclaimed sandbox inbox can have at most 5 (deployment default). More is a 400 validation error with param: "to".

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_update.

Path parameters

inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).
draft_idstringRequired
ID of the draft.

Request body

Content type: application/json.

reply_tostring | string[] | null
Reply-to addresses. null clears them.
tostring | string[] | null
Recipient addresses. null clears them.
ccstring | string[] | null
CC addresses. null clears them.
bccstring | string[] | null
BCC addresses. null clears them.
subjectstring | null
Subject. null clears it.
textstring | null
Plain text body. null clears it.
htmlstring | null
HTML body. null clears it.
add_attachmentsSendAttachment[]
Attachments to add. Each needs content or url.
remove_attachmentsstring[]
IDs of attachments to remove. Unknown IDs are ignored.
add_labelsstring[]
Labels to add.
remove_labelsstring[]
Labels to remove (applied after add_labels).
send_atstring (date-time) | null
Schedule (or reschedule) the draft. null unschedules it.

Each item of add_attachments is a SendAttachment:

filenamestring
Filename of the attachment. Defaults to the last segment of url.
content_typestring
Content type of the attachment. Defaults to the Content-Type of the url response.
content_disposition"inline" | "attachment"
Content disposition of the attachment.
content_idstring
Content ID, for inline images referenced as cid: in the HTML body.
contentstring
Base64 encoded content of the attachment.
urlstring
URL the API downloads the attachment from: public http(s) only, no redirects, at most 25 MB, 20 second timeout.

Response

200 The updated draft (application/json)

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation (idempotency key).
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references (set from in_reply_to).
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Each item of attachments is a Attachment:

attachment_idstringRequired
ID of the attachment.
filenamestring
Filename of the attachment.
sizeintegerRequired
Size of the attachment in bytes.
content_typestring
Content type of the attachment.
content_dispositionstring
Content disposition of the attachment (inline or attachment).
content_idstring
Content ID of the attachment.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X PATCH "https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/drafts/drf_01k6x3b7hn0000e1n7qv3z6g8j" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "customer@example.com",
  "subject": "Order #1042",
  "text": "Thanks for the quick reply.",
  "add_labels": [
    "string"
  ]
}'
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
  "labels": ["UNREAD"],
  "to": ["customer@example.com"],
  "cc": ["team@example.com"],
  "bcc": ["audit@example.com"],
  "subject": "Order #1042",
  "preview": "Thanks for the quick reply.",
  "attachments": [
    {
      "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
      "filename": "invoice.pdf",
      "size": 2048,
      "content_type": "application/pdf",
      "content_disposition": "string",
      "content_id": "string"
    }
  ],
  "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "send_status": "scheduled",
  "send_at": "2026-10-01T12:00:00.000Z",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "client_id": "my-client-id",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "references": ["string"],
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
}

Delete Draft

http
DELETE /v0/inboxes/{inbox_id}/drafts/{draft_id}

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_delete.

Path parameters

inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).
draft_idstringRequired
ID of the draft.

Response

200 Deleted (application/json)

oktrueRequired

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X DELETE "https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/drafts/drf_01k6x3b7hn0000e1n7qv3z6g8j" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "ok": true
}

Send Draft

http
POST /v0/inboxes/{inbox_id}/drafts/{draft_id}/send

Sends the draft now and deletes it; a draft.sent and a message.sent event are emitted. The sent message gets the draft labels plus add_labels, minus remove_labels.

Suppressed recipients and recipients on a send block list return 403, a paused inbox 403. A draft already being sent returns 409; 501 when the deployment has no email transport.

A message can have at most 50 recipients (deployment default; MachineMail staff can change it, and the error message states the cap in force): to, cc and bcc together, each address counted once. An unclaimed sandbox inbox can have at most 5 (deployment default). More is a 400 validation error with param: "to".

An unclaimed sandbox agent can send a limited number of messages to a limited number of different recipients per rolling 24 hours (deployment defaults 10 and 10): 429 with Retry-After.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_send.

Path parameters

inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).
draft_idstringRequired
ID of the draft.

Request body

Content type: application/json.

add_labelsstring | string[]
Label or labels to add.
remove_labelsstring | string[]
Label or labels to remove.

Response

201 Sent (application/json)

message_idstringRequired
ID of the message.
thread_idstringRequired
ID of the thread.
timestampstring (date-time)Required
When the message was sent.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
409Conflicts with an existing resource.
429Unclaimed sandbox agent over a send cap: messages or different recipients per rolling 24 hours (deployment defaults 10 and 10; the message states the cap in force). Retry-After says when the next send fits. Claiming the inbox lifts the caps.
500Unexpected server error.
501Not implemented by this deployment.

Error bodies use the error envelope.

Example

Request
curl -X POST "https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/drafts/drf_01k6x3b7hn0000e1n7qv3z6g8j/send" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "add_labels": "string"
}'
Response 201
{
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "timestamp": "2026-10-01T12:00:00.000Z"
}

List Drafts in Pod

http
GET /v0/pods/{pod_id}/drafts

Same as List Drafts (GET /v0/drafts), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_read.

Path parameters

pod_idstringRequired
ID of the pod.

Query parameters

limitinteger
Maximum number of items to return. Default 50, maximum 500; larger values are capped.
page_tokenstring
next_page_token from the previous page.
beforestring (date-time)
Only drafts created before this time.
afterstring (date-time)
Only drafts created after this time.
ascendingboolean
Sort oldest first.

Response

200 A page of drafts (application/json)

countintegerRequired
Number of items returned.
limitinteger
Maximum number of items per page. Default 50, maximum 500; larger values are capped.
next_page_tokenstring
Page token for pagination. Absent on the last page.
draftsDraftItem[]Required
Ordered by created_at, newest first unless ascending is set.

Each item of drafts is a DraftItem:

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation.
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references.
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/drafts" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "drafts": [
    {
      "inbox_id": "agent@machinemail.dev",
      "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
      "labels": ["UNREAD"],
      "to": ["customer@example.com"],
      "cc": ["team@example.com"],
      "bcc": ["audit@example.com"],
      "subject": "Order #1042",
      "preview": "Thanks for the quick reply.",
      "attachments": [
        {
          "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
          "filename": "invoice.pdf",
          "size": 2048,
          "content_type": "application/pdf",
          "content_disposition": "string",
          "content_id": "string"
        }
      ],
      "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "send_status": "scheduled",
      "send_at": "2026-10-01T12:00:00.000Z",
      "updated_at": "2026-10-01T12:00:00.000Z",
      "client_id": "my-client-id",
      "reply_to": ["agent@machinemail.dev"],
      "text": "Thanks for the quick reply.",
      "html": "<p>Thanks for the quick reply.</p>",
      "references": ["string"],
      "created_at": "2026-10-01T12:00:00.000Z",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
    }
  ]
}

Get Draft in Pod

http
GET /v0/pods/{pod_id}/drafts/{draft_id}

Same as Get Draft (GET /v0/drafts/{draft_id}), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_read.

Path parameters

pod_idstringRequired
ID of the pod.
draft_idstringRequired
ID of the draft.

Response

200 The draft (application/json)

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation (idempotency key).
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references (set from in_reply_to).
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Each item of attachments is a Attachment:

attachment_idstringRequired
ID of the attachment.
filenamestring
Filename of the attachment.
sizeintegerRequired
Size of the attachment in bytes.
content_typestring
Content type of the attachment.
content_dispositionstring
Content disposition of the attachment (inline or attachment).
content_idstring
Content ID of the attachment.

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/drafts/drf_01k6x3b7hn0000e1n7qv3z6g8j" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
  "labels": ["UNREAD"],
  "to": ["customer@example.com"],
  "cc": ["team@example.com"],
  "bcc": ["audit@example.com"],
  "subject": "Order #1042",
  "preview": "Thanks for the quick reply.",
  "attachments": [
    {
      "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
      "filename": "invoice.pdf",
      "size": 2048,
      "content_type": "application/pdf",
      "content_disposition": "string",
      "content_id": "string"
    }
  ],
  "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "send_status": "scheduled",
  "send_at": "2026-10-01T12:00:00.000Z",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "client_id": "my-client-id",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "references": ["string"],
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
}

List Drafts in Pod

http
GET /v0/pods/{pod_id}/inboxes/{inbox_id}/drafts

Same as List Drafts (GET /v0/inboxes/{inbox_id}/drafts), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_read.

Path parameters

pod_idstringRequired
ID of the pod.
inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).

Query parameters

limitinteger
Maximum number of items to return. Default 50, maximum 500; larger values are capped.
page_tokenstring
next_page_token from the previous page.
beforestring (date-time)
Only drafts created before this time.
afterstring (date-time)
Only drafts created after this time.
ascendingboolean
Sort oldest first.

Response

200 A page of drafts (application/json)

countintegerRequired
Number of items returned.
limitinteger
Maximum number of items per page. Default 50, maximum 500; larger values are capped.
next_page_tokenstring
Page token for pagination. Absent on the last page.
draftsDraftItem[]Required
Ordered by created_at, newest first unless ascending is set.

Each item of drafts is a DraftItem:

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation.
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references.
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/inboxes/agent@machinemail.dev/drafts" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "drafts": [
    {
      "inbox_id": "agent@machinemail.dev",
      "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
      "labels": ["UNREAD"],
      "to": ["customer@example.com"],
      "cc": ["team@example.com"],
      "bcc": ["audit@example.com"],
      "subject": "Order #1042",
      "preview": "Thanks for the quick reply.",
      "attachments": [
        {
          "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
          "filename": "invoice.pdf",
          "size": 2048,
          "content_type": "application/pdf",
          "content_disposition": "string",
          "content_id": "string"
        }
      ],
      "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "send_status": "scheduled",
      "send_at": "2026-10-01T12:00:00.000Z",
      "updated_at": "2026-10-01T12:00:00.000Z",
      "client_id": "my-client-id",
      "reply_to": ["agent@machinemail.dev"],
      "text": "Thanks for the quick reply.",
      "html": "<p>Thanks for the quick reply.</p>",
      "references": ["string"],
      "created_at": "2026-10-01T12:00:00.000Z",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
    }
  ]
}

Create Draft in Pod

http
POST /v0/pods/{pod_id}/inboxes/{inbox_id}/drafts

Same as Create Draft (POST /v0/inboxes/{inbox_id}/drafts), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_create.

Path parameters

pod_idstringRequired
ID of the pod.
inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).

Request body

Content type: application/json.

labelsstring[]
Labels of the draft.
reply_tostring | string[]
Reply-to addresses: one address or a list.
tostring | string[]
Recipient addresses: one address or a list.
ccstring | string[]
CC addresses: one address or a list.
bccstring | string[]
BCC addresses: one address or a list.
subjectstring
Subject.
textstring
Plain text body.
htmlstring
HTML body.
attachmentsSendAttachment[]
Attachments, sent with the draft. Each needs content or url; a url is fetched when the draft is sent.
in_reply_tostring
ID of a message in this inbox to reply to: the sent message gets its In-Reply-To and References headers.
send_atstring (date-time) | null
Schedule the draft: it is sent automatically at this time (send_status: scheduled). null or absent: not scheduled.
client_idstring
Idempotency key: a create with a client_id already used in the organization returns that draft with 200.

Each item of attachments is a SendAttachment:

filenamestring
Filename of the attachment. Defaults to the last segment of url.
content_typestring
Content type of the attachment. Defaults to the Content-Type of the url response.
content_disposition"inline" | "attachment"
Content disposition of the attachment.
content_idstring
Content ID, for inline images referenced as cid: in the HTML body.
contentstring
Base64 encoded content of the attachment.
urlstring
URL the API downloads the attachment from: public http(s) only, no redirects, at most 25 MB, 20 second timeout.

Response

200 A draft with this client_id already exists; it is returned unchanged. (application/json)

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation (idempotency key).
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references (set from in_reply_to).
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Each item of attachments is a Attachment:

attachment_idstringRequired
ID of the attachment.
filenamestring
Filename of the attachment.
sizeintegerRequired
Size of the attachment in bytes.
content_typestring
Content type of the attachment.
content_dispositionstring
Content disposition of the attachment (inline or attachment).
content_idstring
Content ID of the attachment.

201 Created (application/json)

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation (idempotency key).
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references (set from in_reply_to).
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Each item of attachments is a Attachment:

attachment_idstringRequired
ID of the attachment.
filenamestring
Filename of the attachment.
sizeintegerRequired
Size of the attachment in bytes.
content_typestring
Content type of the attachment.
content_dispositionstring
Content disposition of the attachment (inline or attachment).
content_idstring
Content ID of the attachment.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X POST "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/inboxes/agent@machinemail.dev/drafts" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "customer@example.com",
  "subject": "Order #1042",
  "text": "Thanks for the quick reply."
}'
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
  "labels": ["UNREAD"],
  "to": ["customer@example.com"],
  "cc": ["team@example.com"],
  "bcc": ["audit@example.com"],
  "subject": "Order #1042",
  "preview": "Thanks for the quick reply.",
  "attachments": [
    {
      "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
      "filename": "invoice.pdf",
      "size": 2048,
      "content_type": "application/pdf",
      "content_disposition": "string",
      "content_id": "string"
    }
  ],
  "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "send_status": "scheduled",
  "send_at": "2026-10-01T12:00:00.000Z",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "client_id": "my-client-id",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "references": ["string"],
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
}

Get Draft in Pod

http
GET /v0/pods/{pod_id}/inboxes/{inbox_id}/drafts/{draft_id}

Same as Get Draft (GET /v0/inboxes/{inbox_id}/drafts/{draft_id}), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_read.

Path parameters

pod_idstringRequired
ID of the pod.
inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).
draft_idstringRequired
ID of the draft.

Response

200 The draft (application/json)

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation (idempotency key).
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references (set from in_reply_to).
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Each item of attachments is a Attachment:

attachment_idstringRequired
ID of the attachment.
filenamestring
Filename of the attachment.
sizeintegerRequired
Size of the attachment in bytes.
content_typestring
Content type of the attachment.
content_dispositionstring
Content disposition of the attachment (inline or attachment).
content_idstring
Content ID of the attachment.

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/inboxes/agent@machinemail.dev/drafts/drf_01k6x3b7hn0000e1n7qv3z6g8j" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
  "labels": ["UNREAD"],
  "to": ["customer@example.com"],
  "cc": ["team@example.com"],
  "bcc": ["audit@example.com"],
  "subject": "Order #1042",
  "preview": "Thanks for the quick reply.",
  "attachments": [
    {
      "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
      "filename": "invoice.pdf",
      "size": 2048,
      "content_type": "application/pdf",
      "content_disposition": "string",
      "content_id": "string"
    }
  ],
  "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "send_status": "scheduled",
  "send_at": "2026-10-01T12:00:00.000Z",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "client_id": "my-client-id",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "references": ["string"],
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
}

Update Draft in Pod

http
PATCH /v0/pods/{pod_id}/inboxes/{inbox_id}/drafts/{draft_id}

Same as Update Draft (PATCH /v0/inboxes/{inbox_id}/drafts/{draft_id}), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_update.

Path parameters

pod_idstringRequired
ID of the pod.
inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).
draft_idstringRequired
ID of the draft.

Request body

Content type: application/json.

reply_tostring | string[] | null
Reply-to addresses. null clears them.
tostring | string[] | null
Recipient addresses. null clears them.
ccstring | string[] | null
CC addresses. null clears them.
bccstring | string[] | null
BCC addresses. null clears them.
subjectstring | null
Subject. null clears it.
textstring | null
Plain text body. null clears it.
htmlstring | null
HTML body. null clears it.
add_attachmentsSendAttachment[]
Attachments to add. Each needs content or url.
remove_attachmentsstring[]
IDs of attachments to remove. Unknown IDs are ignored.
add_labelsstring[]
Labels to add.
remove_labelsstring[]
Labels to remove (applied after add_labels).
send_atstring (date-time) | null
Schedule (or reschedule) the draft. null unschedules it.

Each item of add_attachments is a SendAttachment:

filenamestring
Filename of the attachment. Defaults to the last segment of url.
content_typestring
Content type of the attachment. Defaults to the Content-Type of the url response.
content_disposition"inline" | "attachment"
Content disposition of the attachment.
content_idstring
Content ID, for inline images referenced as cid: in the HTML body.
contentstring
Base64 encoded content of the attachment.
urlstring
URL the API downloads the attachment from: public http(s) only, no redirects, at most 25 MB, 20 second timeout.

Response

200 The updated draft (application/json)

inbox_idstringRequired
ID of the inbox.
draft_idstringRequired
ID of the draft.
labelsstring[]Required
Labels of the draft. The sent message gets them.
tostring[]
Recipient addresses.
ccstring[]
CC addresses.
bccstring[]
BCC addresses.
subjectstring
Subject of the draft.
previewstring
Text preview of the draft.
attachmentsAttachment[]
Attachments of the draft. size is 0 for attachments given by url until the draft is sent (the URL is fetched then).
in_reply_tostring
ID of the message being replied to.
send_status"scheduled" | "sending" | "failed"
scheduled while waiting for send_at, sending while a sender holds it, failed when a scheduled send failed (it is not retried). Absent on drafts without send_at.
send_atstring (date-time)
Time at which the draft is sent automatically.
updated_atstring (date-time)Required
Time at which the draft was last updated.
client_idstring
Client ID given at creation (idempotency key).
reply_tostring[]
Reply-to addresses.
textstring
Plain text body.
htmlstring
HTML body.
referencesstring[]
Message IDs the draft references (set from in_reply_to).
created_atstring (date-time)Required
Time at which the draft was created.
pod_idstringRequired
ID of the pod.

Each item of attachments is a Attachment:

attachment_idstringRequired
ID of the attachment.
filenamestring
Filename of the attachment.
sizeintegerRequired
Size of the attachment in bytes.
content_typestring
Content type of the attachment.
content_dispositionstring
Content disposition of the attachment (inline or attachment).
content_idstring
Content ID of the attachment.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X PATCH "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/inboxes/agent@machinemail.dev/drafts/drf_01k6x3b7hn0000e1n7qv3z6g8j" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "customer@example.com",
  "subject": "Order #1042",
  "text": "Thanks for the quick reply.",
  "add_labels": [
    "string"
  ]
}'
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "draft_id": "drf_01k6x3b7hn0000e1n7qv3z6g8j",
  "labels": ["UNREAD"],
  "to": ["customer@example.com"],
  "cc": ["team@example.com"],
  "bcc": ["audit@example.com"],
  "subject": "Order #1042",
  "preview": "Thanks for the quick reply.",
  "attachments": [
    {
      "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
      "filename": "invoice.pdf",
      "size": 2048,
      "content_type": "application/pdf",
      "content_disposition": "string",
      "content_id": "string"
    }
  ],
  "in_reply_to": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "send_status": "scheduled",
  "send_at": "2026-10-01T12:00:00.000Z",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "client_id": "my-client-id",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "references": ["string"],
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f"
}

Delete Draft in Pod

http
DELETE /v0/pods/{pod_id}/inboxes/{inbox_id}/drafts/{draft_id}

Same as Delete Draft (DELETE /v0/inboxes/{inbox_id}/drafts/{draft_id}), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_delete.

Path parameters

pod_idstringRequired
ID of the pod.
inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).
draft_idstringRequired
ID of the draft.

Response

200 Deleted (application/json)

oktrueRequired

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X DELETE "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/inboxes/agent@machinemail.dev/drafts/drf_01k6x3b7hn0000e1n7qv3z6g8j" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "ok": true
}

Send Draft in Pod

http
POST /v0/pods/{pod_id}/inboxes/{inbox_id}/drafts/{draft_id}/send

Same as Send Draft (POST /v0/inboxes/{inbox_id}/drafts/{draft_id}/send), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: draft_send.

Path parameters

pod_idstringRequired
ID of the pod.
inbox_idstringRequired
ID of the inbox: its email address, as in AgentMail (inbox_id == email).
draft_idstringRequired
ID of the draft.

Request body

Content type: application/json.

add_labelsstring | string[]
Label or labels to add.
remove_labelsstring | string[]
Label or labels to remove.

Response

201 Sent (application/json)

message_idstringRequired
ID of the message.
thread_idstringRequired
ID of the thread.
timestampstring (date-time)Required
When the message was sent.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
409Conflicts with an existing resource.
429Unclaimed sandbox agent over a send cap: messages or different recipients per rolling 24 hours (deployment defaults 10 and 10; the message states the cap in force). Retry-After says when the next send fits. Claiming the inbox lifts the caps.
500Unexpected server error.
501Not implemented by this deployment.

Error bodies use the error envelope.

Example

Request
curl -X POST "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/inboxes/agent@machinemail.dev/drafts/drf_01k6x3b7hn0000e1n7qv3z6g8j/send" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "add_labels": "string"
}'
Response 201
{
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "timestamp": "2026-10-01T12:00:00.000Z"
}