Skip to content
machinemail

Messages

Send, receive, search and manage messages.

MethodPathSummary
GET/v0/inboxes/{inbox_id}/messagesList Messages
POST/v0/inboxes/{inbox_id}/messages/batch-getBatch Get Messages
POST/v0/inboxes/{inbox_id}/messages/batch-updateBatch Update Messages
GET/v0/inboxes/{inbox_id}/messages/searchSearch Messages
POST/v0/inboxes/{inbox_id}/messages/sendSend Message
GET/v0/inboxes/{inbox_id}/messages/{message_id}Get Message
PATCH/v0/inboxes/{inbox_id}/messages/{message_id}Update Message
DELETE/v0/inboxes/{inbox_id}/messages/{message_id}Delete Message
GET/v0/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}Get Attachment
GET/v0/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}/downloadDownload Attachment
POST/v0/inboxes/{inbox_id}/messages/{message_id}/forwardForward Message
GET/v0/inboxes/{inbox_id}/messages/{message_id}/rawGet Raw Message
POST/v0/inboxes/{inbox_id}/messages/{message_id}/replyReply To Message
POST/v0/inboxes/{inbox_id}/messages/{message_id}/reply-allReply All Message
GET/v0/pods/{pod_id}/inboxes/{inbox_id}/messagesList Messages in Pod
POST/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/batch-getBatch Get Messages in Pod
POST/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/batch-updateBatch Update Messages in Pod
GET/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/searchSearch Messages in Pod
POST/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/sendSend Message in Pod
GET/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}Get Message in Pod
PATCH/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}Update Message in Pod
DELETE/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}Delete Message in Pod
GET/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}Get Attachment in Pod
GET/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}/downloadDownload Attachment in Pod
POST/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/forwardForward Message in Pod
GET/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/rawGet Raw Message in Pod
POST/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/replyReply To Message in Pod
POST/v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/reply-allReply All Message in Pod

List Messages

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

Messages in the inbox, newest first.

Spam, blocked, trash, quarantined and unauthenticated messages are hidden unless you pass the matching include_* flag or ask for the label in labels. Spam, blocked, trash and unauthenticated also need the matching label_*_read permission; without it the flag is ignored.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: message_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.
ascendingboolean
Sort oldest first.
labelsstring[]
Only items with any of these labels. Asking for SPAM, BLOCKED, TRASH, QUARANTINE or UNAUTHENTICATED includes them.
beforestring (date-time)
Only items with a timestamp before this time.
afterstring (date-time)
Only items with a timestamp after this time.
include_spamboolean
Include spam (needs label_spam_read; ignored without it).
include_blockedboolean
Include blocked mail (needs label_blocked_read; ignored without it).
include_unauthenticatedboolean
Include unauthenticated mail (needs label_unauthenticated_read; ignored without it).
include_trashboolean
Include trash (needs label_trash_read; ignored without it).
include_quarantineboolean
Include quarantined messages (trust level quarantined).
qstring
Full-text filter: the words must appear in the subject, sender, recipients, body or attachment file names. Combines with the other filters.

Response

200 A page of messages (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.
messagesMessageItem[]Required
Ordered by timestamp, newest first unless ascending is set.

Each item of messages is a MessageItem:

inbox_idstringRequired
ID of the inbox.
thread_idstringRequired
ID of the thread.
message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message.
timestampstring (date-time)Required
Time at which the message was sent or received.
fromstringRequired
Address of the sender. In format username@domain.com or Display Name <username@domain.com>.
tostring[]Required
Addresses of the recipients. In format username@domain.com or Display Name <username@domain.com>.
ccstring[]
Addresses of the CC recipients. In format username@domain.com or Display Name <username@domain.com>.
bccstring[]
Addresses of the BCC recipients. In format username@domain.com or Display Name <username@domain.com>.
subjectstring
Subject of the message.
previewstring
Text preview of the message.
attachmentsAttachment[]
Attachments of the message.
in_reply_tostring
ID of the message being replied to.
referencesstring[]
IDs of previous messages in the thread.
headersRecord<string, string>
Headers of the message.
sizeintegerRequired
Size of the message in bytes.
updated_atstring (date-time)Required
Time at which the message was last updated.
created_atstring (date-time)Required
Time at which the message was created.
pod_idstringRequired
ID of the pod.
direction"inbound" | "outbound"Required
Whether the message was received or sent.
delivery_status"sent" | "delivered" | "bounced" | "complained"
Outbound only: last delivery state reported by the transport.
trust_level"verified" | "known" | "unknown" | "suspicious" | "quarantined"
Inbound only: trust.level, for list badges.

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/messages" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "messages": [
    {
      "inbox_id": "agent@machinemail.dev",
      "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
      "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "labels": ["UNREAD"],
      "timestamp": "2026-10-01T12:00:00.000Z",
      "from": "Support Agent <agent@machinemail.dev>",
      "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",
      "references": ["string"],
      "headers": {
        "key": "value"
      },
      "size": 2048,
      "updated_at": "2026-10-01T12:00:00.000Z",
      "created_at": "2026-10-01T12:00:00.000Z",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
      "direction": "inbound",
      "delivery_status": "sent",
      "trust_level": "verified"
    }
  ]
}

Batch Get Messages

http
POST /v0/inboxes/{inbox_id}/messages/batch-get

Up to 100 messages by ID in one request, as full Message objects. Duplicate IDs are read once; IDs past the first 100 distinct ones are dropped. Missing IDs and IDs from other inboxes are omitted: compare count with limit (the number of IDs you sent).

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

Path parameters

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

Request body

Content type: application/json.

message_idsstring[]Required
IDs of the messages to fetch. Only the first 100 distinct IDs are read.

Response

200 The messages found (application/json)

limitintegerRequired
Number of IDs in the request.
countintegerRequired
Number of messages returned.
messagesMessage[]Required
Found messages, in request order. IDs not found in the inbox are omitted.

Each item of messages is a Message:

