# Mail (/docs/mail)

Agent mail is rolling out and is not yet available to every organization. When
it is on for yours, the `mail__*` tools appear in `tools/list`; until then they
are absent. If it is ever paused for your organization, the tools disappear and
your persistent inboxes stop being charged; they keep their addresses and keep
receiving mail until it is back on.

Mail is a CoreSpeed-hosted capability: your agent gets real email addresses of
its own, with nothing to sign up for and no mailbox credentials to hold. There
are two kinds of inbox:

* **Disposable** — lives up to 7 days (`ttl_hours` ≤ 168), **receive-only**, and
  deletes itself when it expires. For sign-ups, verification codes and one-off
  replies.
* **Persistent** — lives until you delete it (or for up to a year with
  `ttl_hours`), and can also **send, reply, and forward**.

An agent's inboxes are its own; pass `shared: true` to make one visible to
every agent and member of the organization. A member sees all of the
organization's inboxes.

Tool names follow `mail__<action>`. The wire names and exact parameters come
from `tools/list`; the tables below are the map.

## Tools \[#tools]

### Inboxes \[#inboxes]

| Tool                 | Does                                                                                                                                           |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `mail__create_inbox` | Create an inbox and return its address. `ttl_hours` picks disposable or persistent; `allow_senders` limits who can write to it (inbound only). |
| `mail__list_inboxes` | The inboxes you can use.                                                                                                                       |
| `mail__get_inbox`    | One inbox: address, kind, whether it can send, expiry.                                                                                         |
| `mail__update_inbox` | Rename it or replace its sender allowlist.                                                                                                     |
| `mail__delete_inbox` | Delete it. Irreversible — the address is never issued again.                                                                                   |

### Reading \[#reading]

| Tool                     | Returns                                                                                                                                                                                                    |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mail__list_messages`    | Messages in one inbox, newest first, with filters (text, sender, subject, unread, label, time). Each summary carries any verification codes found.                                                         |
| `mail__search_messages`  | Full-text search across every inbox you can see.                                                                                                                                                           |
| `mail__read_message`     | One message in full: cleaned text, extracted codes, links classified as verify / login / reset / unsubscribe, and attachments.                                                                             |
| `mail__get_thread`       | A whole conversation.                                                                                                                                                                                      |
| `mail__wait_for_message` | Waits up to 50 seconds for a matching message and returns it — the way to catch a code right after signing up.                                                                                             |
| `mail__get_attachment`   | Stores an attachment as a private file in your [Drive](/docs/drive) under `tmp/mail/` (7 days; `drive__move` keeps it) that feeds [Media](/docs/media) understanding, connector uploads, and `mail__send`. |
| `mail__update_message`   | Mark read or unread; add or remove labels.                                                                                                                                                                 |
| `mail__list_labels`      | An inbox's labels with counts.                                                                                                                                                                             |

### Sending \[#sending]

| Tool                     | Does                                                                                                 |
| ------------------------ | ---------------------------------------------------------------------------------------------------- |
| `mail__check_recipients` | Without sending, tells you how each address would be treated and whether a send would need approval. |
| `mail__send`             | A new message to up to 10 recipients, with optional attachments.                                     |
| `mail__reply`            | A reply in the thread — to the sender, or everyone with `reply_all`.                                 |
| `mail__forward`          | Forward a message, with its attachments by default.                                                  |

Attachments are passed as a Drive path or file id — an attachment you stored,
a [Media](/docs/media) output, an upload — or a public https URL — up to 10
files per message. The
whole message, attachments included, must fit in 5 MiB once encoded for
sending. Disposable inboxes cannot send.

## Catching a verification code \[#catching-a-verification-code]

```text
mail__create_inbox { "ttl_hours": 1 }                       → inbox address
  … the agent signs up with that address …
mail__wait_for_message { "inbox_id": "inb_…", "from": "@example.com" }
                                                            → message with codes[]
```

Without `since`, a matching unread message that already arrived is returned at
once, so the order of sign-up and wait does not matter. The returned message is
marked read; calling again waits for the next one. A wait that times out
returns `message: null` — call it again to keep waiting.

## First messages to new people need a person \[#first-messages-to-new-people-need-a-person]

A send to someone new **outside your organization** — not a member, not on your
organization's allowlist, and not already written to from this inbox — waits for
a person's approval, whatever your approval policy says. That includes the first
**reply** to someone who wrote in and every forward to a new address: receiving
mail from an address never makes it trusted, because a "From" can be forged. The call returns
**Approval required** with an `approval_id`; the agent calls
`manage__approval_wait` with it at once, and the message is sent the moment it
is approved. The card goes to the agent's owner like every
[Smart Approvals](/docs/approvals) card. If Smart Approvals is not available to
your organization, such a send is refused with `approval_required` and nothing
is sent. Mail to your organization's own members,
to addresses on the organization allowlist (set by an admin), and to addresses
this inbox has already written to needs no approval. An inbox's `allow_senders`
only filters what it receives; it never lets a send skip approval.

Sending limits also protect every inbox's reputation: at most 10 recipients per
message, an hourly cap per inbox, daily caps that grow with the inbox's age
and with the time since your organization first sent, and an automatic pause
if too many messages bounce or are marked as spam.

## Mail content is untrusted \[#mail-content-is-untrusted]

Everything in a message — subject, body, sender name, links, even the codes —
was written by whoever sent it. Every result carrying mail opens with a notice
that says so and is marked `untrusted_content: true` (and
`_meta["io.corespeed/untrusted-content"]`), so agents treat it as data and never
as instructions, and says that sender names and addresses are not verified. When
a message explicitly failed an email authentication check (SPF, DKIM, DMARC) the
result says so too, because a forged "From" is how phishing aimed at agents
begins.

## Pricing and holds \[#pricing-and-holds]

| What                                   | Charge                                                                 |
| -------------------------------------- | ---------------------------------------------------------------------- |
| Disposable inbox                       | 5 credits, once, when created                                          |
| Persistent inbox                       | 300 credits per 30 days while it exists, the first period when created |
| Sending                                | 1 credit per recipient (to + cc + bcc)                                 |
| Receiving, reading, searching, waiting | Free                                                                   |

Pass `idempotency_key` on `mail__create_inbox` and the send tools when you
might retry: a repeat returns the first result and is not charged again. A
failed or refused call never charges. Charges land in the organization ledger
as `mail/inbox-disposable`, `mail/inbox-persistent` and `mail/send`; see
[Billing & credits](/docs/billing). A persistent inbox keeps being charged each
period until it is deleted — deleting it stops the charge, and the current
period is not refunded. An organization billing hold stops mail calls before
they run, as it does every metered tool, while its inboxes keep receiving.
`mail__delete_inbox` still runs during a hold, so you can always stop a
recurring charge.

## Controls \[#controls]

Mail appears as **Agent mail** in
[Dashboard → Tools](https://app.corespeed.io/tools). Turning it off hides every
`mail__*` tool from `tools/list` for that member; see
[Capability controls](/docs/capability-controls).