Skip to content

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

GET
/api/v1/me

Fetch the caller's own account, including its mail storage usage.

Example request
curl -X GET 'https://anymail.tech/api/v1/me' \
  -H 'Authorization: Bearer am_...'
Response
200

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

GET
/api/v1/mail-servers

List mail servers owned by the caller (read-only - no create/attach-domain/delete here).

Example request
curl -X GET 'https://anymail.tech/api/v1/mail-servers' \
  -H 'Authorization: Bearer am_...'
Response
200

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"
    }
  ]
}
GET
/api/v1/mail-servers/:id

Fetch one owned mail server.

Example request
curl -X GET 'https://anymail.tech/api/v1/mail-servers/<id>' \
  -H 'Authorization: Bearer am_...'
Response
200

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

GET
/api/v1/mail-servers/:mailServerId/inboxes

List inboxes under a mail server, with their aliases (read-only - no create/delete or alias changes here).

Example request
curl -X GET 'https://anymail.tech/api/v1/mail-servers/<mailServerId>/inboxes' \
  -H 'Authorization: Bearer am_...'
Response
200

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
    }
  ]
}
GET
/api/v1/inboxes/:id

Fetch one owned inbox.

Example request
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>' \
  -H 'Authorization: Bearer am_...'
Response
200

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

GET
/api/v1/inboxes/:id/messages

List, filter and page through messages in an inbox (folder, sender/subject substring, unread, date range; cursor paging with limit).

Parameters
FieldTypeRequiredConstraints
folderstringnomin length 1, max length 1100
fromstringnomin length 1, max length 254
subjectstringnomin length 1, max length 200
unreadenumnoone of: true, false
unreadOnlyenumnoone of: true, false
includeSpamenumnoone of: true, false
sincestringno—
beforestringno—
limitnumbernomin 1, max 100
cursorstringnomin length 1, max length 512
Example request
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_...'
Response
200

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
}
POST
/api/v1/inboxes/:id/messages

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

Parameters
FieldTypeRequiredConstraints
fromstring (email)nomax length 254
tostring (email) | array<string (email)>yesmax length 254
ccstring (email) | array<string (email)>nomax length 254
bccstring (email) | array<string (email)>nomax length 254
subjectstringyesmin length 1, max length 200
bodystringyesmin length 1, max length 200000
contentTypeenumnoone of: text, html
attachmentsarray<object>no—
Example request
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": []
}'
Response
201

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
}
GET
/api/v1/inboxes/:id/messages/:messageId

Fetch one message (marks an unread inbox message as read).

Example request
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>' \
  -H 'Authorization: Bearer am_...'
Response
200

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
  }
}
PATCH
/api/v1/inboxes/:id/messages/:messageId

Mark a message read or unread (manager access or above).

Parameters
FieldTypeRequiredConstraints
readbooleanyes—
Example request
curl -X PATCH 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>' \
  -H 'Authorization: Bearer am_...' \
  -H 'Content-Type: application/json' \
  -d '{
  "read": false
}'
Response
200

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
  }
}
DELETE
/api/v1/inboxes/:id/messages/:messageId

Permanently delete a message. Only a message already in Trash can be deleted; the deletion is audit-logged.

Example request
curl -X DELETE 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>' \
  -H 'Authorization: Bearer am_...'
Response
204

Deleted - no response body.

POST
/api/v1/inboxes/:id/messages/:messageId/trash

Move a message to Trash (auto-purged after the retention period).

Example request
curl -X POST 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>/trash' \
  -H 'Authorization: Bearer am_...'
Response
200

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
  }
}
POST
/api/v1/inboxes/:id/messages/:messageId/restore

Restore a trashed message to the folder it came from.

Example request
curl -X POST 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>/restore' \
  -H 'Authorization: Bearer am_...'
Response
200

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
  }
}
POST
/api/v1/inboxes/:id/messages/:messageId/reply

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

Parameters
FieldTypeRequiredConstraints
fromstring (email)nomax length 254
bodystringyesmin length 1, max length 200000
contentTypeenumnoone of: text, html
attachmentsarray<object>no—
Example request
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": []
}'
Response
201

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
}
POST
/api/v1/inboxes/:id/messages/:messageId/reply-all

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

Parameters
FieldTypeRequiredConstraints
fromstring (email)nomax length 254
bodystringyesmin length 1, max length 200000
contentTypeenumnoone of: text, html
attachmentsarray<object>no—
Example request
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": []
}'
Response
201

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
}
POST
/api/v1/inboxes/:id/messages/:messageId/forward

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

Parameters
FieldTypeRequiredConstraints
fromstring (email)nomax length 254
tostring (email)yesmax length 254
bodystringnomin length 1, max length 200000
contentTypeenumnoone of: text, html
includeAttachmentsbooleannodefault: true
Example request
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
}'
Response
201

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
}
GET
/api/v1/inboxes/:id/messages/:messageId/attachments/:attachmentId

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

Example request
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/messages/<messageId>/attachments/<attachmentId>' \
  -H 'Authorization: Bearer am_...'
Response
200

The file itself, with its own Content-Type and an attachment Content-Disposition.

Folders

POST
/api/v1/inboxes/:id/messages/:messageId/move

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

Parameters
FieldTypeRequiredConstraints
folderstringyesmin length 1, max length 1100
Example request
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"
}'
Response
200

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
  }
}
GET
/api/v1/inboxes/:id/folders

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

Example request
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/folders' \
  -H 'Authorization: Bearer am_...'
Response
200

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

GET
/api/v1/inboxes/:id/threads

List the conversations in an inbox, newest activity first.

Parameters
FieldTypeRequiredConstraints
folderenumnoone of: inbox, sent, draft, trash
Example request
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/threads?folder=inbox' \
  -H 'Authorization: Bearer am_...'
Response
200

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
    }
  ]
}
GET
/api/v1/inboxes/:id/threads/:threadId

Every message in one conversation, oldest first.

Example request
curl -X GET 'https://anymail.tech/api/v1/inboxes/<id>/threads/<threadId>' \
  -H 'Authorization: Bearer am_...'
Response
200

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

GET
/api/v1/messages/search

Full-text search (subject and body) across every inbox the caller can read, or one inbox via inboxId.

Parameters
FieldTypeRequiredConstraints
qstringyesmin length 1, max length 200
inboxIdstringnomin length 1, max length 64
folderenumnoone of: inbox, sent, draft, trash
pagenumbernodefault: 1, min 1
pageSizenumbernodefault: 25, min 1, max 100
includeSpamenumnoone of: true, false
Example request
curl -X GET 'https://anymail.tech/api/v1/messages/search?q=invoice&page=1&pageSize=25' \
  -H 'Authorization: Bearer am_...'
Response
200

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
}