inbox_idstringRequired
ID of the inbox.
thread_idstringRequired
ID of the thread.
message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message.
timestampstring (date-time)Required
Time at which the message was sent or received.
fromstringRequired
Address of the sender. In format username@domain.com or Display Name <username@domain.com>.
tostring[]Required
Addresses of the recipients. In format username@domain.com or Display Name <username@domain.com>.
ccstring[]
Addresses of the CC recipients. In format username@domain.com or Display Name <username@domain.com>.
bccstring[]
Addresses of the BCC recipients. In format username@domain.com or Display Name <username@domain.com>.
subjectstring
Subject of the message.
previewstring
Text preview of the message.
attachmentsAttachment[]
Attachments of the message.
in_reply_tostring
ID of the message being replied to.
referencesstring[]
IDs of previous messages in the thread.
headersRecord<string, string>
Headers of the message.
sizeintegerRequired
Size of the message in bytes.
updated_atstring (date-time)Required
Time at which the message was last updated.
created_atstring (date-time)Required
Time at which the message was created.
pod_idstringRequired
ID of the pod.
direction"inbound" | "outbound"Required
Whether the message was received or sent.
delivery_status"sent" | "delivered" | "bounced" | "complained"
Outbound only: last delivery state reported by the transport.
trust_level"verified" | "known" | "unknown" | "suspicious" | "quarantined"
Inbound only: trust.level, for list badges.
reply_tostring[]
Reply-to addresses. In format username@domain.com or Display Name <username@domain.com>.
textstring
Plain text body. Untrusted: agents should read trust.content.text or extracted_text.
htmlstring
HTML body. Untrusted.
extracted_textstring
New text content, without quoted replies.
extracted_htmlstring
New HTML content, without quoted replies.
received_via"raw"
raw when the message was injected with POST /inbound/raw (authentication not verified).
Trust report of an inbound message.

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/messages/batch-get" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "message_ids": [
    "msg_01k6x3a1g00000d0m6pt2y5f7h"
  ]
}'
Response 200
{
  "limit": 50,
  "count": 1,
  "messages": [
    {
      "inbox_id": "agent@machinemail.dev",
      "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
      "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "labels": ["UNREAD"],
      "timestamp": "2026-10-01T12:00:00.000Z",
      "from": "Support Agent <agent@machinemail.dev>",
      "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",
      "references": ["string"],
      "headers": {
        "key": "value"
      },
      "size": 2048,
      "updated_at": "2026-10-01T12:00:00.000Z",
      "created_at": "2026-10-01T12:00:00.000Z",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
      "direction": "inbound",
      "delivery_status": "sent",
      "trust_level": "verified",
      "reply_to": ["agent@machinemail.dev"],
      "text": "Thanks for the quick reply.",
      "html": "<p>Thanks for the quick reply.</p>",
      "extracted_text": "Thanks for the quick reply.",
      "extracted_html": "<p>Thanks for the quick reply.</p>",
      "received_via": "raw",
      "trust": {
        "level": "verified",
        "score": 0.8,
        "authentication": {
          "spf": "pass",
          "dkim": "pass",
          "dmarc": "pass",
          "aligned": false
        },
        "sender": {
          "address": "agent@machinemail.dev",
          "domain": "example.com",
          "prior_correspondence": false,
          "on_allow_list": false,
          "on_block_list": false,
          "free_mail_provider": false
        },
        "content": {
          "text": "Thanks for the quick reply.",
          "html": "<p>Thanks for the quick reply.</p>",
          "segments": [{}],
          "hidden_text_found": false,
          "zero_width_found": false,
          "tracking_pixels": 1
        },
        "links": [
          {
            "href": "string",
            "text": "Thanks for the quick reply.",
            "final_url": "https://example.com",
            "domain": "example.com",
            "display_mismatch": false,
            "shortener": false,
            "suspicious": false,
            "reasons": []
          }
        ],
        "attachments": [
          {
            "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
            "filename": "invoice.pdf",
            "content_type": "application/pdf",
            "risk": "low",
            "reasons": [],
            "extracted_text": "Thanks for the quick reply."
          }
        ],
        "classification": {
          "is_spam": 0.8,
          "is_phishing": 0.8,
          "contains_instructions_to_agent": 0.8,
          "requests_credentials_or_payment": 0.8,
          "urgency": 0.8,
          "category": "transactional",
          "language": "string",
          "backend": "string",
          "input_hash": "string",
          "cached": false
        },
        "reasons": ["string"],
        "computed_at": "2026-10-01T12:00:00.000Z"
      }
    }
  ]
}

Batch Update Messages

http
POST /v0/inboxes/{inbox_id}/messages/batch-update

Apply one label change to up to 100 messages: the same add_labels and remove_labels apply to every message. Messages are updated one at a time, not atomically. Missing IDs are skipped: compare count with limit.

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

Path parameters

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

Request body

Content type: application/json.

message_idsstring[]Required
IDs of the messages to update. Only the first 100 distinct IDs are updated.
add_labelsstring | string[]
Label or labels to add to every message.
remove_labelsstring | string[]
Label or labels to remove from every message.

Response

200 The updated messages (application/json)

limitintegerRequired
Number of IDs in the request.
countintegerRequired
Number of messages updated.
Updated messages with their new labels, in request order. IDs not found are omitted.

Each item of updates is a UpdateMessageResponse:

message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message after the update.

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.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X POST "https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/messages/batch-update" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "message_ids": [
    "msg_01k6x3a1g00000d0m6pt2y5f7h"
  ],
  "add_labels": "string"
}'
Response 200
{
  "limit": 50,
  "count": 1,
  "updates": [
    {
      "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "labels": ["UNREAD"]
    }
  ]
}

Search Messages

http
GET /v0/inboxes/{inbox_id}/messages/search

Full-text search across messages in the inbox, newest first (not ranked by relevance). Every word of q must appear in the subject, sender, recipients (to and cc), body text or attachment file names. Spam, trash, blocked, quarantined and unauthenticated messages are always excluded.

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

Path parameters

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

Query parameters

qstringRequired
Words to find in the subject, sender, recipients (to and cc), body text or attachment file names. (min length 1)
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 messages before this time.
afterstring (date-time)
Only messages after this time.
ascendingboolean
Sort oldest first.

Response

200 A page of matching messages (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.
messagesMessageItem[]Required
Matching messages, newest first unless ascending is set.

Each item of messages is a MessageItem:

inbox_idstringRequired
ID of the inbox.
thread_idstringRequired
ID of the thread.
message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message.
timestampstring (date-time)Required
Time at which the message was sent or received.
fromstringRequired
Address of the sender. In format username@domain.com or Display Name <username@domain.com>.
tostring[]Required
Addresses of the recipients. In format username@domain.com or Display Name <username@domain.com>.
ccstring[]
Addresses of the CC recipients. In format username@domain.com or Display Name <username@domain.com>.
bccstring[]
Addresses of the BCC recipients. In format username@domain.com or Display Name <username@domain.com>.
subjectstring
Subject of the message.
previewstring
Text preview of the message.
attachmentsAttachment[]
Attachments of the message.
in_reply_tostring
ID of the message being replied to.
referencesstring[]
IDs of previous messages in the thread.
headersRecord<string, string>
Headers of the message.
sizeintegerRequired
Size of the message in bytes.
updated_atstring (date-time)Required
Time at which the message was last updated.
created_atstring (date-time)Required
Time at which the message was created.
pod_idstringRequired
ID of the pod.
direction"inbound" | "outbound"Required
Whether the message was received or sent.
delivery_status"sent" | "delivered" | "bounced" | "complained"
Outbound only: last delivery state reported by the transport.
trust_level"verified" | "known" | "unknown" | "suspicious" | "quarantined"
Inbound only: trust.level, for list badges.

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/messages/search?q=invoice" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "messages": [
    {
      "inbox_id": "agent@machinemail.dev",
      "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
      "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "labels": ["UNREAD"],
      "timestamp": "2026-10-01T12:00:00.000Z",
      "from": "Support Agent <agent@machinemail.dev>",
      "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",
      "references": ["string"],
      "headers": {
        "key": "value"
      },
      "size": 2048,
      "updated_at": "2026-10-01T12:00:00.000Z",
      "created_at": "2026-10-01T12:00:00.000Z",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
      "direction": "inbound",
      "delivery_status": "sent",
      "trust_level": "verified"
    }
  ]
}

Send Message

http
POST /v0/inboxes/{inbox_id}/messages/send

At least one of to, cc or bcc is required.

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".

Recipients that are suppressed or on a send block list, and paused inboxes, return 403. 501 when the deployment has no email transport.

Attachments given by url are fetched by the API (public http(s) only, no redirects, at most 25 MB, 20 second timeout).

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 past that. Writing again to an address already counted is free. Claiming the inbox lifts the caps.

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

