> ## Documentation Index
> Fetch the complete documentation index at: https://sendmux.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction

> Mailbox-scoped API endpoints for Sendmux mailbox credentials and connected apps.

The Sendmux Mailbox API is for mailbox-scoped access. Use it when a client should act as a mailbox, or as one mailbox from a connected-app mailbox set, without managing team-wide resources.

Team-wide mailbox provisioning stays in the [Management API](/api/introduction). High-volume provider-routed sending stays in the [Sending API](/sending-api/introduction).

## Base URL

All Mailbox API requests should be made to:

```text theme={null}
https://app.sendmux.ai/api/v1
```

## Authentication

Authenticate with a mailbox credential, connected-app access token, or agent access token from Sendmux. Pass it as a Bearer token in the `Authorization` header.

```bash theme={null}
curl https://app.sendmux.ai/api/v1/mailbox/me \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

Manual mailbox credentials are scoped to one mailbox. The same credential is also accepted as the mailbox password for SMTP submission and IMAP retrieval. Connected-app tokens can be granted one or more mailboxes, and each mailbox request is limited to that granted set. Agent access tokens use the `smx_agent_` prefix and are limited by their granted scopes. Root API keys are rejected on Mailbox API endpoints.

## Current endpoints

| Endpoint                                                         | Purpose                                                             |
| ---------------------------------------------------------------- | ------------------------------------------------------------------- |
| `GET /mailbox/mailboxes`                                         | List and search mailboxes granted to the bearer token.              |
| `GET /mailbox/me`                                                | Return the mailbox associated with the bearer token.                |
| `GET /mailbox/session`                                           | Return supported capabilities, limits, and current state tokens.    |
| `GET /mailbox/identity`                                          | Return the mailbox's default sender identity and signatures.        |
| `PATCH /mailbox/identity`                                        | Update the mailbox's sender name and signatures.                    |
| `GET /mailbox/identities`                                        | List sender identities available to the mailbox.                    |
| `GET /mailbox/messages`                                          | List messages with filters, sorting, and cursor pagination.         |
| `POST /mailbox/messages:batch-get`                               | Read exact message IDs with optional raw or clean body output.      |
| `POST /mailbox/messages:batch-update`                            | Update allowed flags for multiple messages.                         |
| `POST /mailbox/messages:batch-delete`                            | Move or permanently delete multiple messages.                       |
| `GET /mailbox/messages/count`                                    | Count messages matching filters without returning rows.             |
| `GET /mailbox/messages/query-changes`                            | Read filtered message-list index changes since a prior state.       |
| `GET /mailbox/messages/search-snippets`                          | Return subject and preview snippets for text searches.              |
| `GET /mailbox/messages/{message_id}`                             | Read a message, including bodies and attachment metadata.           |
| `GET /mailbox/messages/{message_id}/body`                        | Read raw body text, HTML, or both without cleaning.                 |
| `GET /mailbox/messages/{message_id}/content`                     | Read clean message content with body-cleaning controls.             |
| `PATCH /mailbox/messages/{message_id}`                           | Update mutable message flags; `If-Match` adds stale-edit checks.    |
| `DELETE /mailbox/messages/{message_id}`                          | Move or delete a message; `If-Match` adds stale-delete checks.      |
| `POST /mailbox/attachments:upload`                               | Upload an attachment for a later send request.                      |
| `GET /mailbox/messages/{message_id}/attachments/{attachment_id}` | Download an attachment.                                             |
| `POST /mailbox/messages/send`                                    | Send from the authenticated mailbox.                                |
| `GET /mailbox/threads`                                           | List conversation threads with filters and cursor pagination.       |
| `GET /mailbox/threads/{thread_id}`                               | Read thread metadata, message IDs, participants, and state.         |
| `GET /mailbox/threads/{thread_id}/messages`                      | List message summaries for one thread.                              |
| `GET /mailbox/threads/{thread_id}/content`                       | Read clean message content for one thread with cursor pagination.   |
| `GET /mailbox/folders`                                           | List folders.                                                       |
| `POST /mailbox/folders`                                          | Create a folder.                                                    |
| `GET /mailbox/folders/changes`                                   | Read folder object changes since a prior folder state.              |
| `GET /mailbox/folders/query-changes`                             | Read folder-list index changes since a prior query state.           |
| `GET /mailbox/folders/{folder_id}`                               | Read one folder.                                                    |
| `PATCH /mailbox/folders/{folder_id}`                             | Update a folder; `If-Match` adds stale-edit checks.                 |
| `DELETE /mailbox/folders/{folder_id}`                            | Delete an empty custom folder; `If-Match` adds stale-delete checks. |
| `GET /mailbox/submissions`                                       | List send submissions with filters and cursor pagination.           |
| `GET /mailbox/submissions/changes`                               | Read submission object changes since a prior state.                 |
| `GET /mailbox/submissions/{submission_id}`                       | Read one send submission.                                           |
| `GET /mailbox/quotas`                                            | List mailbox quota usage and limits.                                |
| `GET /mailbox/quotas/changes`                                    | Read quota object changes since a prior quota state.                |
| `GET /mailbox/usage`                                             | Read a compact usage view derived from quota records.               |
| `GET /mailbox/changes`                                           | Read message changes, or a typed resource state map.                |
| `GET /mailbox/events`                                            | Stream mailbox events with Server-Sent Events.                      |

Import the [Mailbox API Postman collection](/guides/postman-collection#choose-a-collection) when you want ready-made requests.

## Mailbox targeting for connected apps

Manual mailbox credentials always target their single mailbox. Omit `mailbox_id` when you use a manual `smx_mbx_` credential.

Connected-app tokens can grant a set of mailboxes. Use `GET /mailbox/mailboxes` to list or search the granted set, then pass the selected mailbox's `id` as `mailbox_id` on Mailbox API requests.

Self-registered agent tokens target their assigned mailbox. Omit `mailbox_id` when you use a pre-claim `smx_agent_` token. Pre-claim tokens can read and receive mail, but they cannot send. After owner approval, an app-resource `smx_agent_` token with `email.send` can send from the assigned mailbox.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/mailboxes?q=support" \
  -H "Authorization: Bearer connected_app_access_token"
```

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/messages?mailbox_id=mbx_clxxxxxxxxxxxxxxxxxxxxxxxxx&limit=10" \
  -H "Authorization: Bearer connected_app_access_token"
