[SuperMailOS](/)

[Product](/#product)[Agents](/agents)[Pricing](/pricing)[Compare](/compare)[Tools](/tools)[Docs](/docs)

[Log in](/login)[Start free](/signup)

DocsAgent inboxes

Getting started

-   [Overview](/docs)
-   [Set up your domain’s DNS](/docs/dns-setup)
-   [Connect a mail app (IMAP/SMTP)](/docs/connect-mail-app)
-   [Migrate your existing mail](/docs/migrate)

Running your mail

-   [Deliverability & inbox placement](/docs/deliverability)
-   [Security: 2FA & sessions](/docs/security)

Developers

-   [API reference](/docs/api)
-   [Webhooks](/docs/webhooks)
-   [Connect your AI (MCP)](/docs/mcp)
-   [Agent inboxes](/docs/agents)

Resources

-   [Guides](/learn)
-   [Email checker](/tools/email-checker)
-   [System status](/status)
-   [Changelog](/changelog)

Getting started

-   [Overview](/docs)
-   [Set up your domain’s DNS](/docs/dns-setup)
-   [Connect a mail app (IMAP/SMTP)](/docs/connect-mail-app)
-   [Migrate your existing mail](/docs/migrate)

Running your mail

-   [Deliverability & inbox placement](/docs/deliverability)
-   [Security: 2FA & sessions](/docs/security)

Developers

-   [API reference](/docs/api)
-   [Webhooks](/docs/webhooks)
-   [Connect your AI (MCP)](/docs/mcp)
-   [Agent inboxes](/docs/agents)

Resources

-   [Guides](/learn)
-   [Email checker](/tools/email-checker)
-   [System status](/status)
-   [Changelog](/changelog)

[Home](/)[Docs](/docs)Agent inboxes

Developers

Copy page[.md](/docs/agents.md "Open this page as Markdown")

# Agent inboxes

Updated 16 Oct 2026

On this page 11 sections

-   [Create one](#create-one)
-   [In the app](#in-the-app)
-   [With the API](#with-the-api)
-   [Every agent endpoint](#every-agent-endpoint)
-   [Agent keys](#agent-keys)
-   [Sending rules and approvals](#sending-rules-and-approvals)
-   [When an email waits](#when-an-email-waits)
-   [Reading rules and held mail](#reading-rules-and-held-mail)
-   [What an agent reads](#what-an-agent-reads)
-   [The AI disclosure line](#the-ai-disclosure-line)
-   [Its own pause](#its-own-pause)
-   [Webhooks](#webhooks)
-   [MCP tools](#mcp-tools)
-   [Limits by plan](#limits-by-plan)
-   [Objects](#objects)
-   [AgentInbox](#agentinbox)
-   [AgentKey](#agentkey)
-   [AgentApproval](#agentapproval)
-   [AgentHold](#agenthold)

An agent inbox is an inbox of its own for an AI agent, on your verified domain, next to your team’s mailboxes. The agent reads and sends through the API or MCP, and people see its mail in the app like any other inbox. Every agent has a sponsor, a named person who answers for it, and the guardrails are on from the start.

-   **A person approves new recipients.** Replies, and email to people the agent already corresponds with, go out right away. An email to anyone new waits for a person.
-   **Spoofed mail is held back.** Mail whose sender fails authentication doesn’t reach the agent until a person releases it.
-   **It reads what a person would see.** Hidden text is removed from every message, and each one says how far its sender can be trusted.
-   **It says it’s an AI.** Every email it sends ends with a line saying an AI agent sent it, and for whom.
-   **It pauses on its own.** Complaints or bounces on its mail pause that agent alone, long before they could add up to a pause for your whole workspace.

## Create one

Agent inboxes live on a verified domain, so [set up your domain](/docs/dns-setup) first. Creating one is for workspace owners and admins.

### In the app

Open *Settings → Agents* and create the agent: its name (it signs its email with it), its address, its sponsor, how freely it may send and what it may read. You can create its key in the same step. The key is shown once.

### With the API

Use an owner’s or admin’s API key with the *Manage mail* scope. Only `name` is required; everything else has a safe default.

POST`/api/v1/inboxes`Manage mail

curl

```
curl -X POST "https://supermailos.com/api/v1/inboxes" \
  -H "Authorization: Bearer $SUPERMAILOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Billing assistant","localPart":"billing","sendMode":"known","inboundMode":"verified","createKey":{"scopes":["read","write","send"],"expiresInDays":90}}'
```

TypeScript

```
const res = await fetch("https://supermailos.com/api/v1/inboxes", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SUPERMAILOS_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "Billing assistant",
    "localPart": "billing",
    "sendMode": "known",
    "inboundMode": "verified",
    "createKey": {
      "scopes": [
        "read",
        "write",
        "send"
      ],
      "expiresInDays": 90
    }
  }),
});
if (!res.ok) throw new Error(`${res.status}: ${(await res.json()).error}`);
const data = await res.json();
```

Python

```
import os
import requests

res = requests.post(
    "https://supermailos.com/api/v1/inboxes",
    headers={
        "Authorization": f"Bearer {os.environ['SUPERMAILOS_API_KEY']}",
    },
    json={
        "name": "Billing assistant",
        "localPart": "billing",
        "sendMode": "known",
        "inboundMode": "verified",
        "createKey": {
            "scopes": ["read", "write", "send"],
            "expiresInDays": 90,
        },
    },
    timeout=30,
)
res.raise_for_status()
data = res.json()
```

Request body (JSON)

| Name | Type | Description |
| --- | --- | --- |
| namerequired | string | What the agent is called, such as `Billing assistant`. It signs its email with this name. |
| localPart | string | The part of its address before the @. Made from the name when you leave it out. |
| domain | string | One of your verified domains, by name or id. Your first verified domain when you leave it out. |
| sponsorUserId | string | The person who answers for the agent: approvals and alerts go to them. When you leave it out, the person the API key belongs to. |
| sendMode | approval | known | open | How freely it sends (see sending rules). Default `known`. |
| inboundMode | all | verified | allowlist | What it may read (see reading rules). Default `all`. |
| dailySendCap | integer | Emails it may send in 24 hours before the rest wait for a person. Default 100, at most 5000. |
| newRecipientsDailyCap | integer | In `open` mode, new recipients a day before the rest wait for a person. Default 20. |
| allowRecipients | string\[\] | Addresses or `@domains` it may write to without approval. |
| allowSenders | string\[\] | Addresses or `@domains` it may read in `allowlist` mode. |
| blockSenders | string\[\] | Addresses or `@domains` whose mail is never shown to it. |
| disclosure | boolean | End every email it sends with a line saying an AI agent sent it, and for whom. Default `true`; only a workspace admin can change it. |
| description | string | What the agent does, for the people who review it. |
| createKey | boolean or object | `true`, or `{ name?, scopes?, expiresInDays? }`, to create its agent key in the same call. The answer then carries the key, shown once. |

It answers `201` with the new `inbox` (an [AgentInbox](#agentinbox)) and, if you asked for one, its `key`. The key’s `secret` appears in this answer only, so store it now.

The inbox’s `id` is also its mailbox id. Pass it as `mailbox` to any mail endpoint or MCP tool, and the agent’s mail works like any other mailbox’s: list it, search it, reply from it.

### Every agent endpoint

Each one links to its full entry, with parameters and samples in curl, TypeScript and Python, in the [API reference](/docs/api).

| Operation | Endpoint | Scope |
| --- | --- | --- |
| [List agent inboxes](/docs/api#list-agent-inboxes) | `GET /inboxes` | read |
| [Create an agent inbox](/docs/api#create-an-agent-inbox) | `POST /inboxes` | write |
| [Get an agent inbox](/docs/api#get-an-agent-inbox) | `GET /inboxes/{id}` | read |
| [Update or pause an agent inbox](/docs/api#update-or-pause-an-agent-inbox) | `PATCH /inboxes/{id}` | write |
| [Delete an agent inbox](/docs/api#delete-an-agent-inbox) | `DELETE /inboxes/{id}` | write |
| [List an agent's keys](/docs/api#list-an-agents-keys) | `GET /inboxes/{id}/keys` | read |
| [Create an agent key](/docs/api#create-an-agent-key) | `POST /inboxes/{id}/keys` | write |
| [Revoke an agent key](/docs/api#revoke-an-agent-key) | `DELETE /inboxes/{id}/keys/{keyId}` | write |
| [List mail held back from agents](/docs/api#list-mail-held-back-from-agents) | `GET /holds` | read |
| [Release held mail to the agent](/docs/api#release-held-mail-to-the-agent) | `POST /holds/{id}/release` | write |
| [Keep held mail from the agent](/docs/api#keep-held-mail-from-the-agent) | `POST /holds/{id}/dismiss` | write |
| [List agent emails waiting for a person](/docs/api#list-agent-emails-waiting-for-a-person) | `GET /approvals` | read |
| [Get an approval](/docs/api#get-an-approval) | `GET /approvals/{id}` | read |
| [Approve and send an agent's email](/docs/api#approve-and-send-an-agents-email) | `POST /approvals/{id}/approve` | send |
| [Reject an agent's email](/docs/api#reject-an-agents-email) | `POST /approvals/{id}/reject` | write |

## Agent keys

An agent key reaches one agent inbox and nothing else: not your team’s mailboxes, not other agents. Give each agent its own key, and keep your own keys to yourself.

POST`/api/v1/inboxes/{id}/keys`Manage mail

curl

```
curl -X POST "https://supermailos.com/api/v1/inboxes/INBOX_ID/keys" \
  -H "Authorization: Bearer $SUPERMAILOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Production worker","scopes":["read","send"],"expiresInDays":30}'
```

-   **Create one** with this endpoint, or with `createKey` when you create the inbox. Owners and admins only.
-   **Scopes** are the usual three: read, write and send, all three unless you choose. Leave out send and the agent can read and draft, but never send.
-   **Expiry** is optional: `expiresInDays`, from 1 to 3650. Without it, the key works until you revoke it.
-   **It is shown once.** Revoke it with `DELETE /api/v1/inboxes/{id}/keys/{keyId}`. Deleting the inbox deletes its keys.

An agent key can’t approve or reject email, release held mail, change its own rules, or create agents and keys. Those are for people, and the MCP server hides those tools from an agent’s key.

Agent inboxes have no IMAP or SMTP app passwords. An agent works through the API or MCP, which is where its rules are enforced. To connect it to an MCP client, use its key as the bearer token for `https://supermailos.com/mcp`; the setup for each client is in [Connect your AI](/docs/mcp).

## Sending rules and approvals

The rules belong to the inbox, so they apply whichever API key sends from it. `sendMode` decides how freely it sends:

| sendMode | What happens |
| --- | --- |
| known (default) | Replies, and email to people the agent already corresponds with, go out right away. An email to a new recipient waits for a person. |
| approval | Every email waits for a person. |
| open | It sends on its own, up to 20 new recipients a day unless you change that. Past the limit, emails wait for a person. |

Two more settings apply in every mode:

-   `dailySendCap`: at most this many emails in 24 hours (default 100). Past it, emails wait for a person.
-   `allowRecipients`: addresses or whole domains (`@example.com`) the agent may always write to without approval.

People the agent already corresponds with are everyone who wrote to it and proved who they are (their email passed DMARC), everyone it has written to, the recipients of any email a person approved, and the senders of mail a person released to it. Anyone can write any address in an email’s From, so an unproven sender never counts.

### When an email waits

A send that has to wait still answers `202`, with `status: "pending_approval"`. Nothing was sent yet. An email that did go out also answers `202`, with `status: "sent"`, so check `status`, not the HTTP code.

202 · pending\_approval

```
{
  "ok": true,
  "status": "pending_approval",
  "approvalId": "apr_4f1c2b7e9a",
  "reasons": ["new recipient client@example.com"],
  "expiresAt": "2026-10-23T09:30:00.000Z",
  "mailboxId": "mbx_6e2a91c0d4",
  "from": "billing@acme.com"
}
```

Response · PendingSendResponse

| Name | Type | Description |
| --- | --- | --- |
| okrequired | boolean | `true`: the request was accepted. |
| statusrequired | string | `pending_approval`: nothing was sent yet. |
| approvalIdrequired | string | `GET /approvals/{approvalId}` for what became of it. |
| reasonsrequired | string\[\] | Why it waits, in plain words. |
| expiresAtrequired | string (date-time) | When it expires unless a person decides: 7 days after the agent asked. |
| mailboxIdrequired | string | The agent inbox it would go out from. |
| fromrequired | string (email) | The address it would go out from. |

The agent’s sponsor is alerted by email. Then a person who can send from the agent’s inbox decides, in the app or with the API. The app shows the email exactly as it would go out: its HTML as recipients see it, its plain-text version and the disclosure line.

-   **Approve** sends it as written, as the agent, through every usual check. It needs the *Send mail* scope.
-   **Reject** sends nothing. An optional `note` tells the agent why. It needs the *Manage mail* scope.

Approve · curl

```
curl -X POST "https://supermailos.com/api/v1/approvals/APPROVAL_ID/approve" \
  -H "Authorization: Bearer $SUPERMAILOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"note":"Looks right."}'
```

Reject · curl

```
curl -X POST "https://supermailos.com/api/v1/approvals/APPROVAL_ID/reject" \
  -H "Authorization: Bearer $SUPERMAILOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"note":"Don'\''t quote a price; ask them to call."}'
```

The agent finds out by polling `GET /api/v1/approvals/{id}`, or from the `agent.approval_decided` webhook. Its own key can never approve its own email. Each approval is in one of these states:

| status | Meaning |
| --- | --- |
| pending | Waiting for a person. |
| approved | A person approved it and it is being sent. |
| sent | Approved and sent as written. `result` has its `messageId` and `threadId`. |
| rejected | A person rejected it and nothing was sent. `decisionNote` carries their note, if they left one. |
| failed | Approved, but it couldn’t be sent. `result` says why. |
| expired | Nobody decided within 7 days. Nothing was sent. |

Retry a send with the same key and the same `Idempotency-Key` and you get the same approval back, so an email never waits twice. A different email under a key already used answers `422` `idempotency_key_reused`. Up to 200 emails can wait per agent; past that, its sends answer `429` until people catch up.

## Reading rules and held mail

SuperMailOS checks SPF, DKIM and DMARC on every message to an agent inbox itself, then decides whether the agent may read it. `inboundMode` sets how strict that is:

| inboundMode | What the agent reads |
| --- | --- |
| all (default) | Everything, except messages that fail authentication and mail from blocked senders. |
| verified | Only mail whose sender passed authentication. |
| allowlist | Only mail from senders on its allowlist, and only when they passed authentication. |

Failing authentication is specific: the sender’s domain tells receivers to reject or quarantine mail that fails its checks, and this message failed them. Mail from a domain without such a policy counts as unverified, not failed. In every mode, failing mail and mail from `blockSenders` stay away from the agent.

Mail the agent may not read is **held**: its conversation doesn’t exist for the agent’s key until a person releases it. People still see it in their inbox as usual, and the agent’s sponsor is alerted by email. Each hold says why, and a conversation’s hold shows the worst reason among its messages: a spoof that arrives in a conversation held for an unverified sender turns it into a spoof’s hold.

| reason | Why it was held |
| --- | --- |
| auth\_failed | The sender failed authentication (DMARC): it may not be who it claims to be. |
| blocked\_sender | The sender is on this agent's block list. |
| not\_allowlisted | The sender isn't on this agent's allowlist. |
| unverified\_sender | The sender couldn't be verified, and this agent only reads verified mail. |

A person who can manage the agent’s mail decides, in the app or with the API:

-   `GET /api/v1/holds` lists what is held. Add `?inbox=` for one agent.
-   `POST /api/v1/holds/{id}/release` lets the agent read the conversation from now on, fires `message.inbound` for it, and counts the sender as someone the agent corresponds with. Send the `reason` you reviewed (`{ "reason": "unverified_sender" }`): if a worse email has arrived in the conversation since, nothing is released and you get `409`.
-   `POST /api/v1/holds/{id}/dismiss` keeps it from the agent.

curl

```
curl "https://supermailos.com/api/v1/holds?inbox=INBOX_ID&status=held" \
  -H "Authorization: Bearer $SUPERMAILOS_API_KEY"
```

Release only mail you have looked at: a released message reaches the agent as it is. Until then, `message.inbound` doesn’t fire for it; the `message.held` webhook carries ids and the sender’s address only, never the subject or a snippet.

## What an agent reads

An agent’s key reads the visible text of a message, nothing more. Before it gets a message, we remove what a person reading it would never see: elements hidden by an inline style or by the email’s own stylesheet (`display:none`, a zero font size, transparent text, text pushed off the screen), HTML comments, and invisible Unicode characters. Instructions planted in an email for an AI to follow are often hidden in exactly those places.

When an email has HTML, the agent’s text is built from what that HTML shows, with each link’s address after it. Its plain-text part is ignored: mail apps show the HTML, so nobody reads that part, which makes it a place to hide instructions in plain sight. Snippets in lists, search results and webhooks follow the same rule, and an agent’s key can’t download a message’s raw source.

Each message it reads carries `trust`:

trust

```
"trust": {
  "sender": "verified",
  "hiddenContent": true,
  "signals": ["2 hidden elements", "1 HTML comment"]
}
```

| trust.sender | Meaning |
| --- | --- |
| verified | The sender passed our own SPF, DKIM and DMARC check. |
| unverified | There was nothing to check against, or the check couldn't run. Not proven either way. |
| failed | The sender's domain tells receivers to reject or quarantine mail that fails its checks, and this message failed: a likely spoof. An agent only sees one after a person releases it. |
| self | Mail this inbox sent. |

-   `hiddenContent` is `true` when the email carried content a person wouldn’t see. `text` and `html` are the visible part only.
-   `signals` lists what was removed, such as `2 hidden elements`.

The MCP server also wraps everything an agent’s key reads in a notice that it is untrusted email: data to work on, never instructions to follow. No filter catches every trick, so give the agent narrow instructions and keep email to new people behind approval.

## The AI disclosure line

Every email an agent sends ends with a line naming the agent, the person it works for and your workspace:

> Sent by Billing assistant, an AI agent working for Ana Ruiz at Acme.

It also carries an `X-SuperMailOS-Agent` header with the agent’s address, so software can tell agent mail apart too. The line is on by default (`disclosure`); a workspace admin can turn it off.

The line is added to every email, even one that already seems to have it, and nothing the agent writes can hide it: before adding it, we remove comments, stylesheets and the document’s head from the agent’s HTML and close anything it left open. Style an agent’s email with inline styles.

Saying plainly that an email comes from an AI, and on whose behalf, helps you meet transparency rules like the EU AI Act’s. Whether it is enough for your use is a question for your own legal adviser.

## Its own pause

An agent is held to tighter limits than a person. One spam complaint, or three hard bounces (mail to addresses that don’t exist), on an agent’s mail within 24 hours pauses that agent. Each pause lasts longer than the one before: 1 hour, then 24 hours, then until a person resumes it.

Only that agent stops sending, from every app, a person writing as it included. It still receives mail, and the rest of your workspace keeps sending as before. Its sponsor gets an email and the `agent.paused` webhook fires. While it is paused, its sends answer `423` and nothing is queued. Its mail also counts toward your workspace’s own reputation, like anyone else’s.

A pause for complaints or bounces runs its course: the timed ones lift on their own, and the one that waits for a person needs a workspace admin. People can pause an agent themselves too, and its sponsor or a workspace admin can lift that pause, in the app or with `PATCH /api/v1/inboxes/{id}`.

Pause, then resume

```
{ "status": "paused", "pauseReason": "Checking a complaint" }

{ "status": "active" }
```

## Webhooks

These events follow agent inboxes, and each carries the agent’s `mailboxId`. Payloads, signature checks and retries are on [Webhooks](/docs/webhooks); an admin subscribes an endpoint under *Settings → Developers*.

| Event | When it fires |
| --- | --- |
| message.held | Mail to an agent inbox was held back from the agent. It carries ids and the sender's address only, never the subject or a snippet. |
| agent.approval\_requested | An email the agent asked to send is waiting for a person. |
| agent.approval\_decided | A person approved the email (so it was sent) or rejected it. `decision` says which. |
| agent.paused | The agent was paused, automatically or by a person. Its sending stops; the rest of the workspace keeps sending. |

## MCP tools

The MCP server at `https://supermailos.com/mcp` has tools for agent inboxes next to the mail tools. Tools for people are hidden from an agent’s own key, which works its inbox with the ordinary mail tools (`list_threads`, `get_thread`, `reply_to_thread`, `send_email`) under the rules above.

| Tool | What it does | Scope | For |
| --- | --- | --- | --- |
| `list_agent_inboxes` | The workspace's AI agent inboxes: address, sponsor, pause state, send and read rules, and emails waiting for approval. | `read` | People and agents |
| `create_agent_inbox` | Creates an inbox of its own for an AI agent on your domain, with safe defaults. For people, not agents. | `write` | People |
| `update_agent_inbox` | Changes an AI agent's send and read rules, or pauses and resumes its sending. For people, not agents. | `write` | People |
| `list_agent_approvals` | Emails AI agents asked to send that wait for a person, with why they wait. An agent sees only its own outcomes. | `read` | People and agents |
| `decide_agent_approval` | Approves (sends) or rejects an email an AI agent asked to send. For people, not agents. | `send` | People |
| `list_held_mail` | Mail held back from AI agents because its sender failed authentication or isn't allowed. For people, not agents. | `read` | People |
| `decide_held_mail` | Releases held mail to the AI agent, or keeps it from the agent. For people, not agents. | `write` | People |

Creating an agent over MCP doesn’t create its key: that happens in the app or with the API. How to connect each client is in [Connect your AI](/docs/mcp).

## Limits by plan

Agent inboxes never count as paid seats. Each paid seat includes some, and the trial includes a few:

| Plan | Agent inboxes included |
| --- | --- |
| Pro | 2 with each paid seat |
| Business | 5 with each paid seat |
| 14\-day trial | 3 in total |

So a Business workspace with 4 paid seats can have 20 agent inboxes. Need more? Add a seat. At the limit, creating another answers `403` with the code `limit_reached`. Plans and seats are on the [pricing page](/pricing).

## Objects

The shapes the agent endpoints return. Fields marked required are always present; the rest appear when they apply.

### AgentInbox

An agent inbox and its settings. Its id is its mailbox id.

| Name | Type | Description |
| --- | --- | --- |
| idrequired | string | Also its mailbox id: pass it as `mailbox` to the mail endpoints. |
| addressrequired | string (email) | Its email address. |
| namerequired | string | What the agent is called; it signs its mail with it. |
| description | string | What the agent does, for the people who review it. |
| statusrequired | active | paused | `paused` while a pause is in force, otherwise `active`. |
| paused | object | While it is paused: `reason`, `by`, `since`, and `until` (absent when it waits for a person to resume it). |
| sponsorrequired | object | The person who answers for the agent: approvals and alerts go to them. |
| sendModerequired | approval | known | open | How freely it sends. |
| inboundModerequired | all | verified | allowlist | What it may read. |
| dailySendCaprequired | integer | Emails it may send in 24 hours before the rest wait for a person. |
| newRecipientsDailyCaprequired | integer | In `open` mode, new recipients a day before the rest wait for a person. |
| allowSendersrequired | string\[\] | Addresses or `@domains` the agent may read in `allowlist` mode. |
| blockSendersrequired | string\[\] | Never shown to the agent. |
| allowRecipientsrequired | string\[\] | The agent may write to these without approval. |
| disclosurerequired | boolean | Its mail ends with a line saying an AI agent sent it, for whom. |
| createdVia | app | api | mcp | Where it was created. |
| createdAtrequired | string (date-time) | When it was created. |
| updatedAt | string (date-time) | When its settings last changed. |
| pendingApprovals | integer | Emails waiting for a person (people's keys only). |

### AgentKey

A key that reaches one agent inbox. The secret appears only in the answer that created it.

| Name | Type | Description |
| --- | --- | --- |
| idrequired | string | The key's id, for revoking it. |
| namerequired | string | Its label. When you don't name it, `Agent:` followed by the agent's name. |
| prefixrequired | string | Non-secret leading characters. |
| scopesrequired | string\[\] | Any of `read`, `write` and `send`. |
| inboxIdrequired | string | The one agent inbox it reaches. |
| createdAtrequired | string (date-time) | When it was created. |
| lastUsedAt | string (date-time) | When it was last used. |
| expiresAt | string (date-time) | When it stops working, if it expires. |
| revokedAt | string (date-time) | When it was revoked. |
| secret | string | Only when it was just created: the key itself (`smk_…`). Shown once. |

### AgentApproval

An email an agent asked to send that waits, or waited, for a person. An agent's own key never gets the body or the Bcc line back.

| Name | Type | Description |
| --- | --- | --- |
| idrequired | string | The approval's id, to poll, approve or reject it. |
| inboxIdrequired | string | The agent inbox that asked. |
| kindrequired | send | reply | `send` for a new email, `reply` for a reply in a conversation. |
| threadId | string | The conversation, for a reply. |
| fromrequired | string (email) | The address it goes out from. |
| torequired | string | Recipients, as the agent wrote them. |
| ccrequired | string | Cc recipients, as the agent wrote them. |
| bcc | string | People's keys only. |
| subjectrequired | string | The subject the agent wrote. |
| text | string | The body the agent wrote (people's keys only). |
| html | string | Its HTML version, when it wrote one (people's keys only): what most mail apps show. |
| reasonsrequired | string\[\] | Why it waits, in plain words. |
| statusrequired | pending | approved | rejected | sent | failed | expired | Where it stands. See the states under sending rules. |
| createdAtrequired | string (date-time) | When the agent asked. |
| expiresAtrequired | string (date-time) | When it expires unless a person decides. |
| decidedAt | string (date-time) | When a person decided. |
| decisionNote | string | What the person said when deciding. |
| result | object | Once sent: `{ messageId, threadId, mailboxId }`. Once failed: `{ error, code }`. |

### AgentHold

Mail held back from an agent, and what a person decided.

| Name | Type | Description |
| --- | --- | --- |
| idrequired | string | The hold's id, to release or dismiss it. |
| inboxIdrequired | string | The agent inbox it was held from. |
| threadIdrequired | string | Hidden from the agent's key while held or dismissed. |
| emailId | string | The held message. |
| senderrequired | string (email) | The From address, and only the address. |
| reasonrequired | auth\_failed | blocked\_sender | not\_allowlisted | unverified\_sender | Why it was held. |
| reasonTextrequired | string | The reason in plain words. |
| verdictrequired | verified | unverified | failed | Our own authentication verdict for the sender. |
| auth | object | The SPF, DKIM and DMARC results. |
| statusrequired | held | released | dismissed | Held, released to the agent, or kept from it. |
| createdAtrequired | string (date-time) | When it was held. |
| decidedAt | string (date-time) | When a person released or dismissed it. |

Next: [the API reference](/docs/api) for every agent endpoint, or [webhooks](/docs/webhooks) to hear about approvals, holds and pauses as they happen.

Was this page helpful?

YesNo

[← PreviousConnect your AI (MCP)](/docs/mcp)

Stuck?

Write to [hello@supermailos.com](mailto:hello@supermailos.com). A person who can fix it reads every message.

[SuperMailOS](/)

Every domain you own, in one beautiful inbox. From $3 a mailbox.

Product

-   [Tour](/#product)
-   [Pricing](/pricing)
-   [Features](/features)
-   [Phone apps](/#iphone)
-   [Agent inboxes](/agents)
-   [MCP & API](/features/ai-agents)
-   [Changelog](/changelog)

Compare

-   [Google Workspace](/compare/google-workspace)
-   [Microsoft 365](/alternatives/microsoft-365-alternative)
-   [Zoho Mail](/compare/zoho)
-   [Fastmail](/compare/fastmail)
-   [AgentMail](/compare/agentmail)
-   [Cost calculator](/tools/email-cost-calculator)
-   [All comparisons](/compare)

Resources

-   [Docs](/docs)
-   [Developers](/docs/api)
-   [Learn](/learn)
-   [Use cases](/use-cases)
-   [Free tools](/tools)
-   [Glossary](/glossary)
-   [Status](/status)

Company

-   [About](/about)
-   [Contact](/contact)
-   [Brand](/brand)
-   [Privacy](/privacy)
-   [Terms](/terms)
-   [Refunds](/refund)
-   [Security](/security-policy)

More from Adee Labs

-   [SuperSplit](https://supersplit.app)Split expenses with friends
-   [SuperDiffs](https://www.superdiffs.com)AI code review for GitHub
-   [Image2Vector](https://image2vector.app)Image to SVG converter
-   [Adee Labs](https://adeelabs.com)Independent product studio

© 2026 SuperMailOS · Built by [Adee Labs](https://adeelabs.com)Every domain · one inbox