Path parameters

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

Request body

Content type: application/json.

labelsstring | string[]
Labels of the message. SENT is always added.
reply_tostring | string[]
Reply-to address or addresses.
tostring | string[]
Recipient address or addresses.
ccstring | string[]
CC recipient address or addresses.
bccstring | string[]
BCC recipient address or addresses.
subjectstring
Subject of the message.
textstring
Plain text body.
htmlstring
HTML body.
attachmentsSendAttachment[]
Attachments to include.
headersRecord<string, string>
Headers to include. In-Reply-To and References also thread the message.

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

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/messages/send" \
  -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 201
{
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "timestamp": "2026-10-01T12:00:00.000Z"
}

Get Message

http
GET /v0/inboxes/{inbox_id}/messages/{message_id}

Message content is untrusted: when feeding an LLM, read trust.content.text rather than text or html.

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

Path parameters

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

Response

200 The message (application/json)

inbox_idstringRequired
ID of the inbox.
thread_idstringRequired
ID of the thread.
message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message.
timestampstring (date-time)Required
Time at which the message was sent or received.
fromstringRequired
Address of the sender. In format username@domain.com or Display Name <username@domain.com>.
tostring[]Required
Addresses of the recipients. In format username@domain.com or Display Name <username@domain.com>.
ccstring[]
Addresses of the CC recipients. In format username@domain.com or Display Name <username@domain.com>.
bccstring[]
Addresses of the BCC recipients. In format username@domain.com or Display Name <username@domain.com>.
subjectstring
Subject of the message.
previewstring
Text preview of the message.
attachmentsAttachment[]
Attachments of the message.
in_reply_tostring
ID of the message being replied to.
referencesstring[]
IDs of previous messages in the thread.
headersRecord<string, string>
Headers of the message.
sizeintegerRequired
Size of the message in bytes.
updated_atstring (date-time)Required
Time at which the message was last updated.
created_atstring (date-time)Required
Time at which the message was created.
pod_idstringRequired
ID of the pod.
direction"inbound" | "outbound"Required
Whether the message was received or sent.
delivery_status"sent" | "delivered" | "bounced" | "complained"
Outbound only: last delivery state reported by the transport.
trust_level"verified" | "known" | "unknown" | "suspicious" | "quarantined"
Inbound only: trust.level, for list badges.
reply_tostring[]
Reply-to addresses. In format username@domain.com or Display Name <username@domain.com>.
textstring
Plain text body. Untrusted: agents should read trust.content.text or extracted_text.
htmlstring
HTML body. Untrusted.
extracted_textstring
New text content, without quoted replies.
extracted_htmlstring
New HTML content, without quoted replies.
received_via"raw"
raw when the message was injected with POST /inbound/raw (authentication not verified).
Trust report of an inbound message.

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.

trust is a TrustReport:

level"verified" | "known" | "unknown" | "suspicious" | "quarantined"Required
Overall verdict, safest first. quarantined messages are labelled QUARANTINE and hidden from lists unless asked for.
scorenumberRequired
0 to 1, higher is safer. Ranks messages within a level. (minimum 0, maximum 1)
authenticationobjectRequired
senderobjectRequired
contentobjectRequired
linksobject[]Required
attachmentsobject[]Required
classificationobjectRequired
reasonsstring[]Required
Human-readable reasons for the verdict.
computed_atstring (date-time)Required
When the report was computed.

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "labels": ["UNREAD"],
  "timestamp": "2026-10-01T12:00:00.000Z",
  "from": "Support Agent <agent@machinemail.dev>",
  "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",
  "references": ["string"],
  "headers": {
    "key": "value"
  },
  "size": 2048,
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "direction": "inbound",
  "delivery_status": "sent",
  "trust_level": "verified",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "extracted_text": "Thanks for the quick reply.",
  "extracted_html": "<p>Thanks for the quick reply.</p>",
  "received_via": "raw",
  "trust": {
    "level": "verified",
    "score": 0.8,
    "authentication": {
      "spf": "pass",
      "dkim": "pass",
      "dmarc": "pass",
      "aligned": false
    },
    "sender": {
      "address": "agent@machinemail.dev",
      "domain": "example.com",
      "prior_correspondence": false,
      "on_allow_list": false,
      "on_block_list": false,
      "free_mail_provider": false
    },
    "content": {
      "text": "Thanks for the quick reply.",
      "html": "<p>Thanks for the quick reply.</p>",
      "segments": [
        {
          "kind": "body",
          "text": "Thanks for the quick reply."
        }
      ],
      "hidden_text_found": false,
      "zero_width_found": false,
      "tracking_pixels": 1
    },
    "links": [
      {
        "href": "string",
        "text": "Thanks for the quick reply.",
        "final_url": "https://example.com",
        "domain": "example.com",
        "display_mismatch": false,
        "shortener": false,
        "suspicious": false,
        "reasons": ["string"]
      }
    ],
    "attachments": [
      {
        "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
        "filename": "invoice.pdf",
        "content_type": "application/pdf",
        "risk": "low",
        "reasons": ["string"],
        "extracted_text": "Thanks for the quick reply."
      }
    ],
    "classification": {
      "is_spam": 0.8,
      "is_phishing": 0.8,
      "contains_instructions_to_agent": 0.8,
      "requests_credentials_or_payment": 0.8,
      "urgency": 0.8,
      "category": "transactional",
      "language": "string",
      "backend": "string",
      "input_hash": "string",
      "cached": false
    },
    "reasons": ["string"],
    "computed_at": "2026-10-01T12:00:00.000Z"
  }
}

Update Message

http
PATCH /v0/inboxes/{inbox_id}/messages/{message_id}

Adds and removes labels. Returns the whole updated message.

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

Path parameters

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

Request body

Content type: application/json.

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

Response

200 The updated message (application/json)

inbox_idstringRequired
ID of the inbox.
thread_idstringRequired
ID of the thread.
message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message.
timestampstring (date-time)Required
Time at which the message was sent or received.
fromstringRequired
Address of the sender. In format username@domain.com or Display Name <username@domain.com>.
tostring[]Required
Addresses of the recipients. In format username@domain.com or Display Name <username@domain.com>.
ccstring[]
Addresses of the CC recipients. In format username@domain.com or Display Name <username@domain.com>.
bccstring[]
Addresses of the BCC recipients. In format username@domain.com or Display Name <username@domain.com>.
subjectstring
Subject of the message.
previewstring
Text preview of the message.
attachmentsAttachment[]
Attachments of the message.
in_reply_tostring
ID of the message being replied to.
referencesstring[]
IDs of previous messages in the thread.
headersRecord<string, string>
Headers of the message.
sizeintegerRequired
Size of the message in bytes.
updated_atstring (date-time)Required
Time at which the message was last updated.
created_atstring (date-time)Required
Time at which the message was created.
pod_idstringRequired
ID of the pod.
direction"inbound" | "outbound"Required
Whether the message was received or sent.
delivery_status"sent" | "delivered" | "bounced" | "complained"
Outbound only: last delivery state reported by the transport.
trust_level"verified" | "known" | "unknown" | "suspicious" | "quarantined"
Inbound only: trust.level, for list badges.
reply_tostring[]
Reply-to addresses. In format username@domain.com or Display Name <username@domain.com>.
textstring
Plain text body. Untrusted: agents should read trust.content.text or extracted_text.
htmlstring
HTML body. Untrusted.
extracted_textstring
New text content, without quoted replies.
extracted_htmlstring
New HTML content, without quoted replies.
received_via"raw"
raw when the message was injected with POST /inbound/raw (authentication not verified).
Trust report of an inbound message.

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.