```

If a connected app has exactly one granted mailbox, Mailbox API requests use that mailbox by default. If several mailboxes are granted and you omit `mailbox_id`, Sendmux returns `400 missing_parameter`. If you pass a mailbox outside the grant, Sendmux returns `403 insufficient_permissions`.

## Capability discovery

Use `GET /mailbox/session` before planning a mailbox workflow. It returns the
selected mailbox, supported Mailbox API features, current state
tokens, request limits, and gated features. A gated feature is intentionally
unavailable through the Mailbox API.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/session" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "mailbox": {
      "id": "mbx_clxxxxxxxxxxxxxxxxxxxxxxxxx",
      "email": "agent@example.com",
      "display_name": "Agent"
    },
    "states": {
      "messages": "email_state_token",
      "folders": "folder_state_token",
      "threads": "thread_state_token",
      "submissions": "submission_state_token",
      "identities": "identity_state_token",
      "quotas": "quota_state_token"
    },
    "capabilities": {
      "messages": {
        "list": true,
        "query_changes": true,
        "batch_update": true,
        "keywords": true,
        "update_fields": ["seen", "flagged", "keywords"]
      },
      "identities": {
        "list": true,
        "update": true
      },
      "attachments": {
        "upload": true,
        "download": true,
        "parsing": false
      }
    },
    "limits": {
      "list_limit_max": 100,
      "changes_limit_max": 500,
      "batch_ids_max": 100,
      "body_chars_max": 1000000,
      "inline_attachment_bytes_max": 5000000,
      "attachment_upload_bytes_max": 7500000,
      "outbound_raw_message_bytes_max": 26214400,
      "keywords_per_update_max": 50
    },
    "gated": {
      "identity_mutation": false,
      "quota_mutation": true,
      "filter_script_writes": true,
      "events": false,
      "raw_protocol": true,
      "attachment_parsing": true
    }
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

<Note>
  `gated` fields are `true` when a feature is intentionally unavailable.
</Note>

## Operational resources

Operational endpoints expose what an agent needs to send safely and monitor
mailbox health without adding mutation authority.

### Sender identities

Use `GET /mailbox/identity` to read the mailbox's default sender name and
signatures. Use `PATCH /mailbox/identity` to update `name`,
`text_signature`, and `html_signature`.
Mailbox API sends use this sender name by default and append the matching
plain text or HTML signature when the send body includes that format.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/identity" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```bash theme={null}
curl -X PATCH "https://app.sendmux.ai/api/v1/mailbox/identity" \
  -H "Authorization: Bearer smx_mbx_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Support",
    "text_signature": "Regards",
    "html_signature": "<p>Regards</p>"
  }'
