# Control who can email your agent (/tasks/inbound-control)

<!-- agent-signals: reading_time_min: 4 · est_tokens: 1820 · updated: 2026-08-03 -->
Related: [Receive email](/tasks/receive.md), [Send and reply](/tasks/send.md), [Manage conversations](/tasks/conversations.md)



# Control who can email an AgentMail inbox and who it can email

Allow and block lists filter inbound senders and outbound recipients by inbox, pod, or organization scope.

## Do this

Use the CLI to accept new inbound mail from one domain, block a sender for one inbox, and unblock a recipient:

```bash
# Organization-scope receive allow list. Unmatched new inbound senders are blocked.
agentmail lists create \
  --direction receive \
  --type allow \
  --entry yourcompany.com

# Inbox-scope receive block entry
agentmail inboxes:lists create \
  --inbox-id agent@yourdomain.com \
  --direction receive \
  --type block \
  --entry noise@example.com \
  --reason "automated newsletter"

# Delete an organization send block entry. Returns 204.
agentmail lists delete \
  --direction send \
  --type block \
  --entry user@example.com
```

## SDK

Install: `npm install agentmail` (TypeScript), `pip install agentmail` (Python), or `npm install -g agentmail-cli` (CLI).

| Operation                   | TypeScript                                                 | Python                                                          |
| --------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------- |
| Create entry (organization) | `client.lists.create(direction, type, { entry, reason })`  | `client.lists.create(direction, type, entry=..., reason=...)`   |
| List entries (organization) | `client.lists.list(direction, type, { limit, pageToken })` | `client.lists.list(direction, type, limit=..., page_token=...)` |
| Get entry (organization)    | `client.lists.get(direction, type, entry)`                 | `client.lists.get(direction, type, entry=...)`                  |
| Delete entry (organization) | `client.lists.delete(direction, type, entry)`              | `client.lists.delete(direction, type, entry=...)`               |
| Pod scope                   | `client.pods.lists.<op>(podId, direction, type, ...)`      | `client.pods.lists.<op>(pod_id, direction, type, ...)`          |
| Inbox scope                 | `client.inboxes.lists.<op>(inboxId, direction, type, ...)` | `client.inboxes.lists.<op>(inbox_id, direction, type, ...)`     |

CLI: `agentmail lists create|list|get|delete --direction <d> --type <t> [--entry <e>] [--reason <r>]`; pod scope: `agentmail pods:lists ... --pod-id <id>`; inbox scope: `agentmail inboxes:lists ... --inbox-id <address>`.

SDK reference: [https://docs.agentmail.to/api-reference](https://docs.agentmail.to/api-reference)

## Facts

* Organization endpoints: `GET /v0/lists/{direction}/{type}`, `POST /v0/lists/{direction}/{type}`, `GET /v0/lists/{direction}/{type}/{entry}`, and `DELETE /v0/lists/{direction}/{type}/{entry}`.
* Pod endpoints start with `/v0/pods/{pod_id}`; inbox endpoints start with `/v0/inboxes/{inbox_id}`. Unprefixed `/v0/lists/...` resolves scope from the API key.
* `direction`: `send`, `receive`, `reply`. `type`: `allow`, `block`.
* An entry containing `@` has `entry_type: "email"`; other entries have `entry_type: "domain"`. Do not pass an entry type.
* `reason` is optional and limited to 1,024 characters. Create returns `entry`, `organization_id`, `direction`, `list_type`, `entry_type`, optional `reason`, optional `read_only`, and `created_at`; delete returns HTTP 204.
* Evaluation order is inbox, pod, organization. The first match wins; within a scope, AgentMail checks email allow, email block, domain allow, then domain block.
* If an allow list has entries at any scanned scope for a direction, unmatched entries are blocked with reason `not in allow list`.
* Inbound replies resolved through `In-Reply-To` use `reply` lists only; new threads use `receive` lists only. Empty reply lists accept all replies.
* Blocked inbound mail is stored with the `blocked` label and omitted from message and thread lists by default. Use `include_blocked=true` and `label_blocked_read`. The same pattern applies to `spam` (`include_spam`, `label_spam_read`) and `unauthenticated` (`include_unauthenticated`, `label_unauthenticated_read`).
* `spam` means the delivery spam verdict failed. `unauthenticated` means SPF, DKIM, and DMARC headers were absent; mail with present but failing headers is dropped before delivery.
* Automatic organization `send`/`block` entries: permanent bounce (`bounced`, deletable), spam complaint (`complained`, read-only), and List-Unsubscribe click (`Unsubscribed via List-Unsubscribe`, read-only). Transient bounces create no entry. Complaint and unsubscribe entries remain read-only because the recipient asked to stop hearing from you, and programmatically re-enabling sends would damage your sender reputation; deletion returns `409 CannotDeleteError`.
* Reading lists requires `list_entry_read`, which all keys have. Creating and deleting require a verified organization.
* Shared `agentmail.to` sends also use an SES account-level suppression list for bounce and complaint feedback and unsubscribe clicks. Custom-domain sends do not use that list.

## Not supported

* You cannot view or clear SES account-level suppression through the API. Contact [support@agentmail.cc](mailto:support@agentmail.cc).
* You cannot delete read-only `complained` or `Unsubscribed via List-Unsubscribe` entries.
* No update/PATCH, wildcard or regex entries, or per-entry expiry/TTL. Delete and create a replacement entry.
* Inbound blocks do not reject mail at SMTP level; they deliver it with the `blocked` label.

## Errors

| Error                  | HTTP | Cause                                                                        | Fix                                                                   |
| ---------------------- | ---- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `MessageRejectedError` | 403  | Recipient matches a send block list or misses a populated send allow list    | Delete the block entry or add the recipient to the allow list         |
| `CannotDeleteError`    | 409  | Delete a read-only `complained` or `Unsubscribed via List-Unsubscribe` entry | Keep the recipient blocked; contact support if the entry is erroneous |
| `NotFoundError`        | 404  | Entry is absent from that scope's list                                       | Check scope, direction, and type                                      |
| `ValidationError`      | 400  | Invalid entry or `reason` over 1,024 characters                              | Use a valid email address or bare domain                              |
| `ForbiddenError`       | 403  | Create or delete with an unverified organization                             | Verify the organization                                               |

## Verify

Confirm an entry and inspect `read_only` before deletion:

```bash
agentmail lists get \
  --direction send \
  --type block \
  --entry user@example.com
```

The command returns the entry object, such as `{"entry": "user@example.com", "direction": "send", "list_type": "block", "entry_type": "email", "reason": "bounced", ...}`. A 404 means the address is absent from that list.

## Related

* [Send and reply](/tasks/send)
* [Receive email](/tasks/receive)


## Tenant instructions

Every page ships two renditions at one URL. The HTML page is for humans. The Markdown rendition (append .md to any page URL, or request with Accept: text/markdown) is agent-optimized: a Do this section with runnable commands, SDK signatures, exhaustive Facts, a Not supported section listing shapes that do NOT work, an Errors table, and a Verify command. Prefer the Markdown rendition over scraping HTML, and trust Not supported entries instead of retrying those call shapes.