---
title: "Inboxes"
description: "The addresses your agents own: named, generated, ephemeral and catch-all inboxes, the shared machinemail.dev domain, custom domains, pausing and deletion."
canonical: "https://machinemail.dev/docs/concepts/inboxes"
---

# Inboxes

> The addresses your agents own: named, generated, ephemeral and catch-all inboxes, the shared machinemail.dev domain, custom domains, pausing and deletion.

Source: https://machinemail.dev/docs/concepts/inboxes

An inbox is one email address. It receives mail, sends mail, and holds the threads, messages and drafts for that address. As in AgentMail, the inbox ID is the address itself: `inbox_id` and `email` are the same string.

```json title="Inbox"
{
  "inbox_id": "support-agent@machinemail.dev",
  "organization_id": "org_01m4fy8h140000efvagszh6rpx",
  "pod_id": "pod_01m4fy8h150000w4xty1ehfnqa",
  "email": "support-agent@machinemail.dev",
  "display_name": "Support agent",
  "client_id": "support-agent-v1",
  "status": "active",
  "ephemeral": false,
  "created_by": "api",
  "created_at": "2026-10-09T09:00:15.835Z",
  "updated_at": "2026-10-09T09:00:15.835Z"
}
```

| Field                                    | Notes                                                                                       |
| ---------------------------------------- | ------------------------------------------------------------------------------------------- |
| `inbox_id`, `email`                      | The address, lowercase. Use it in paths (URL-encode the `@` if your client requires it).    |
| `display_name`                           | Shown as the sender name on outbound mail: `Support agent <support-agent@machinemail.dev>`. |
| `status`                                 | `active` or `paused`.                                                                       |
| `metadata`                               | Your own string-to-string map.                                                              |
| `ephemeral`, `ttl_seconds`, `expires_at` | Set on inboxes that delete themselves. See below.                                           |
| `created_by`                             | `api`, `dashboard`, `catch_all` or `agent`.                                                 |
| `client_id`                              | Your idempotency key, if you set one.                                                       |

## Creating an inbox

**curl**

```bash title="Terminal"
curl https://api.machinemail.dev/v0/inboxes \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"username": "support-agent", "display_name": "Support agent", "client_id": "support-agent-v1"}'
```

**TypeScript**

```ts title="create-inbox.ts"
const res = await fetch('https://api.machinemail.dev/v0/inboxes', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.MACHINEMAIL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ username: 'support-agent', display_name: 'Support agent', client_id: 'support-agent-v1' }),
});
const inbox = await res.json();
```

**Python**

```python title="create_inbox.py"
import os, requests

inbox = requests.post(
    "https://api.machinemail.dev/v0/inboxes",
    headers={"Authorization": f"Bearer {os.environ['MACHINEMAIL_API_KEY']}"},
    json={"username": "support-agent", "display_name": "Support agent", "client_id": "support-agent-v1"},
).json()
```

All body fields are optional:

| Field          | Notes                                                                                                                                                                                               |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `username`     | The local part. `a-z`, `0-9` and `. _ + -`, 1 to 64 characters, starting and ending with a letter or digit. Uppercase is lowercased. Omit it for a random 12-character name such as `a2rz80xf1b49`. |
| `domain`       | `machinemail.dev` (the default) or a domain your organization has added.                                                                                                                            |
| `display_name` | Sender name.                                                                                                                                                                                        |
| `ttl_seconds`  | Makes the inbox ephemeral.                                                                                                                                                                          |
| `ephemeral`    | `true` without `ttl_seconds` means a one-hour TTL.                                                                                                                                                  |
| `metadata`     | String-to-string map.                                                                                                                                                                               |
| `pod_id`       | Create in a specific pod (organization keys only).                                                                                                                                                  |
| `status`       | `active` (default) or `paused`.                                                                                                                                                                     |
| `client_id`    | Idempotency key. The same `client_id` returns the existing inbox with `200` instead of `201`.                                                                                                       |

### Checking availability

The dashboard's create dialog checks names as you type. You can call the same endpoint:

```bash title="Terminal"
curl "https://api.machinemail.dev/v0/inboxes/availability?username=support-agent&domain=machinemail.dev" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
```

```json title="Response"
{ "available": false, "email": "support-agent@machinemail.dev", "reason": "taken", "message": "support-agent@machinemail.dev is taken" }
```

It never fails for a bad name. `reason` is `invalid_username`, `domain_not_found` or `taken`. An available name returns `{ "available": true, "email": "..." }`.

## The shared domain and custom domains

Inboxes on `machinemail.dev` are free and need no setup. The shared domain is one namespace for everyone, first come first served: if another organization holds `support@machinemail.dev`, you get the same `409` as if you held it yourself. Each organization can hold up to 1,000 addresses on the shared domain. Mail sent to an address on the shared domain that nobody has created is not delivered; catch-all never applies there.