```

`GET /mailbox/identities` lists all sender identities available to the
authenticated mailbox.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/identities" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```json theme={null}
{
  "ok": true,
  "data": [
    {
      "id": "id_123",
      "name": "Support",
      "email": "support@example.com",
      "reply_to": [],
      "bcc": [],
      "text_signature": "Regards",
      "html_signature": "<p>Regards</p>",
      "may_delete": false
    }
  ],
  "pagination": {
    "has_more": false
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx",
    "identity_state": "identity_state_token"
  }
}
```

### Send submissions

Use submissions to inspect queued, sent, failed, or cancelled send lifecycle
records separately from the `messages/send` request that created them.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/submissions?email_ids=msg_123&limit=10" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

Useful filters:

| Parameter        | Purpose                                        |
| ---------------- | ---------------------------------------------- |
| `identity_ids`   | Comma-separated identity IDs.                  |
| `email_ids`      | Comma-separated message IDs.                   |
| `thread_ids`     | Comma-separated thread IDs.                    |
| `undo_status`    | Match a specific submission undo state.        |
| `after`          | Match submissions sent at or after this time.  |
| `before`         | Match submissions sent before this time.       |
| `cursor`         | Continue from a previous page.                 |
| `limit`          | Return `1` to `100` submissions.               |
| `sort_by`        | Sort by `send_at`, `email_id`, or `thread_id`. |
| `sort_direction` | Sort `asc` or `desc`.                          |

Read one submission with `GET /mailbox/submissions/{submission_id}`. Poll
`GET /mailbox/submissions/changes?since_state=...` to sync submission object
changes.

### Quotas and usage

Use quotas for detailed limits and `usage` for a compact health view.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/usage" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "resources": [
      {
        "quota_id": "quota_123",
        "name": "Mailbox storage",
        "resource_type": "octets",
        "scope": "account",
        "types": ["Mail"],
        "used": 536870912,
        "hard_limit": 1073741824,
        "warn_limit": 858993459,
        "soft_limit": null,
        "percent_used": 50,
        "limit_status": "ok"
      }
    ],
    "states": {
      "quota_state": "quota_state_token"
    }
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

Quota filters:

| Parameter        | Purpose                                  |
| ---------------- | ---------------------------------------- |
| `name`           | Match quota name text.                   |
| `scope`          | Match `account`, `domain`, or `global`.  |
| `resource_type`  | Match `count` or `octets`.               |
| `type`           | Match a resource family, such as `Mail`. |
| `cursor`         | Continue from a previous page.           |
| `limit`          | Return `1` to `100` quotas.              |
| `sort_by`        | Sort by `name` or `used`.                |
| `sort_direction` | Sort `asc` or `desc`.                    |

Poll `GET /mailbox/quotas/changes?since_state=...` to sync quota changes.

## Thread APIs

Use thread endpoints when you need conversation-level context without fetching
every body.

### List threads

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/threads?q=invoice&participant=sender@example.com&folder_id=inbox&is_unread=true&limit=10" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```json theme={null}
{
  "ok": true,
  "data": [
    {
      "id": "thr_123",
      "subject": "Invoice question",
      "message_count": 2,
      "unread_count": 1,
      "has_attachments": true,
      "folder_ids": ["inbox"],
      "participants": [
        { "email": "sender@example.com", "name": "Sender" },
        { "email": "agent@example.com", "name": "Agent" }
      ],
      "last_message": {
        "id": "msg_456",
        "thread_id": "thr_123",
        "subject": "Re: Invoice question",
        "preview": "Thanks, I found it.",
        "has_attachments": false
      },
      "states": {
        "thread_state": "thread_state_token",
        "email_state": "message_state_token"
      }
    }
  ],
  "pagination": {
    "has_more": false
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx",
    "query_state": "thread_query_state_token"
  }
}
```

Thread list filters:

| Parameter        | Purpose                                            |
| ---------------- | -------------------------------------------------- |
| `q`              | Search common address, subject, and body text.     |
| `participant`    | Match sender or recipient addresses.               |
| `folder_id`      | Restrict results to one folder.                    |
| `is_unread`      | Match unread or read threads.                      |
| `has_attachment` | Match threads with or without attachment metadata. |
| `after`          | Match threads with messages at or after this time. |
| `before`         | Match threads with messages before this time.      |
| `cursor`         | Continue from a previous page.                     |
| `limit`          | Return `1` to `100` threads.                       |
| `sort_direction` | Sort by most recent message, `desc` or `asc`.      |

### Read a thread

```bash theme={null}
curl https://app.sendmux.ai/api/v1/mailbox/threads/thr_123 \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