trust is a TrustReport:

level"verified" | "known" | "unknown" | "suspicious" | "quarantined"Required
Overall verdict, safest first. quarantined messages are labelled QUARANTINE and hidden from lists unless asked for.
scorenumberRequired
0 to 1, higher is safer. Ranks messages within a level. (minimum 0, maximum 1)
authenticationobjectRequired
senderobjectRequired
contentobjectRequired
linksobject[]Required
attachmentsobject[]Required
classificationobjectRequired
reasonsstring[]Required
Human-readable reasons for the verdict.
computed_atstring (date-time)Required
When the report was computed.

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.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X PATCH "https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/messages/msg_01k6x3a1g00000d0m6pt2y5f7h" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "add_labels": "string"
}'
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "labels": ["UNREAD"],
  "timestamp": "2026-10-01T12:00:00.000Z",
  "from": "Support Agent <agent@machinemail.dev>",
  "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",
  "references": ["string"],
  "headers": {
    "key": "value"
  },
  "size": 2048,
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "direction": "inbound",
  "delivery_status": "sent",
  "trust_level": "verified",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "extracted_text": "Thanks for the quick reply.",
  "extracted_html": "<p>Thanks for the quick reply.</p>",
  "received_via": "raw",
  "trust": {
    "level": "verified",
    "score": 0.8,
    "authentication": {
      "spf": "pass",
      "dkim": "pass",
      "dmarc": "pass",
      "aligned": false
    },
    "sender": {
      "address": "agent@machinemail.dev",
      "domain": "example.com",
      "prior_correspondence": false,
      "on_allow_list": false,
      "on_block_list": false,
      "free_mail_provider": false
    },
    "content": {
      "text": "Thanks for the quick reply.",
      "html": "<p>Thanks for the quick reply.</p>",
      "segments": [
        {
          "kind": "body",
          "text": "Thanks for the quick reply."
        }
      ],
      "hidden_text_found": false,
      "zero_width_found": false,
      "tracking_pixels": 1
    },
    "links": [
      {
        "href": "string",
        "text": "Thanks for the quick reply.",
        "final_url": "https://example.com",
        "domain": "example.com",
        "display_mismatch": false,
        "shortener": false,
        "suspicious": false,
        "reasons": ["string"]
      }
    ],
    "attachments": [
      {
        "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
        "filename": "invoice.pdf",
        "content_type": "application/pdf",
        "risk": "low",
        "reasons": ["string"],
        "extracted_text": "Thanks for the quick reply."
      }
    ],
    "classification": {
      "is_spam": 0.8,
      "is_phishing": 0.8,
      "contains_instructions_to_agent": 0.8,
      "requests_credentials_or_payment": 0.8,
      "urgency": 0.8,
      "category": "transactional",
      "language": "string",
      "backend": "string",
      "input_hash": "string",
      "cached": false
    },
    "reasons": ["string"],
    "computed_at": "2026-10-01T12:00:00.000Z"
  }
}

Delete Message

http
DELETE /v0/inboxes/{inbox_id}/messages/{message_id}

Permanently deletes the message, its raw copy and attachments. The thread is updated (or deleted with its last message).

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

Path parameters

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

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.
409Conflicts with an existing resource.
500Unexpected server error.

Error bodies use the error envelope.

Example

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

Get Attachment

http
GET /v0/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}

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

Path parameters

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

Response

200 The attachment with a download URL (application/json)

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.
download_urlstringRequired
URL of the attachment bytes. Depending on the storage backend: a signed storage URL, the API URL GET .../attachments/{attachment_id}/download (send your API key), or a data: URI.
expires_atstring (date-time)Required
When download_url expires: one hour from the request unless the signed URL sets its own expiry.

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/attachments/att_01k6x3h7qv0000m7v3xb9f2p4r" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
  "filename": "invoice.pdf",
  "size": 2048,
  "content_type": "application/pdf",
  "content_disposition": "string",
  "content_id": "string",
  "download_url": "https://example.com",
  "expires_at": "2026-10-01T12:00:00.000Z"
}

Download Attachment

http
GET /v0/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}/download

The attachment bytes, served with the attachment content type, Content-Disposition: attachment and X-Content-Type-Options: nosniff.

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

Path parameters

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

Response

200 The attachment bytes (application/octet-stream)

Headers:

Content-Dispositionstring
attachment; filename="<filename>"

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/attachments/att_01k6x3h7qv0000m7v3xb9f2p4r/download" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

Forward Message

http
POST /v0/inboxes/{inbox_id}/messages/{message_id}/forward

Sends the message to new recipients. The text body is your text followed by a “Forwarded message” header block and the original text. The original HTML and attachments are not included. subject defaults to Fwd: <original subject>.

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".

Recipients that are suppressed or on a send block list, and paused inboxes, return 403. 501 when the deployment has no email transport.

Attachments given by url are fetched by the API (public http(s) only, no redirects, at most 25 MB, 20 second timeout).

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 past that. Writing again to an address already counted is free. Claiming the inbox lifts the caps.

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

Path parameters

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

Request body

Content type: application/json.

labelsstring | string[]
Labels of the message. SENT is always added.
reply_tostring | string[]
Reply-to address or addresses.
tostring | string[]
Recipient address or addresses.
ccstring | string[]
CC recipient address or addresses.
bccstring | string[]
BCC recipient address or addresses.
subjectstring
Subject of the message.
textstring
Plain text body.
htmlstring
HTML body.
attachmentsSendAttachment[]
Attachments to include.
headersRecord<string, string>
Headers to include. In-Reply-To and References also thread the message.

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

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/forward" \
  -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 201
{
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "timestamp": "2026-10-01T12:00:00.000Z"
}

Get Raw Message

http
GET /v0/inboxes/{inbox_id}/messages/{message_id}/raw

The original RFC 5322 message bytes, as received or sent. AgentMail returns a JSON object with a download URL instead.

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

Path parameters

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

Response

200 The raw message (message/rfc822)

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/raw" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

Reply To Message

http
POST /v0/inboxes/{inbox_id}/messages/{message_id}/reply

Sends a reply in the thread of the message, with In-Reply-To and References set.

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".

Recipients that are suppressed or on a send block list, and paused inboxes, return 403. 501 when the deployment has no email transport.

Attachments given by url are fetched by the API (public http(s) only, no redirects, at most 25 MB, 20 second timeout).

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 past that. Writing again to an address already counted is free. Claiming the inbox lifts the caps.

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

Path parameters

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

Request body

Content type: application/json.

labelsstring | string[]
Labels of the message. SENT is always added.
reply_tostring | string[]
Reply-to address or addresses.
tostring | string[]
Recipient address or addresses. Defaults to the sender of the original (its reply-to addresses if any); for an outbound original, its recipients.
ccstring | string[]
CC recipient address or addresses.
bccstring | string[]
BCC recipient address or addresses.
reply_allboolean
true replies to all recipients of the original, as Reply All Message does; to and cc are then added to them.
textstring
Plain text body.
htmlstring
HTML body.
attachmentsSendAttachment[]
Attachments to include.
headersRecord<string, string>
Headers to include. In-Reply-To and References also thread the message.
subjectstring
Subject of the reply. Defaults to the original subject with Re: in front.

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

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/reply" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "customer@example.com",
  "text": "Thanks for the quick reply.",
  "subject": "Order #1042"
}'
Response 201
{
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "timestamp": "2026-10-01T12:00:00.000Z"
}