Some names are reserved on the shared domain and answer the same `409`:

- role and mail-system addresses (`abuse`, `postmaster`, `hostmaster`, `admin`, `mailer-daemon`, `dmarc`, …), including every mailbox a certificate authority accepts for domain validation;
- addresses that look like MachineMail itself (`support`, `sign-in`, `noreply`, `security`, `billing`, `api`, `mcp`, anything containing `machinemail`, …);
- well-known brands (`paypal-support`, `apple-help`, `openai-billing`, …), which on a shared domain could only be phishing.

Matching ignores case, a `+tag`, `.`/`_`/`-` and a trailing number, so `no.reply`, `post_master+x` and `support-24` are reserved too. Ordinary agent names (`agent-7`, `research-bot`, `invoice-parser`) are not. Your own custom domains have no reserved names.

Every organization's [slug](/content/docs/concepts/organizations-and-pods#the-slug/index.html) is also reserved, for that organization alone: only the organization with the slug `acme-agents` can create `acme-agents@machinemail.dev`. Everyone else gets the same `409`, and the availability check answers `taken`. Only that exact name is reserved. MachineMail creates it with the organization as its [default inbox](/content/docs/concepts/organizations-and-pods#the-default-inbox/index.html). Names of the form `agent-` followed by 16 or more hex digits are kept for the organizations of agents that sign up with an identity assertion, so other organizations cannot create them on the shared domain.

To use your own addresses, add a [custom domain](/content/docs/concepts/domains/index.html). You can create inboxes on it as soon as it is added, with no cap on how many. Mail only arrives once its MX record is in place.

## Ephemeral inboxes

An ephemeral inbox has a time to live. MachineMail deletes it once `expires_at` passes, along with its messages, threads, drafts, raw MIME and attachments, and emits an `inbox.expired` event. The cleanup job runs every minute.

```bash title="Terminal"
curl https://api.machinemail.dev/v0/inboxes \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ttl_seconds": 3600}'
```

```json title="Response"
{
  "inbox_id": "a2rz80xf1b49@machinemail.dev",
  "email": "a2rz80xf1b49@machinemail.dev",
  "status": "active",
  "ephemeral": true,
  "ttl_seconds": 3600,
  "expires_at": "2026-10-09T10:00:15.841Z",
  "created_by": "api",
  "created_at": "2026-10-09T09:00:15.841Z",
  "updated_at": "2026-10-09T09:00:15.841Z"
}
```

Each new inbound message pushes `expires_at` forward to the time of arrival plus `ttl_seconds`, so an inbox in active use stays alive. Ephemeral inboxes suit sign-up flows and one-off verification codes; see [OTP and sign-ups](/content/docs/guides/otp-and-signups/index.html).

Change the TTL later with `PATCH`:

- `{ "ttl_seconds": 86400 }` makes the inbox ephemeral (or changes its TTL) and resets `expires_at` to now plus the new TTL.
- `{ "ttl_seconds": null }` or `{ "ephemeral": false }` makes it permanent.

## Catch-all inboxes

A verified custom domain with `catch_all: true` accepts mail to any address. The first message to a new address creates the inbox on the spot, with `created_by: "catch_all"`. If the domain sets `catch_all_ttl_seconds`, those inboxes are ephemeral with that TTL. The local part must still be a valid username. See [Domains](/content/docs/concepts/domains#catch-all/index.html).

Catch-all is how you give every agent run, test or customer a fresh address without an API call per address.

## Updating, pausing and deleting

`PATCH /v0/inboxes/{inbox_id}` accepts `display_name`, `status`, `metadata` and `ttl_seconds`.

Pausing (`"status": "paused"`) stops the inbox in both directions:

- Sending from it returns `403 forbidden`.
- Inbound mail is refused and a `message.rejected` event is emitted with reason `inbox_paused`.

`DELETE /v0/inboxes/{inbox_id}` deletes the inbox and purges everything in it: messages, threads, drafts, raw MIME and attachments. This cannot be undone. Export first if you need a copy; see [Search and export](/content/docs/guides/search-and-export/index.html). Inbox-scoped keys cannot delete their own inbox.

## Listing and searching

| Method | Path                     | Notes                                                                                                                                       |
| ------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/v0/inboxes`            | Paginated with `limit` (default 50, max 500) and `page_token`.                                                                              |
| `GET`  | `/v0/inboxes/search?q=`  | Case-insensitive match on the address or display name. Scans the newest 500 inboxes in scope and sets `truncated: true` if there were more. |
| `GET`  | `/v0/inboxes/{inbox_id}` | One inbox.                                                                                                                                  |

An `inbox.created` event fires for every new inbox, including catch-all ones.

## Next

- [Threads and messages](/content/docs/concepts/threads-and-messages/index.html)
- [Domains](/content/docs/concepts/domains/index.html)
- [Give an agent an inbox](/content/docs/guides/give-an-agent-an-inbox/index.html)