The response includes the same thread metadata as the list endpoint plus
`message_ids` in chronological order. Use
`GET /mailbox/threads/{thread_id}/messages` for paginated message summaries, or
`GET /mailbox/threads/{thread_id}/content` when you need cleaned bodies.

## Retrieval precision APIs

Use exact retrieval and count endpoints when you already know what you need.
This keeps client payloads small and avoids fetching message bodies just to
answer count or search-preview questions.

### Rich message filters

`GET /mailbox/messages` and `GET /mailbox/messages/count` support these
filters. `GET /mailbox/messages/search-snippets` and
`GET /mailbox/messages/query-changes` support the same filters except
`thread_id`; pass `message_ids` when you already know the exact messages to
snippet.

| Parameter        | Purpose                                                        |
| ---------------- | -------------------------------------------------------------- |
| `folder_id`      | Restrict results to one folder.                                |
| `thread_id`      | Restrict list/count to one thread. Not supported for snippets. |
| `q`              | Search common address, subject, and body text.                 |
| `from`           | Search the From header.                                        |
| `to`             | Search the To header.                                          |
| `cc`             | Search the Cc header.                                          |
| `bcc`            | Search the Bcc header.                                         |
| `subject`        | Search subject text.                                           |
| `body`           | Search body text.                                              |
| `header_name`    | Match messages with a specific header.                         |
| `header_value`   | Match text inside `header_name`.                               |
| `min_size_bytes` | Match messages at least this many bytes.                       |
| `max_size_bytes` | Match messages smaller than this many bytes.                   |
| `keyword`        | Match messages with a keyword, such as `$seen`.                |
| `not_keyword`    | Match messages without a keyword.                              |
| `after`          | Match messages received at or after this timestamp.            |
| `before`         | Match messages received before this timestamp.                 |
| `has_attachment` | Match messages with or without attachments.                    |
| `is_unread`      | Match unread or read messages.                                 |

<Note>
  `thread_id` uses the thread's message order and cannot be combined with other
  message filters. Use the thread content endpoint when you need cleaned bodies
  for one conversation.
</Note>

### Count messages

Use the count endpoint when you only need the number of matches.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/messages/count?body=invoice&after=2026-05-01T00:00:00Z" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "total": 12,
    "sync_state": "state_token"
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

### Search snippets

Use snippets to decide which matching messages deserve a full fetch. Snippets
may include `<mark>` tags around matched terms.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/messages/search-snippets?q=invoice&limit=5" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "snippets": [
      {
        "message_id": "msg_123",
        "subject": "Question about <mark>invoice</mark>",
        "preview": "Can you resend the <mark>invoice</mark> for April?"
      }
    ],
    "not_found": [],
    "sync_state": "state_token"
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

Pass `message_ids` as a comma-separated list when you already have exact
messages:

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/messages/search-snippets?q=invoice&message_ids=msg_123,msg_456" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

### Batch get messages

Use batch get when you have exact IDs and want one request instead of one call
per message.

```bash theme={null}
curl https://app.sendmux.ai/api/v1/mailbox/messages:batch-get \
  -H "Authorization: Bearer smx_mbx_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": ["msg_123", "msg_456"],
    "body_mode": "clean_json",
    "part": "text",
    "max_body_chars": 50000,
    "strip_signature": true,
    "strip_quotes": true,
    "include_links": true,
    "include_html": false,
    "include_headers": "selected",
    "include_attachments": "metadata"
  }'
```