Reply All Message

http
POST /v0/inboxes/{inbox_id}/messages/{message_id}/reply-all

Replies to the sender and every to and cc recipient of the message, except this inbox. to and cc add more recipients.

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".

Recipients that are suppressed or on a send block list, and paused inboxes, return 403. 501 when the deployment has no email transport.

Attachments given by url are fetched by the API (public http(s) only, no redirects, at most 25 MB, 20 second timeout).

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 past that. Writing again to an address already counted is free. Claiming the inbox lifts the caps.

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

Path parameters

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

Request body

Content type: application/json.

labelsstring | string[]
Labels of the message. SENT is always added.
reply_tostring | string[]
Reply-to address or addresses.
textstring
Plain text body.
htmlstring
HTML body.
attachmentsSendAttachment[]
Attachments to include.
headersRecord<string, string>
Headers to include. In-Reply-To and References also thread the message.
tostring | string[]
More recipients, added to the sender and recipients of the original.
ccstring | string[]
More CC recipients, added to the CC recipients of the original.
bccstring | string[]
BCC recipient address or addresses.
subjectstring
Subject of the reply. Defaults to the original subject with Re: in front.

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

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/reply-all" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "Thanks for the quick reply.",
  "to": "customer@example.com",
  "subject": "Order #1042"
}'
Response 201
{
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "timestamp": "2026-10-01T12:00:00.000Z"
}

List Messages in Pod

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

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

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: message_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.
ascendingboolean
Sort oldest first.
labelsstring[]
Only items with any of these labels. Asking for SPAM, BLOCKED, TRASH, QUARANTINE or UNAUTHENTICATED includes them.
beforestring (date-time)
Only items with a timestamp before this time.
afterstring (date-time)
Only items with a timestamp after this time.
include_spamboolean
Include spam (needs label_spam_read; ignored without it).
include_blockedboolean
Include blocked mail (needs label_blocked_read; ignored without it).
include_unauthenticatedboolean
Include unauthenticated mail (needs label_unauthenticated_read; ignored without it).
include_trashboolean
Include trash (needs label_trash_read; ignored without it).
include_quarantineboolean
Include quarantined messages (trust level quarantined).
qstring
Full-text filter: the words must appear in the subject, sender, recipients, body or attachment file names. Combines with the other filters.

Response

200 A page of messages (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.
messagesMessageItem[]Required
Ordered by timestamp, newest first unless ascending is set.

Each item of messages is a MessageItem:

inbox_idstringRequired
ID of the inbox.
thread_idstringRequired
ID of the thread.
message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message.
timestampstring (date-time)Required
Time at which the message was sent or received.
fromstringRequired
Address of the sender. In format username@domain.com or Display Name <username@domain.com>.
tostring[]Required
Addresses of the recipients. In format username@domain.com or Display Name <username@domain.com>.
ccstring[]
Addresses of the CC recipients. In format username@domain.com or Display Name <username@domain.com>.
bccstring[]
Addresses of the BCC recipients. In format username@domain.com or Display Name <username@domain.com>.
subjectstring
Subject of the message.
previewstring
Text preview of the message.
attachmentsAttachment[]
Attachments of the message.
in_reply_tostring
ID of the message being replied to.
referencesstring[]
IDs of previous messages in the thread.
headersRecord<string, string>
Headers of the message.
sizeintegerRequired
Size of the message in bytes.
updated_atstring (date-time)Required
Time at which the message was last updated.
created_atstring (date-time)Required
Time at which the message was created.
pod_idstringRequired
ID of the pod.
direction"inbound" | "outbound"Required
Whether the message was received or sent.
delivery_status"sent" | "delivered" | "bounced" | "complained"
Outbound only: last delivery state reported by the transport.
trust_level"verified" | "known" | "unknown" | "suspicious" | "quarantined"
Inbound only: trust.level, for list badges.

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/messages" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "messages": [
    {
      "inbox_id": "agent@machinemail.dev",
      "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
      "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "labels": ["UNREAD"],
      "timestamp": "2026-10-01T12:00:00.000Z",
      "from": "Support Agent <agent@machinemail.dev>",
      "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",
      "references": ["string"],
      "headers": {
        "key": "value"
      },
      "size": 2048,
      "updated_at": "2026-10-01T12:00:00.000Z",
      "created_at": "2026-10-01T12:00:00.000Z",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
      "direction": "inbound",
      "delivery_status": "sent",
      "trust_level": "verified"
    }
  ]
}

Batch Get Messages in Pod

http
POST /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/batch-get

Same as Batch Get Messages (POST /v0/inboxes/{inbox_id}/messages/batch-get), limited to the pod.

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

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.

message_idsstring[]Required
IDs of the messages to fetch. Only the first 100 distinct IDs are read.

Response

200 The messages found (application/json)

limitintegerRequired
Number of IDs in the request.
countintegerRequired
Number of messages returned.
messagesMessage[]Required
Found messages, in request order. IDs not found in the inbox are omitted.

Each item of messages is a Message:

inbox_idstringRequired
ID of the inbox.
thread_idstringRequired
ID of the thread.
message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message.
timestampstring (date-time)Required
Time at which the message was sent or received.
fromstringRequired
Address of the sender. In format username@domain.com or Display Name <username@domain.com>.
tostring[]Required
Addresses of the recipients. In format username@domain.com or Display Name <username@domain.com>.
ccstring[]
Addresses of the CC recipients. In format username@domain.com or Display Name <username@domain.com>.
bccstring[]
Addresses of the BCC recipients. In format username@domain.com or Display Name <username@domain.com>.
subjectstring
Subject of the message.
previewstring
Text preview of the message.
attachmentsAttachment[]
Attachments of the message.
in_reply_tostring
ID of the message being replied to.
referencesstring[]
IDs of previous messages in the thread.
headersRecord<string, string>
Headers of the message.
sizeintegerRequired
Size of the message in bytes.
updated_atstring (date-time)Required
Time at which the message was last updated.
created_atstring (date-time)Required
Time at which the message was created.
pod_idstringRequired
ID of the pod.
direction"inbound" | "outbound"Required
Whether the message was received or sent.
delivery_status"sent" | "delivered" | "bounced" | "complained"
Outbound only: last delivery state reported by the transport.
trust_level"verified" | "known" | "unknown" | "suspicious" | "quarantined"
Inbound only: trust.level, for list badges.
reply_tostring[]
Reply-to addresses. In format username@domain.com or Display Name <username@domain.com>.
textstring
Plain text body. Untrusted: agents should read trust.content.text or extracted_text.
htmlstring
HTML body. Untrusted.
extracted_textstring
New text content, without quoted replies.
extracted_htmlstring
New HTML content, without quoted replies.
received_via"raw"
raw when the message was injected with POST /inbound/raw (authentication not verified).
Trust report of an inbound message.

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/messages/batch-get" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "message_ids": [
    "msg_01k6x3a1g00000d0m6pt2y5f7h"
  ]
}'
Response 200
{
  "limit": 50,
  "count": 1,
  "messages": [
    {
      "inbox_id": "agent@machinemail.dev",
      "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
      "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "labels": ["UNREAD"],
      "timestamp": "2026-10-01T12:00:00.000Z",
      "from": "Support Agent <agent@machinemail.dev>",
      "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",
      "references": ["string"],
      "headers": {
        "key": "value"
      },
      "size": 2048,
      "updated_at": "2026-10-01T12:00:00.000Z",
      "created_at": "2026-10-01T12:00:00.000Z",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
      "direction": "inbound",
      "delivery_status": "sent",
      "trust_level": "verified",
      "reply_to": ["agent@machinemail.dev"],
      "text": "Thanks for the quick reply.",
      "html": "<p>Thanks for the quick reply.</p>",
      "extracted_text": "Thanks for the quick reply.",
      "extracted_html": "<p>Thanks for the quick reply.</p>",
      "received_via": "raw",
      "trust": {
        "level": "verified",
        "score": 0.8,
        "authentication": {
          "spf": "pass",
          "dkim": "pass",
          "dmarc": "pass",
          "aligned": false
        },
        "sender": {
          "address": "agent@machinemail.dev",
          "domain": "example.com",
          "prior_correspondence": false,
          "on_allow_list": false,
          "on_block_list": false,
          "free_mail_provider": false
        },
        "content": {
          "text": "Thanks for the quick reply.",
          "html": "<p>Thanks for the quick reply.</p>",
          "segments": [{}],
          "hidden_text_found": false,
          "zero_width_found": false,
          "tracking_pixels": 1
        },
        "links": [
          {
            "href": "string",
            "text": "Thanks for the quick reply.",
            "final_url": "https://example.com",
            "domain": "example.com",
            "display_mismatch": false,
            "shortener": false,
            "suspicious": false,
            "reasons": []
          }
        ],
        "attachments": [
          {
            "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
            "filename": "invoice.pdf",
            "content_type": "application/pdf",
            "risk": "low",
            "reasons": [],
            "extracted_text": "Thanks for the quick reply."
          }
        ],
        "classification": {
          "is_spam": 0.8,
          "is_phishing": 0.8,
          "contains_instructions_to_agent": 0.8,
          "requests_credentials_or_payment": 0.8,
          "urgency": 0.8,
          "category": "transactional",
          "language": "string",
          "backend": "string",
          "input_hash": "string",
          "cached": false
        },
        "reasons": ["string"],
        "computed_at": "2026-10-01T12:00:00.000Z"
      }
    }
  ]
}

Batch Update Messages in Pod

http
POST /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/batch-update

Same as Batch Update Messages (POST /v0/inboxes/{inbox_id}/messages/batch-update), limited to the pod.

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

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.

message_idsstring[]Required
IDs of the messages to update. Only the first 100 distinct IDs are updated.
add_labelsstring | string[]
Label or labels to add to every message.
remove_labelsstring | string[]
Label or labels to remove from every message.

Response

200 The updated messages (application/json)

limitintegerRequired
Number of IDs in the request.
countintegerRequired
Number of messages updated.
Updated messages with their new labels, in request order. IDs not found are omitted.

Each item of updates is a UpdateMessageResponse:

message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message after the update.

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.
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/messages/batch-update" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "message_ids": [
    "msg_01k6x3a1g00000d0m6pt2y5f7h"
  ],
  "add_labels": "string"
}'
Response 200
{
  "limit": 50,
  "count": 1,
  "updates": [
    {
      "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "labels": ["UNREAD"]
    }
  ]
}

Search Messages in Pod

http
GET /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/search

Same as Search Messages (GET /v0/inboxes/{inbox_id}/messages/search), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: message_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

qstringRequired
Words to find in the subject, sender, recipients (to and cc), body text or attachment file names. (min length 1)
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 messages before this time.
afterstring (date-time)
Only messages after this time.
ascendingboolean
Sort oldest first.

Response

200 A page of matching messages (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.
messagesMessageItem[]Required
Matching messages, newest first unless ascending is set.

Each item of messages is a MessageItem:

inbox_idstringRequired
ID of the inbox.
thread_idstringRequired
ID of the thread.
message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message.
timestampstring (date-time)Required
Time at which the message was sent or received.
fromstringRequired
Address of the sender. In format username@domain.com or Display Name <username@domain.com>.
tostring[]Required
Addresses of the recipients. In format username@domain.com or Display Name <username@domain.com>.
ccstring[]
Addresses of the CC recipients. In format username@domain.com or Display Name <username@domain.com>.
bccstring[]
Addresses of the BCC recipients. In format username@domain.com or Display Name <username@domain.com>.
subjectstring
Subject of the message.
previewstring
Text preview of the message.
attachmentsAttachment[]
Attachments of the message.
in_reply_tostring
ID of the message being replied to.
referencesstring[]
IDs of previous messages in the thread.
headersRecord<string, string>
Headers of the message.
sizeintegerRequired
Size of the message in bytes.
updated_atstring (date-time)Required
Time at which the message was last updated.
created_atstring (date-time)Required
Time at which the message was created.
pod_idstringRequired
ID of the pod.
direction"inbound" | "outbound"Required
Whether the message was received or sent.
delivery_status"sent" | "delivered" | "bounced" | "complained"
Outbound only: last delivery state reported by the transport.
trust_level"verified" | "known" | "unknown" | "suspicious" | "quarantined"
Inbound only: trust.level, for list badges.

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/messages/search?q=invoice" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "messages": [
    {
      "inbox_id": "agent@machinemail.dev",
      "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
      "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
      "labels": ["UNREAD"],
      "timestamp": "2026-10-01T12:00:00.000Z",
      "from": "Support Agent <agent@machinemail.dev>",
      "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",
      "references": ["string"],
      "headers": {
        "key": "value"
      },
      "size": 2048,
      "updated_at": "2026-10-01T12:00:00.000Z",
      "created_at": "2026-10-01T12:00:00.000Z",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
      "direction": "inbound",
      "delivery_status": "sent",
      "trust_level": "verified"
    }
  ]
}

Send Message in Pod

http
POST /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/send

Same as Send Message (POST /v0/inboxes/{inbox_id}/messages/send), limited to the pod.

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

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 | string[]
Labels of the message. SENT is always added.
reply_tostring | string[]
Reply-to address or addresses.
tostring | string[]
Recipient address or addresses.
ccstring | string[]
CC recipient address or addresses.
bccstring | string[]
BCC recipient address or addresses.
subjectstring
Subject of the message.
textstring
Plain text body.
htmlstring
HTML body.
attachmentsSendAttachment[]
Attachments to include.
headersRecord<string, string>
Headers to include. In-Reply-To and References also thread the message.

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

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/messages/send" \
  -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 201
{
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "timestamp": "2026-10-01T12:00:00.000Z"
}

Get Message in Pod

http
GET /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}

Same as Get Message (GET /v0/inboxes/{inbox_id}/messages/{message_id}), limited to the pod.

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

Path parameters

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

Response

200 The message (application/json)

