# Inboxes

An Extrovert **inbox** is a persistent email account with authenticated sending and IMAP-backed
receiving. It belongs to one agent in one project. It is not a forwarding alias or catch-all.

## Identity and addressing

Every inbox has:

- an opaque `id` such as `pmbx_…`, which is the stable API path key;
- an email `address`, accepted as a project-local path alias;
- fixed `org_id`, `project_id`, and `agent_id` ownership;
- a lifecycle `status`;
- an effective rolling 24-hour recipient limit;
- a read-only `direct_smtp_enabled` status for agent clients;
- optional display name, webhook URL, and metadata.

Use the opaque id for durable references. Do not parse meaning from it.

Omit `username` and `domain` to use the shared domain for the account's plan:

| Account | Address domain |
|---|---|
| Paid account without a custom domain | `extrovertmail.com` |
| Free account, when free signup is enabled | `free.extrovertmail.com` |
| Account with a verified custom domain | The selected customer domain |

Free signup is currently disabled. An existing `@free.extrovertmail.com` address remains valid after
an upgrade, but newly created paid inboxes use `extrovertmail.com` unless a verified custom domain is
selected.

### Shared-domain names

On both platform shared domains, Extrovert normalizes the local part to lowercase, removes spaces and
unsupported characters, and then requires at least five characters. Omit `username` to receive a
generated `agent-...` name.

The following normalized names are reserved on both domains:

`postmaster`, `admin`, `webadmin`, `legal`, `fraudmark`, `fraudmarc`, `keith`,
`melissa`, `richard`, `sydney`, `syd`, `john`, and `johnny`.

These restrictions do not apply to customer-owned domains.

```ts
const generated = await extrovert.inboxes.create();
const support = await extrovert.inboxes.create({ username: "support" });
const billing = await extrovert.inboxes.create({
  username: "billing",
  domain: "mail.acme.com",
  client_id: "billing-primary",
});
```

## Lifecycle

1. **Create.** Extrovert creates the receiving account, registers the authenticated sender, seals the
   connection credential, and returns the inbox. POST /v1/inboxes

2. **Inspect.** Fetch the inbox before sending. The single-inbox response includes
   `effective_review_policy`; list responses do not.

3. **Send and receive.** Outbound API, SDK, and MCP requests follow review, suppression, contact-list,
   and daily recipient controls. Incoming mail is available through messages, threads, webhooks, and
   `wait_for_email`.

4. **Manage.** Update the display name, webhook, metadata, or effective daily limit when the key has the
   required permission.

5. **Delete.** Deletion removes the receiving account, sender registration, and stored messages. It
   cannot be undone. DELETE /v1/inboxes/{inbox_id}

## Review policy applies to every outbound request

An inbox resolves its policy from the inbox override, then the account default, then the
`require_review` floor.

| Policy | Behavior |
|---|---|
| `require_review` | Every send, reply, and forward needs an intent and normally waits for human review |
| `allow_direct` | A bare outbound request may send immediately; an explicit review request still queues |
| `auto_send_graduated` | A message in a graduated category can send automatically only when every deterministic gate passes |

An agent can read `effective_review_policy` but cannot widen it. Under `require_review`, omitting
`intent.summary` returns `422 intent_required`; nothing is sent or queued.

Queued mail has not been delivered. Keep the returned `rr_…` id and wait for a terminal review event
or poll the review until `closed` is true.

## Daily send accounting

`daily_send_limit` is a rolling 24-hour **recipient** cap. A message sent to three recipients consumes
three units. A queued review consumes no capacity until delivery. A rejected request consumes none.

Changing the effective limit requires `mailbox:quota` plus read access and accepts values from 1 to
10,000. Enrollment keys can set the inherited limit for the agents they create; `0` in the console
means use the organization default.

Over-limit responses include `429` and `Retry-After`. See
[Rate limits and quotas](https://docs.extrovert.dev/operating/limits/) for the other limits that can apply.

## Metadata

Metadata stores small application values on the inbox:

```ts
const inbox = await extrovert.inboxes.create({
  metadata: { team: "support", tier: 2, monitored: true },
});

await extrovert.inboxes.update(inbox.id, {
  metadata: { tier: 3, monitored: null },
});
```

Values may be strings, numbers, or booleans. Updates are shallow merges. A key set to `null` is
removed, and top-level `null` clears the object. Nested objects and arrays are rejected. Metadata is
limited to the same project as the inbox.

## Receiving

| Method | Use it when |
|---|---|
| Messages and threads | You need bounded lists, search, read state, folders, or conversation history |
| Webhooks | A service needs signed push delivery |
| `wait_for_email` | A task needs the next matching message, OTP, or verification link in the current turn |

The console's **Mail** section exposes inboxes and conversations together. Its compose and reply
actions use the same API and review rules as an agent request.

## Portable email credentials

Exporting IMAP and SMTP configuration requires `mailbox:credentials` and an eligible paid plan. The
normal API, SDK, and MCP path does not require the connection password. A password grants IMAP access,
but it does not by itself authorize raw SMTP submission.
**Direct SMTP starts disabled:** `direct_smtp_enabled` is false for every inbox by default. Only a human administrator can enable
  it, and the account must retain paid entitlement. Disabling it takes effect even when an older
  password is still in use. Agent keys cannot change this setting.

Raw SMTP bypasses review, suppression and contact-list checks, unsubscribe injection, and platform
accounting. API, SDK, and MCP sends still follow the Review Loop even when direct SMTP is enabled.

The term **mailbox** appears in stable permission strings, fields such as `max_mailboxes`, and IMAP protocol
documentation. Product instructions and interface labels use **inbox**.

## Deletion and lifetime limits

Deleting an inbox does not refund the enrollment key's lifetime `max_mailboxes` count. This keeps a
copied enrollment key from creating and deleting repeatedly to bypass its cap.

Owning agents may perform lifecycle cleanup with `mailbox:create`; dedicated destructive access can use
`mailbox:delete`. Deleting a message or thread is separate from deleting the inbox.

## Next

- [Messages, threads, and search](https://docs.extrovert.dev/concepts/messages-and-threads/)
- [Domains and onboarding](https://docs.extrovert.dev/concepts/domains-and-onboarding/)
- [Review Loop agent contract](https://docs.extrovert.dev/review-loop/agent-contract/)
- [Deliverability and limits](https://docs.extrovert.dev/concepts/deliverability-and-limits/)