```json theme={null}
{
  "ok": true,
  "data": {
    "messages": [
      {
        "message": {
          "id": "msg_123",
          "thread_id": "thr_123",
          "subject": "Invoice question",
          "preview": "Can you resend the invoice?",
          "has_attachments": true
        },
        "raw_body": null,
        "content": {
          "id": "msg_123",
          "thread_id": "thr_123",
          "subject": "Invoice question",
          "body": {
            "format": "text",
            "text": "Can you resend the invoice?",
            "html": null,
            "is_truncated": false,
            "truncated_at_chars": null,
            "signature_stripped": false,
            "quotes_stripped": false,
            "extracted_links": []
          },
          "attachments": [
            {
              "id": "att_123",
              "filename": "invoice.pdf",
              "content_type": "application/pdf",
              "size_bytes": 12345,
              "disposition": "attachment",
              "content_id": null,
              "download_url": "/api/v1/mailbox/messages/msg_123/attachments/att_123"
            }
          ]
        }
      }
    ],
    "not_found": [],
    "states": {
      "email_state": "state_token"
    }
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

Batch body modes:

| `body_mode`  | Output                                                                      |
| ------------ | --------------------------------------------------------------------------- |
| `none`       | Message summaries only.                                                     |
| `raw`        | Message summaries plus `raw_body`. Supports `part=text`, `html`, or `both`. |
| `clean_json` | Message summaries plus `content`. Supports the clean controls below.        |

### Batch update messages

Use batch update to set allowed flags and keywords on up to 100 messages in one
state-safe request. `keywords` is a map where `true` sets a keyword and `false`
clears it. Keyword names are normalised to lowercase. Lifecycle keywords such
as `$draft` are read-only.

```bash theme={null}
curl -X POST https://app.sendmux.ai/api/v1/mailbox/messages:batch-update \
  -H "Authorization: Bearer smx_mbx_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": ["msg_123", "msg_456"],
    "seen": true,
    "keywords": {
      "agent_triaged": true,
      "needs_reply": false
    },
    "if_in_state": "message_state_token"
  }'
