Developer API reference
A REST API for reading, searching, replying to, sending and tidying up mail in the inboxes on your AnyMail account - the same surface the official SDKs cover.
API access is part of the Pro plan. Create a key from the API tab after signing in, then send it as Authorization: Bearer am_... on every request. The machine-readable /api/docs/openapi.json describes the same endpoints for Postman, Insomnia or your own client generator.
Prefer a library? The TypeScript, Python and Go SDKs cover every endpoint below with message objects and inboxes named by address:
await Anymail.connect({ apiKey: process.env.ANYMAIL_API_KEY! });
for (const message of await Anymail.getMessages({ inbox: 'support@acme.com', unread: true })) {
await message.reply({ text: 'Thanks - we are on it.' });
}Authentication
This documents only the Developer API — the small set of endpoints your API key can call. It does not cover the rest of the AnyMail application, which isn't a published API. Every path below is relative to https://anymail.tech. Authenticate with:
bearer-api-key— Your API key, minted from the API tab, sent as `Authorization: Bearer am_...`. This is how you authenticate to every endpoint below.
Account
/api/v1/meFetch the caller's own account, including its mail storage usage.
curl -X GET 'https://anymail.tech/api/v1/me' \ -H 'Authorization: Bearer am_...'
The authenticated account, plus `storage`: bytes used (message subjects and bodies plus attachments at their original size, across every inbox the account owns), the plan's limit (`null` = unlimited), and a level - `warning` from 80%, `critical` from 95%, `full` at 100%, when new mail is refused and sends fail with `403 STORAGE_QUOTA_EXCEEDED`.
{
"user": {
"id": "usr_8f2c1e4a",
"email": "jane@example.com",
"roles": [
"user"
],
"status": "active",
"billingState": "active",
"plan": "pro",
"gdprConsentAt": "2026-01-04T10:15:00.000Z",
"createdAt": "2026-01-04T10:15:00.000Z",
"lastLoginAt": "2026-08-19T08:02:00.000Z",
"emailVerifiedAt": "2026-01-04T10:20:00.000Z",
"twoFactorEnabled": false
},
"storage": {
"usedBytes": 1288490188,
"limitBytes": 26843545600,
"usedFraction": 0.048,
"level": "ok",
"messageCount": 18234
}
}Mail servers
/api/v1/mail-serversList mail servers owned by the caller (read-only - no create/attach-domain/delete here).
curl -X GET 'https://anymail.tech/api/v1/mail-servers' \ -H 'Authorization: Bearer am_...'
Every mail server owned by the caller.
{
"mailServers": [
{
"id": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"name": "Acme Mail",
"domain": "acme.example",
"status": "active",
"dnsVerification": {
"ownership": true,
"mx": true,
"spf": true,
"dkim": true,
"dmarc": true
},
"security": {
"dkimSelector": "anymail",
"dkimPublicKey": "MIGfMA0GCSq...",
"requireTls": true
},
"createdAt": "2026-02-10T09:00:00.000Z"
}
]
}/api/v1/mail-servers/:idFetch one owned mail server.
curl -X GET 'https://anymail.tech/api/v1/mail-servers/<id>' \ -H 'Authorization: Bearer am_...'
The requested mail server.
{
"mailServer": {
"id": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"name": "Acme Mail",
"domain": "acme.example",
"status": "active",
"dnsVerification": {
"ownership": true,
"mx": true,
"spf": true,
"dkim": true,
"dmarc": true
},
"security": {
"dkimSelector": "anymail",
"dkimPublicKey": "MIGfMA0GCSq...",
"requireTls": true
},
"createdAt": "2026-02-10T09:00:00.000Z"
}
}Inboxes
/api/v1/mail-servers/:mailServerId/inboxesList inboxes under a mail server, with their aliases (read-only - no create/delete or alias changes here).
curl -X GET 'https://anymail.tech/api/v1/mail-servers/<mailServerId>/inboxes' \ -H 'Authorization: Bearer am_...'
Every inbox under the mail server.
{
"inboxes": [
{
"id": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"localPart": "sales",
"aliases": [
"hello"
],
"status": "active",
"createdAt": "2026-02-10T09:05:00.000Z",
"avatarMode": "initials",
"avatarUrl": null,
"avatarVersion": 1
}
]
}/api/v1/inboxes/:idFetch one owned inbox.
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>' \ -H 'Authorization: Bearer am_...'
The requested inbox.
{
"inbox": {
"id": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"localPart": "sales",
"aliases": [
"hello"
],
"status": "active",
"createdAt": "2026-02-10T09:05:00.000Z",
"avatarMode": "initials",
"avatarUrl": null,
"avatarVersion": 1
}
}Messages
/api/v1/inboxes/:id/messagesList, filter and page through messages in an inbox (folder, sender/subject substring, unread, date range; cursor paging with limit).
| Field | Type | Required | Constraints |
|---|---|---|---|
folder | string | no | min length 1, max length 1100 |
from | string | no | min length 1, max length 254 |
subject | string | no | min length 1, max length 200 |
unread | enum | no | one of: true, false |
unreadOnly | enum | no | one of: true, false |
includeSpam | enum | no | one of: true, false |
since | string | no | — |
before | string | no | — |
limit | number | no | min 1, max 100 |
cursor | string | no | min length 1, max length 512 |
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/messages?folder=string&from=someone%40example.com&subject=Quarterly+update&unread=true&unreadOnly=true&includeSpam=true&since=string&before=string&limit=1&cursor=string' \ -H 'Authorization: Bearer am_...'
Matching messages, newest first (attachment bytes omitted - see GET one message), how many further spam-hidden messages were excluded, and a nextCursor to pass back as `cursor` for the next page (null on the last page, or when no limit was given).
{
"messages": [
{
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "inbox",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
}
],
"hiddenSpamCount": 0,
"nextCursor": null
}/api/v1/inboxes/:id/messagesSend a message from an inbox - as its own address, or as one of its aliases by setting `from` (anything else is refused). `to`, `cc` and `bcc` each take one address or a list - at most 50 recipients in total. Every recipient is delivered (and reported on) separately; Bcc recipients never appear in any copy's headers.
| Field | Type | Required | Constraints |
|---|---|---|---|
from | string (email) | no | max length 254 |
to | string (email) | array<string (email)> | yes | max length 254 |
cc | string (email) | array<string (email)> | no | max length 254 |
bcc | string (email) | array<string (email)> | no | max length 254 |
subject | string | yes | min length 1, max length 200 |
body | string | yes | min length 1, max length 200000 |
contentType | enum | no | one of: text, html |
attachments | array<object> | no | — |
curl -X POST 'https://anymail.tech/api/v1/inboxes/<id>/messages' \
-H 'Authorization: Bearer am_...' \
-H 'Content-Type: application/json' \
-d '{
"from": "someone@example.com",
"to": "someone@example.com",
"cc": [
"colleague@example.com"
],
"bcc": [],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": []
}'The created, sent message, plus optional spam/delivery notices (both null on a clean, successful send). `recipientDeliveries` holds each recipient's delivery state; `deliveryWarning` names every recipient that could not be reached. Refused with `403 STORAGE_QUOTA_EXCEEDED` when the inbox owner's storage is full - the Sent copy needs room.
{
"message": {
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "sent",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "sales@acme.example",
"to": "someone@example.com",
"toList": [
"someone@example.com"
],
"cc": [
"colleague@example.com"
],
"bcc": [],
"recipientDeliveries": [
{
"address": "someone@example.com",
"status": "delivered",
"attempts": 0,
"nextRetryAt": null,
"lastError": null
},
{
"address": "colleague@example.com",
"status": "delivered",
"attempts": 0,
"nextRetryAt": null,
"lastError": null
}
],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentBase64": "JVBERi0xLjQKJc...",
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
},
"spamNotice": null,
"deliveryWarning": null
}/api/v1/inboxes/:id/messages/:messageIdFetch one message (marks an unread inbox message as read).
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>' \ -H 'Authorization: Bearer am_...'
The requested message, including attachment content.
{
"message": {
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "inbox",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentBase64": "JVBERi0xLjQKJc...",
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
}
}/api/v1/inboxes/:id/messages/:messageIdMark a message read or unread (manager access or above).
| Field | Type | Required | Constraints |
|---|---|---|---|
read | boolean | yes | — |
curl -X PATCH 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>' \
-H 'Authorization: Bearer am_...' \
-H 'Content-Type: application/json' \
-d '{
"read": false
}'The updated message.
{
"message": {
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "inbox",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentBase64": "JVBERi0xLjQKJc...",
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
}
}/api/v1/inboxes/:id/messages/:messageIdPermanently delete a message. Only a message already in Trash can be deleted; the deletion is audit-logged.
curl -X DELETE 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>' \ -H 'Authorization: Bearer am_...'
Deleted - no response body.
/api/v1/inboxes/:id/messages/:messageId/trashMove a message to Trash (auto-purged after the retention period).
curl -X POST 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>/trash' \ -H 'Authorization: Bearer am_...'
The trashed message.
{
"message": {
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "trash",
"previousFolder": "inbox",
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentBase64": "JVBERi0xLjQKJc...",
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
}
}/api/v1/inboxes/:id/messages/:messageId/restoreRestore a trashed message to the folder it came from.
curl -X POST 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>/restore' \ -H 'Authorization: Bearer am_...'
The restored message.
{
"message": {
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "inbox",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentBase64": "JVBERi0xLjQKJc...",
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
}
}/api/v1/inboxes/:id/messages/:messageId/replyReply to a message. The server picks the recipient (the original sender, or the To recipients of a sent message), prefixes the subject with "Re: " once, and threads the reply via In-Reply-To/References. It is sent from the inbox address the original used (e.g. the alias it was sent to) unless `from` names another of the inbox's addresses.
| Field | Type | Required | Constraints |
|---|---|---|---|
from | string (email) | no | max length 254 |
body | string | yes | min length 1, max length 200000 |
contentType | enum | no | one of: text, html |
attachments | array<object> | no | — |
curl -X POST 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>/reply' \
-H 'Authorization: Bearer am_...' \
-H 'Content-Type: application/json' \
-d '{
"from": "someone@example.com",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": []
}'The sent reply, plus optional spam/delivery notices - same shape as sending a message.
{
"message": {
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "sent",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Re: Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentBase64": "JVBERi0xLjQKJc...",
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
},
"spamNotice": null,
"deliveryWarning": null
}/api/v1/inboxes/:id/messages/:messageId/reply-allReply to everyone on a message: the original sender plus every other To and Cc recipient, minus this inbox's own addresses (Bcc recipients are never included). Same subject and threading rules as reply.
| Field | Type | Required | Constraints |
|---|---|---|---|
from | string (email) | no | max length 254 |
body | string | yes | min length 1, max length 200000 |
contentType | enum | no | one of: text, html |
attachments | array<object> | no | — |
curl -X POST 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>/reply-all' \
-H 'Authorization: Bearer am_...' \
-H 'Content-Type: application/json' \
-d '{
"from": "someone@example.com",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": []
}'The sent reply, plus optional spam/delivery notices - same shape as sending a message.
{
"message": {
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "sent",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "sales@acme.example",
"to": "someone@example.com",
"toList": [
"someone@example.com"
],
"cc": [
"colleague@example.com"
],
"bcc": [],
"recipientDeliveries": [
{
"address": "someone@example.com",
"status": "delivered",
"attempts": 0,
"nextRetryAt": null,
"lastError": null
},
{
"address": "colleague@example.com",
"status": "delivered",
"attempts": 0,
"nextRetryAt": null,
"lastError": null
}
],
"subject": "Re: Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentBase64": "JVBERi0xLjQKJc...",
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
},
"spamNotice": null,
"deliveryWarning": null
}/api/v1/inboxes/:id/messages/:messageId/forwardForward a message (and, by default, its attachments) to a new recipient, with an optional note above it. `from` may name one of the inbox's aliases.
| Field | Type | Required | Constraints |
|---|---|---|---|
from | string (email) | no | max length 254 |
to | string (email) | yes | max length 254 |
body | string | no | min length 1, max length 200000 |
contentType | enum | no | one of: text, html |
includeAttachments | boolean | no | default: true |
curl -X POST 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>/forward' \
-H 'Authorization: Bearer am_...' \
-H 'Content-Type: application/json' \
-d '{
"from": "someone@example.com",
"to": "someone@example.com",
"body": "Hi there — see the attached report.",
"contentType": "text",
"includeAttachments": true
}'The sent forward, plus optional spam/delivery notices - same shape as sending a message.
{
"message": {
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "sent",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Fwd: Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentBase64": "JVBERi0xLjQKJc...",
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
},
"spamNotice": null,
"deliveryWarning": null
}/api/v1/inboxes/:id/messages/:messageId/attachments/:attachmentIdDownload one attachment's raw bytes. Attachments are kept as long as their message; 410 Gone only for one removed under the former 90-day attachment retention.
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>/attachments/<attachmentId>' \ -H 'Authorization: Bearer am_...'
The file itself, with its own Content-Type and an attachment Content-Disposition.
Folders
/api/v1/inboxes/:id/messages/:messageId/moveMove a message to the inbox, to Trash, or into one of the inbox's custom folders (by id or full path). Drafts and mail held for spam review cannot be moved; Sent and Drafts are not destinations.
| Field | Type | Required | Constraints |
|---|---|---|---|
folder | string | yes | min length 1, max length 1100 |
curl -X POST 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>/move' \
-H 'Authorization: Bearer am_...' \
-H 'Content-Type: application/json' \
-d '{
"folder": "Clients/Acme"
}'The moved message - folder "custom" with the destination's customFolderId when it went into a custom folder.
{
"message": {
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "custom",
"previousFolder": null,
"trashedAt": null,
"customFolderId": "0f6c2a4e-3b1d-4c55-9a7e-2d8f1b6c9e10",
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentBase64": "JVBERi0xLjQKJc...",
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
}
}/api/v1/inboxes/:id/foldersList the inbox's custom folders (the system folders inbox/sent/draft/trash always exist and are not listed), sorted by path. Pass a folder's id or path as `folder` when listing messages.
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/folders' \ -H 'Authorization: Bearer am_...'
Every custom folder with its full path ("/"-separated), parent, and message/unread counts.
{
"folders": [
{
"id": "5d1e7b20-8c4a-4f3e-b2a9-6e0c3d7f1a42",
"inboxId": "inb_7c02f1",
"name": "Clients",
"parentId": null,
"path": "Clients",
"hasChildren": true,
"messageCount": 0,
"unreadCount": 0,
"createdAt": "2026-09-01T08:00:00.000Z"
},
{
"id": "0f6c2a4e-3b1d-4c55-9a7e-2d8f1b6c9e10",
"inboxId": "inb_7c02f1",
"name": "Acme",
"parentId": "5d1e7b20-8c4a-4f3e-b2a9-6e0c3d7f1a42",
"path": "Clients/Acme",
"hasChildren": false,
"messageCount": 12,
"unreadCount": 2,
"createdAt": "2026-09-01T08:00:00.000Z"
}
]
}Threads
/api/v1/inboxes/:id/threadsList the conversations in an inbox, newest activity first.
| Field | Type | Required | Constraints |
|---|---|---|---|
folder | enum | no | one of: inbox, sent, draft, trash |
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/threads?folder=inbox' \ -H 'Authorization: Bearer am_...'
One row per conversation: its latest message (attachment bytes omitted) and message/unread counts.
{
"threads": [
{
"threadId": "thr_e19a02",
"latestMessage": {
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "inbox",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
},
"messageCount": 3,
"unreadCount": 1
}
]
}/api/v1/inboxes/:id/threads/:threadIdEvery message in one conversation, oldest first.
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/threads/<threadId>' \ -H 'Authorization: Bearer am_...'
The messages in the thread (attachment bytes omitted).
{
"messages": [
{
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "inbox",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
}
]
}Search
/api/v1/messages/searchFull-text search (subject and body) across every inbox the caller can read, or one inbox via inboxId.
| Field | Type | Required | Constraints |
|---|---|---|---|
q | string | yes | min length 1, max length 200 |
inboxId | string | no | min length 1, max length 64 |
folder | enum | no | one of: inbox, sent, draft, trash |
page | number | no | default: 1, min 1 |
pageSize | number | no | default: 25, min 1, max 100 |
includeSpam | enum | no | one of: true, false |
curl -X GET 'https://anymail.tech/api/v1/messages/search?q=invoice&page=1&pageSize=25' \ -H 'Authorization: Bearer am_...'
One page of matches (attachment bytes omitted) and the total match count.
{
"messages": [
{
"id": "msg_e19a02",
"inboxId": "inb_7c02f1",
"mailServerId": "ms_3a91d0",
"ownerUserId": "usr_8f2c1e4a",
"folder": "inbox",
"previousFolder": null,
"trashedAt": null,
"customFolderId": null,
"previousCustomFolderId": null,
"from": "someone@example.com",
"to": "sales@acme.example",
"toList": [
"sales@acme.example"
],
"cc": [
"finance@acme.example"
],
"bcc": [],
"recipientDeliveries": [],
"subject": "Quarterly update",
"body": "Hi there — see the attached report.",
"contentType": "text",
"attachments": [
{
"id": "att_9b1",
"filename": "report.pdf",
"mimeType": "application/pdf",
"size": 48213,
"contentRemoved": false
}
],
"isRead": false,
"createdAt": "2026-08-18T14:22:00.000Z",
"spamStatus": "clean",
"spamScore": 0,
"spamReasons": [],
"spamReviewedAt": null,
"spamReviewedBy": null,
"deliveryStatus": "delivered",
"deliveryAttempts": 0,
"nextRetryAt": null,
"lastDeliveryError": null,
"messageIdHeader": "<e19a02@acme.example>",
"inReplyTo": null,
"references": [],
"threadId": "thr_e19a02",
"assignedToUserId": null
}
],
"total": 1,
"page": 1,
"pageSize": 25
}