# Create an inbox

Create an inbox with a limited agent key that includes `mailbox:create`. The key's organization and
project are fixed, so you do not choose a tenant in the request.
**Need a credential?:** In the console, issue an enrollment key when setup needs to create the agent. Create an API key when
  the agent already exists. For a remote MCP client, hosted OAuth avoids copying either secret into
  client configuration.

## Create the inbox

Omit `username` and `domain` to use `extrovertmail.com` on a paid account. Free accounts will use
`free.extrovertmail.com` when free signup is enabled. Add a stable idempotency value when the same
request may be retried.

```bash frame="terminal"
export EXTROVERT_API_BASE_URL="https://api.extrovert.dev"
export EXTROVERT_API_KEY="pk_agent_…"

curl -sS -X POST "$EXTROVERT_API_BASE_URL/v1/inboxes" \
  -H "Authorization: Bearer $EXTROVERT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: support-primary" \
  -d '{ "display_name": "Support agent" }'
```

The `201` response includes an opaque `id`, address, project and organization ids, the effective
daily recipient limit, and `direct_smtp_enabled`. It does not return a password unless a paid caller
explicitly requests credentials with the separate `mailbox:credentials` permission. Treat the opaque
`id` as the stable path key. The address is also accepted as a project-local alias.

  ```bash frame="terminal"
npm install @extrovert.dev/sdk@next
```

```ts title="create-inbox.ts"
import { Extrovert } from "@extrovert.dev/sdk";

const extrovert = new Extrovert({ apiKey: process.env.EXTROVERT_API_KEY! });
const inbox = await extrovert.inboxes.create({
  display_name: "Support agent",
  client_id: "support-primary",
});

console.log(inbox.id);
console.log(inbox.address);
```

`inboxes.create()` returns an `InboxHandle` with methods such as `send`, `reply`, `messages`,
`threads`, `waitForEmail`, `update`, and `delete`.

  Connect the MCP client first, then call:

```json title="create_inbox"
{
  "name": "create_inbox",
  "arguments": {
    "display_name": "Support agent",
    "client_id": "support-primary"
  }
}
```

The structured result includes the same inbox object as the REST response.

  ## Read the review policy

Fetch the inbox before the first outbound request. The single-inbox response includes
`effective_review_policy`; list responses omit it.

```ts
await inbox.refresh();
console.log(inbox.record?.effective_review_policy);
```

New accounts use `require_review`. Under that policy:

- every send, reply, and forward needs `intent.summary`;
- a request without intent returns `422 intent_required`, with nothing sent or queued;
- a valid request normally returns `202 queued_for_review` and an `rr_…` review id;
- delivery finishes only after a terminal review event or a closed review record.

Agents can read the policy but cannot widen it.

## Submit outbound mail

```bash frame="terminal"
curl -sS -X POST "$EXTROVERT_API_BASE_URL/v1/inboxes/$INBOX_ID/send" \
  -H "Authorization: Bearer $EXTROVERT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: support-online-001" \
  -d '{
    "to": ["ops@acme.test"],
    "subject": "Support inbox ready",
    "text": "The support inbox is ready.",
    "intent": { "summary": "Tell operations that the support inbox is ready" }
  }'
```

  ```ts title="send.ts"
const outcome = await inbox.send({
  to: "ops@acme.test",
  subject: "Support inbox ready",
  text: "The support inbox is ready.",
  intent: { summary: "Tell operations that the support inbox is ready" },
  idempotency_key: "support-online-001",
});
```

  ```json title="send_email"
{
  "name": "send_email",
  "arguments": {
    "inbox": "pmbx_…",
    "to": ["ops@acme.test"],
    "subject": "Support inbox ready",
    "text": "The support inbox is ready.",
    "intent": { "summary": "Tell operations that the support inbox is ready" },
    "client_id": "support-online-001"
  }
}
```

  ## Read incoming mail

```bash frame="terminal"
curl -sS "$EXTROVERT_API_BASE_URL/v1/inboxes/$INBOX_ID/messages?unread=true" \
  -H "Authorization: Bearer $EXTROVERT_API_KEY"
```

  ```ts title="read.ts"
const { items: messages } = await inbox.messages({ unread: true });
const { items: threads } = await inbox.threads();
```

  ```json title="read_messages"
{
  "name": "read_messages",
  "arguments": { "inbox": "pmbx_…", "unread_only": true }
}
```

  Message reads expose source-faithful `text` and `html` MIME alternatives plus nullable
`extracted_text` and `extracted_html` derivatives. Neither source format is synthesized from the
other. Use the source fields when fidelity matters and the extracted fields for concise reading.

## Flow summary

1. **Connect** with OAuth or a limited agent key.

2. **Create** an inbox. POST /v1/inboxes

3. **Read** `effective_review_policy` from the single-inbox response.

4. **Submit** outbound mail with an intent and monitor the returned review id.

5. **Receive** through messages, threads, webhooks, or
   [`wait_for_email`](https://docs.extrovert.dev/quickstart/wait-for-email/).

## Next

- [Authentication and keys](https://docs.extrovert.dev/quickstart/authentication/)
- [`wait_for_email`](https://docs.extrovert.dev/quickstart/wait-for-email/)
- [Messages, threads, and search](https://docs.extrovert.dev/concepts/messages-and-threads/)
- [Review Loop agent contract](https://docs.extrovert.dev/review-loop/agent-contract/)