```

```json theme={null}
{
  "ok": true,
  "data": {
    "updated": ["msg_123", "msg_456"],
    "not_found": [],
    "failed": [],
    "states": {
      "old_state": "message_state_token",
      "new_state": "message_state_token_2"
    }
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

### Batch delete messages

Use batch delete to move up to 100 messages to Trash. Set `permanent=true` only
when the messages should be permanently removed.

```bash theme={null}
curl -X POST https://app.sendmux.ai/api/v1/mailbox/messages:batch-delete \
  -H "Authorization: Bearer smx_mbx_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": ["msg_123", "msg_456"],
    "permanent": false,
    "if_in_state": "message_state_token"
  }'
```

```json theme={null}
{
  "ok": true,
  "data": {
    "deleted": ["msg_123", "msg_456"],
    "not_found": [],
    "failed": [],
    "states": {
      "old_state": "message_state_token",
      "new_state": "message_state_token_2"
    }
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

<Note>
  Batch update and delete accept `if_in_state` for stale-write protection. Use
  the latest message state from message lists, detail reads, batch reads, or
  change endpoints.
</Note>

## Message body APIs

Use the raw body endpoint when you need the message body exactly as available from the mailbox.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/messages/msg_123/body?part=both&max_body_chars=50000" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "id": "msg_123",
    "thread_id": "thr_123",
    "part": "both",
    "body": {
      "text": "Original body text...",
      "html": "<p>Original body HTML...</p>",
      "is_truncated": false,
      "truncated_at_chars": null
    },
    "states": {
      "email_state": "state_token"
    }
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

Use the clean content endpoint when you want deterministic body cleaning and structured metadata.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/messages/msg_123/content?strip_signature=true&strip_quotes=true&include_links=true&include_html=false&include_headers=selected&include_attachments=metadata" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "id": "msg_123",
    "thread_id": "thr_123",
    "subject": "Invoice question",
    "body": {
      "format": "text",
      "text": "Clean body text...",
      "html": null,
      "is_truncated": false,
      "truncated_at_chars": null,
      "signature_stripped": true,
      "quotes_stripped": true,
      "extracted_links": ["https://example.com/invoice"]
    },
    "attachments": [
      {
        "id": "att_123",
        "filename": "invoice.pdf",
        "content_type": "application/pdf",
        "size_bytes": 12345,
        "disposition": "attachment",
        "content_id": null,
        "download_url": "/api/v1/mailbox/messages/msg_123/attachments/att_123"
      }
    ]
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

Clean content controls:

| Parameter             | Values                     | Default                                           | Applies to                                        |
| --------------------- | -------------------------- | ------------------------------------------------- | ------------------------------------------------- |
| `part`                | `auto`, `text`, `html`     | `auto`                                            | Message content, thread content, batch clean JSON |
| `max_body_chars`      | `1` to `1000000`           | `100000` for messages, `25000` per thread message | Raw body, message content, thread content, batch  |
| `strip_signature`     | `true`, `false`            | `true`                                            | Message content, thread content, batch clean JSON |
| `strip_quotes`        | `true`, `false`            | `true`                                            | Message content, thread content, batch clean JSON |
| `include_links`       | `true`, `false`            | `true`                                            | Message content, thread content, batch clean JSON |
| `include_html`        | `true`, `false`            | `false`                                           | Message content, thread content, batch clean JSON |
| `include_headers`     | `none`, `selected`, `full` | `selected`                                        | Message content, thread content, batch clean JSON |
| `include_attachments` | `none`, `metadata`         | `metadata`                                        | Message content, thread content, batch clean JSON |
| `cursor`              | Opaque cursor              | none                                              | Thread content                                    |
| `limit`               | `1` to `100`               | `25`                                              | Thread content                                    |

<Note>
  Body endpoints do not parse attachment contents. Attachments are returned as
  metadata or downloaded separately. PDF, CSV, Office document, and OCR parsing
  are not part of these APIs.
</Note>

## Attachments

Use `POST /mailbox/attachments:upload` for binary files up to 7.5 MB. Send the
raw bytes in the request body, then pass the returned `blob_id` to
`POST /mailbox/messages/send`. Final outbound messages, including bodies,
headers, and encoded attachments, must fit inside the 25 MB raw message limit.

```bash theme={null}
curl -X POST "https://app.sendmux.ai/api/v1/mailbox/attachments:upload?filename=invoice.pdf" \
  -H "Authorization: Bearer smx_mbx_your_key_here" \
  -H "Content-Type: application/pdf" \
  --data-binary "@invoice.pdf"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "blob_id": "blob_123",
    "filename": "invoice.pdf",
    "content_type": "application/pdf",
    "size_bytes": 12345
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

Then send the uploaded attachment by ID:

```bash theme={null}
curl -X POST https://app.sendmux.ai/api/v1/mailbox/messages/send \
  -H "Authorization: Bearer smx_mbx_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "to": [{ "email": "customer@example.com" }],
    "subject": "Invoice",
    "text_body": "Attached is your invoice.",
    "attachments": [
      {
        "filename": "invoice.pdf",
        "content_type": "application/pdf",
        "blob_id": "blob_123"
      }
    ]
  }'
```

Small inline base64 attachments are still supported on `messages/send`, but the
upload endpoint avoids large JSON request bodies.

Attachment downloads support byte ranges:

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/messages/msg_123/attachments/att_123" \
  -H "Authorization: Bearer smx_mbx_your_key_here" \
  -H "Range: bytes=0-1048575" \
  --output invoice.part
```

## Sync APIs

Use sync endpoints to poll for changes with state tokens returned by earlier
responses, or open an event stream when a client needs live updates.

### Event stream

`GET /mailbox/events` streams mailbox events as Server-Sent Events. Use it for
agents, CLIs, MCP servers, and SDKs that need to react when inbound mail arrives.
Use [webhooks](/guides/webhooks-setup) instead when a backend service should
receive signed event POSTs without keeping a live connection open.

```bash theme={null}
curl -N "https://app.sendmux.ai/api/v1/mailbox/events?event_types=message.received,message.received.spam" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```text theme={null}
id: evt_clxxxxxxxxxxxxxxxxxxxxxxxxx
event: message.received
data: {"event_type":"message.received","mailbox_id":"mbx_clxxxxxxxxxxxxxxxxxxxxxxxxx","message_id":"msg_123","message":{"id":"msg_123","subject":"New reply","preview":"Thanks for the update.","body":{"text":"Thanks for the update.","html":null,"is_truncated":false,"max_bytes":16384}}}
```

Each received-message event includes subject, participants, preview, attachment
metadata, and a capped body snapshot. Use the message and attachment endpoints
when you need full content or attachment bytes.

To resume after a disconnect, pass the last SSE `id` as the `Last-Event-ID`
header or the `last_event_id` query parameter. If the stream sends
`sync_required`, call `GET /mailbox/changes` before reopening the stream.

Optional query parameters:

| Parameter       | Purpose                                                                      |
| --------------- | ---------------------------------------------------------------------------- |
| `event_types`   | Comma-separated list of `message.received` and `message.received.spam`.      |
| `ping`          | Heartbeat interval in seconds, from `10` to `300`.                           |
| `close_after`   | Close the stream after `30` to `3600` seconds. Omit for a long-lived stream. |
| `last_event_id` | Replay events after a prior SSE event ID.                                    |

### Message query changes

`GET /mailbox/messages/query-changes` tracks how a filtered message list has
changed since a prior `query_state`. Omit `since_query_state` to get the
current query state for a filter without a change list.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/messages/query-changes?since_query_state=message_query_state_token&q=invoice&limit=100" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "old_query_state": "message_query_state_token",
    "new_query_state": "message_query_state_token_2",
    "has_more": false,
    "removed": ["msg_old"],
    "added": [{ "id": "msg_new", "index": 0 }],
    "total": null
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

### Folder changes

`GET /mailbox/folders/changes` tracks folder object changes. Omit
`since_state` to get the current folder state without a change list.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/folders/changes?since_state=folder_state_token" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

### Folder query changes

`GET /mailbox/folders/query-changes` tracks folder-list ordering changes. Omit
`since_query_state` to get the current folder query state.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/folders/query-changes?since_query_state=folder_query_state_token" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

### Typed mailbox changes

`GET /mailbox/changes` keeps the legacy message-only response when `types` is
omitted. Pass a comma-separated `types` list to receive a typed state map.

```bash theme={null}
curl "https://app.sendmux.ai/api/v1/mailbox/changes?types=messages,folders,threads,submissions,identities,quotas" \
  -H "Authorization: Bearer smx_mbx_your_key_here"
```

```json theme={null}
{
  "ok": true,
  "data": {
    "types": {
      "messages": {
        "old_state": "message_state_token",
        "new_state": "message_state_token_2",
        "has_more": false,
        "created": ["msg_789"],
        "updated": [],
        "destroyed": []
      },
      "folders": {
        "old_state": "folder_state_token",
        "new_state": "folder_state_token_2",
        "has_more": false,
        "created": [],
        "updated": ["inbox"],
        "destroyed": []
      },
      "threads": {
        "old_state": "thread_state_token",
        "new_state": "thread_state_token_2",
        "has_more": false,
        "created": [],
        "updated": ["thr_123"],
        "destroyed": []
      },
      "submissions": {
        "old_state": "submission_state_token",
        "new_state": "submission_state_token_2",
        "has_more": false,
        "created": [],
        "updated": ["sub_123"],
        "destroyed": []
      },
      "identities": {
        "old_state": "identity_state_token",
        "new_state": "identity_state_token_2",
        "has_more": false,
        "created": [],
        "updated": ["id_123"],
        "destroyed": []
      },
      "quotas": {
        "old_state": "quota_state_token",
        "new_state": "quota_state_token_2",
        "has_more": false,
        "created": [],
        "updated": ["quota_123"],
        "destroyed": []
      }
    }
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

Supported `types` values are `messages`, `folders`, `threads`, `submissions`,
`identities`, and `quotas`.

## Response format

The Mailbox API uses the same envelope as the Management API.

### Success

```json theme={null}
{
  "ok": true,
  "data": {
    "id": "mbx_clxxxxxxxxxxxxxxxxxxxxxxxxx",
    "email": "agent@example.com"
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

### Error

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "not_found",
    "message": "Mailbox not found.",
    "doc_url": "https://sendmux.ai/docs/api/errors#not_found",
    "retryable": false
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

Every response includes an `X-Request-Id` header matching `meta.request_id`. Include that value when contacting support.

## Rate limiting

Mailbox API keys are rate-limited to **1800 requests per minute**. Rate limit headers are included on responses:

```http theme={null}
X-RateLimit-Limit: 1800
X-RateLimit-Remaining: 1794
X-RateLimit-Reset: 1679313700
```

When the limit is exceeded, the API returns `429 rate_limit_exceeded` with a `Retry-After` header.

## Conventions

* **snake\_case** fields in JSON request and response bodies
* **UTC ISO 8601 timestamps** in RFC 3339 format: `2026-03-19T10:30:00Z`
* **Opaque IDs only** for mailbox, message, folder, and attachment resources
* **`Cache-Control: no-store`** on authenticated responses
* **Weak `ETag`** headers on single-resource GETs where supported
* **Header-based idempotency** for retriable POST requests where supported

## OpenAPI specification

Mailbox API endpoints are included in the app API specification:

```text theme={null}
https://app.sendmux.ai/api/v1/openapi.json
```