inbox_idstringRequired
ID of the inbox.
thread_idstringRequired
ID of the thread.
message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message.
timestampstring (date-time)Required
Time at which the message was sent or received.
fromstringRequired
Address of the sender. In format username@domain.com or Display Name <username@domain.com>.
tostring[]Required
Addresses of the recipients. In format username@domain.com or Display Name <username@domain.com>.
ccstring[]
Addresses of the CC recipients. In format username@domain.com or Display Name <username@domain.com>.
bccstring[]
Addresses of the BCC recipients. In format username@domain.com or Display Name <username@domain.com>.
subjectstring
Subject of the message.
previewstring
Text preview of the message.
attachmentsAttachment[]
Attachments of the message.
in_reply_tostring
ID of the message being replied to.
referencesstring[]
IDs of previous messages in the thread.
headersRecord<string, string>
Headers of the message.
sizeintegerRequired
Size of the message in bytes.
updated_atstring (date-time)Required
Time at which the message was last updated.
created_atstring (date-time)Required
Time at which the message was created.
pod_idstringRequired
ID of the pod.
direction"inbound" | "outbound"Required
Whether the message was received or sent.
delivery_status"sent" | "delivered" | "bounced" | "complained"
Outbound only: last delivery state reported by the transport.
trust_level"verified" | "known" | "unknown" | "suspicious" | "quarantined"
Inbound only: trust.level, for list badges.
reply_tostring[]
Reply-to addresses. In format username@domain.com or Display Name <username@domain.com>.
textstring
Plain text body. Untrusted: agents should read trust.content.text or extracted_text.
htmlstring
HTML body. Untrusted.
extracted_textstring
New text content, without quoted replies.
extracted_htmlstring
New HTML content, without quoted replies.
received_via"raw"
raw when the message was injected with POST /inbound/raw (authentication not verified).
Trust report of an inbound message.

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.

trust is a TrustReport:

level"verified" | "known" | "unknown" | "suspicious" | "quarantined"Required
Overall verdict, safest first. quarantined messages are labelled QUARANTINE and hidden from lists unless asked for.
scorenumberRequired
0 to 1, higher is safer. Ranks messages within a level. (minimum 0, maximum 1)
authenticationobjectRequired
senderobjectRequired
contentobjectRequired
linksobject[]Required
attachmentsobject[]Required
classificationobjectRequired
reasonsstring[]Required
Human-readable reasons for the verdict.
computed_atstring (date-time)Required
When the report was computed.

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "labels": ["UNREAD"],
  "timestamp": "2026-10-01T12:00:00.000Z",
  "from": "Support Agent <agent@machinemail.dev>",
  "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",
  "references": ["string"],
  "headers": {
    "key": "value"
  },
  "size": 2048,
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "direction": "inbound",
  "delivery_status": "sent",
  "trust_level": "verified",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "extracted_text": "Thanks for the quick reply.",
  "extracted_html": "<p>Thanks for the quick reply.</p>",
  "received_via": "raw",
  "trust": {
    "level": "verified",
    "score": 0.8,
    "authentication": {
      "spf": "pass",
      "dkim": "pass",
      "dmarc": "pass",
      "aligned": false
    },
    "sender": {
      "address": "agent@machinemail.dev",
      "domain": "example.com",
      "prior_correspondence": false,
      "on_allow_list": false,
      "on_block_list": false,
      "free_mail_provider": false
    },
    "content": {
      "text": "Thanks for the quick reply.",
      "html": "<p>Thanks for the quick reply.</p>",
      "segments": [
        {
          "kind": "body",
          "text": "Thanks for the quick reply."
        }
      ],
      "hidden_text_found": false,
      "zero_width_found": false,
      "tracking_pixels": 1
    },
    "links": [
      {
        "href": "string",
        "text": "Thanks for the quick reply.",
        "final_url": "https://example.com",
        "domain": "example.com",
        "display_mismatch": false,
        "shortener": false,
        "suspicious": false,
        "reasons": ["string"]
      }
    ],
    "attachments": [
      {
        "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
        "filename": "invoice.pdf",
        "content_type": "application/pdf",
        "risk": "low",
        "reasons": ["string"],
        "extracted_text": "Thanks for the quick reply."
      }
    ],
    "classification": {
      "is_spam": 0.8,
      "is_phishing": 0.8,
      "contains_instructions_to_agent": 0.8,
      "requests_credentials_or_payment": 0.8,
      "urgency": 0.8,
      "category": "transactional",
      "language": "string",
      "backend": "string",
      "input_hash": "string",
      "cached": false
    },
    "reasons": ["string"],
    "computed_at": "2026-10-01T12:00:00.000Z"
  }
}

Update Message in Pod

http
PATCH /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}

Same as Update Message (PATCH /v0/inboxes/{inbox_id}/messages/{message_id}), limited to the pod.

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

Path parameters

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

Request body

Content type: application/json.

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

Response

200 The updated message (application/json)

inbox_idstringRequired
ID of the inbox.
thread_idstringRequired
ID of the thread.
message_idstringRequired
ID of the message.
labelsstring[]Required
Labels of the message.
timestampstring (date-time)Required
Time at which the message was sent or received.
fromstringRequired
Address of the sender. In format username@domain.com or Display Name <username@domain.com>.
tostring[]Required
Addresses of the recipients. In format username@domain.com or Display Name <username@domain.com>.
ccstring[]
Addresses of the CC recipients. In format username@domain.com or Display Name <username@domain.com>.
bccstring[]
Addresses of the BCC recipients. In format username@domain.com or Display Name <username@domain.com>.
subjectstring
Subject of the message.
previewstring
Text preview of the message.
attachmentsAttachment[]
Attachments of the message.
in_reply_tostring
ID of the message being replied to.
referencesstring[]
IDs of previous messages in the thread.
headersRecord<string, string>
Headers of the message.
sizeintegerRequired
Size of the message in bytes.
updated_atstring (date-time)Required
Time at which the message was last updated.
created_atstring (date-time)Required
Time at which the message was created.
pod_idstringRequired
ID of the pod.
direction"inbound" | "outbound"Required
Whether the message was received or sent.
delivery_status"sent" | "delivered" | "bounced" | "complained"
Outbound only: last delivery state reported by the transport.
trust_level"verified" | "known" | "unknown" | "suspicious" | "quarantined"
Inbound only: trust.level, for list badges.
reply_tostring[]
Reply-to addresses. In format username@domain.com or Display Name <username@domain.com>.
textstring
Plain text body. Untrusted: agents should read trust.content.text or extracted_text.
htmlstring
HTML body. Untrusted.
extracted_textstring
New text content, without quoted replies.
extracted_htmlstring
New HTML content, without quoted replies.
received_via"raw"
raw when the message was injected with POST /inbound/raw (authentication not verified).
Trust report of an inbound message.

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.

trust is a TrustReport:

level"verified" | "known" | "unknown" | "suspicious" | "quarantined"Required
Overall verdict, safest first. quarantined messages are labelled QUARANTINE and hidden from lists unless asked for.
scorenumberRequired
0 to 1, higher is safer. Ranks messages within a level. (minimum 0, maximum 1)
authenticationobjectRequired
senderobjectRequired
contentobjectRequired
linksobject[]Required
attachmentsobject[]Required
classificationobjectRequired
reasonsstring[]Required
Human-readable reasons for the verdict.
computed_atstring (date-time)Required
When the report was computed.

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.
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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "add_labels": "string"
}'
Response 200
{
  "inbox_id": "agent@machinemail.dev",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "labels": ["UNREAD"],
  "timestamp": "2026-10-01T12:00:00.000Z",
  "from": "Support Agent <agent@machinemail.dev>",
  "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",
  "references": ["string"],
  "headers": {
    "key": "value"
  },
  "size": 2048,
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "direction": "inbound",
  "delivery_status": "sent",
  "trust_level": "verified",
  "reply_to": ["agent@machinemail.dev"],
  "text": "Thanks for the quick reply.",
  "html": "<p>Thanks for the quick reply.</p>",
  "extracted_text": "Thanks for the quick reply.",
  "extracted_html": "<p>Thanks for the quick reply.</p>",
  "received_via": "raw",
  "trust": {
    "level": "verified",
    "score": 0.8,
    "authentication": {
      "spf": "pass",
      "dkim": "pass",
      "dmarc": "pass",
      "aligned": false
    },
    "sender": {
      "address": "agent@machinemail.dev",
      "domain": "example.com",
      "prior_correspondence": false,
      "on_allow_list": false,
      "on_block_list": false,
      "free_mail_provider": false
    },
    "content": {
      "text": "Thanks for the quick reply.",
      "html": "<p>Thanks for the quick reply.</p>",
      "segments": [
        {
          "kind": "body",
          "text": "Thanks for the quick reply."
        }
      ],
      "hidden_text_found": false,
      "zero_width_found": false,
      "tracking_pixels": 1
    },
    "links": [
      {
        "href": "string",
        "text": "Thanks for the quick reply.",
        "final_url": "https://example.com",
        "domain": "example.com",
        "display_mismatch": false,
        "shortener": false,
        "suspicious": false,
        "reasons": ["string"]
      }
    ],
    "attachments": [
      {
        "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
        "filename": "invoice.pdf",
        "content_type": "application/pdf",
        "risk": "low",
        "reasons": ["string"],
        "extracted_text": "Thanks for the quick reply."
      }
    ],
    "classification": {
      "is_spam": 0.8,
      "is_phishing": 0.8,
      "contains_instructions_to_agent": 0.8,
      "requests_credentials_or_payment": 0.8,
      "urgency": 0.8,
      "category": "transactional",
      "language": "string",
      "backend": "string",
      "input_hash": "string",
      "cached": false
    },
    "reasons": ["string"],
    "computed_at": "2026-10-01T12:00:00.000Z"
  }
}

Delete Message in Pod

http
DELETE /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}

Same as Delete Message (DELETE /v0/inboxes/{inbox_id}/messages/{message_id}), limited to the pod.

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

Path parameters

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

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.
409Conflicts with an existing resource.
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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "ok": true
}

Get Attachment in Pod

http
GET /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}

Same as Get Attachment (GET /v0/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}), limited to the pod.

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

Path parameters

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

Response

200 The attachment with a download URL (application/json)

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.
download_urlstringRequired
URL of the attachment bytes. Depending on the storage backend: a signed storage URL, the API URL GET .../attachments/{attachment_id}/download (send your API key), or a data: URI.
expires_atstring (date-time)Required
When download_url expires: one hour from the request unless the signed URL sets its own expiry.

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/attachments/att_01k6x3h7qv0000m7v3xb9f2p4r" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "attachment_id": "att_01k6x3h7qv0000m7v3xb9f2p4r",
  "filename": "invoice.pdf",
  "size": 2048,
  "content_type": "application/pdf",
  "content_disposition": "string",
  "content_id": "string",
  "download_url": "https://example.com",
  "expires_at": "2026-10-01T12:00:00.000Z"
}

Download Attachment in Pod

http
GET /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}/download

Same as Download Attachment (GET /v0/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}/download), limited to the pod.

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

Path parameters

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

Response

200 The attachment bytes (application/octet-stream)

Headers:

Content-Dispositionstring
attachment; filename="<filename>"

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/attachments/att_01k6x3h7qv0000m7v3xb9f2p4r/download" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

Forward Message in Pod

http
POST /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/forward

Same as Forward Message (POST /v0/inboxes/{inbox_id}/messages/{message_id}/forward), limited to the pod.

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

Path parameters

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

Request body

Content type: application/json.

labelsstring | string[]
Labels of the message. SENT is always added.
reply_tostring | string[]
Reply-to address or addresses.
tostring | string[]
Recipient address or addresses.
ccstring | string[]
CC recipient address or addresses.
bccstring | string[]
BCC recipient address or addresses.
subjectstring
Subject of the message.
textstring
Plain text body.
htmlstring
HTML body.
attachmentsSendAttachment[]
Attachments to include.
headersRecord<string, string>
Headers to include. In-Reply-To and References also thread the message.

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

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/forward" \
  -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 201
{
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "timestamp": "2026-10-01T12:00:00.000Z"
}

Get Raw Message in Pod

http
GET /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/raw

Same as Get Raw Message (GET /v0/inboxes/{inbox_id}/messages/{message_id}/raw), limited to the pod.

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

Path parameters

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

Response

200 The raw message (message/rfc822)

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/raw" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

Reply To Message in Pod

http
POST /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/reply

Same as Reply To Message (POST /v0/inboxes/{inbox_id}/messages/{message_id}/reply), limited to the pod.

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

Path parameters

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

Request body

Content type: application/json.

labelsstring | string[]
Labels of the message. SENT is always added.
reply_tostring | string[]
Reply-to address or addresses.
tostring | string[]
Recipient address or addresses. Defaults to the sender of the original (its reply-to addresses if any); for an outbound original, its recipients.
ccstring | string[]
CC recipient address or addresses.
bccstring | string[]
BCC recipient address or addresses.
reply_allboolean
true replies to all recipients of the original, as Reply All Message does; to and cc are then added to them.
textstring
Plain text body.
htmlstring
HTML body.
attachmentsSendAttachment[]
Attachments to include.
headersRecord<string, string>
Headers to include. In-Reply-To and References also thread the message.
subjectstring
Subject of the reply. Defaults to the original subject with Re: in front.

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

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/reply" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "customer@example.com",
  "text": "Thanks for the quick reply.",
  "subject": "Order #1042"
}'
Response 201
{
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "timestamp": "2026-10-01T12:00:00.000Z"
}

Reply All Message in Pod

http
POST /v0/pods/{pod_id}/inboxes/{inbox_id}/messages/{message_id}/reply-all

Same as Reply All Message (POST /v0/inboxes/{inbox_id}/messages/{message_id}/reply-all), limited to the pod.

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

Path parameters

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

Request body

Content type: application/json.

labelsstring | string[]
Labels of the message. SENT is always added.
reply_tostring | string[]
Reply-to address or addresses.
textstring
Plain text body.
htmlstring
HTML body.
attachmentsSendAttachment[]
Attachments to include.
headersRecord<string, string>
Headers to include. In-Reply-To and References also thread the message.
tostring | string[]
More recipients, added to the sender and recipients of the original.
ccstring | string[]
More CC recipients, added to the CC recipients of the original.
bccstring | string[]
BCC recipient address or addresses.
subjectstring
Subject of the reply. Defaults to the original subject with Re: in front.

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

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/messages/msg_01k6x3a1g00000d0m6pt2y5f7h/reply-all" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "Thanks for the quick reply.",
  "to": "customer@example.com",
  "subject": "Order #1042"
}'
Response 201
{
  "message_id": "msg_01k6x3a1g00000d0m6pt2y5f7h",
  "thread_id": "thd_01k6x3a1fz0000c9k5ns1x4e6g",
  "timestamp": "2026-10-01T12:00:00.000Z"
}