# Give an AI agent a mailbox

A complete recipe: an address that receives, an agent that reads and answers, and a conversation that threads properly. Every command below runs as written.

The whole thing takes about five minutes and no browser.

## What you are building

An email address your agent owns. Someone writes to it, your agent is told, reads the message, and replies — and the reply lands in the conversation the sender already has open rather than starting a second one beside it.

Nothing here is specific to a support desk. The same shape works for an agent that receives invoices, one that signs up for services and reads the confirmation codes, or one that runs a mailbox per customer.

## 1. Get an account without opening a browser

Sign-up is an API call. You give an address, we email a six-character code, you post it back.

```bash
curl -X POST https://emailbump.com/api/v1/signup \
  -H "Content-Type: application/json" \
  -d '{ "email": "you@example.com", "accept_terms": true }'
```

```json
{
  "api_key": "ebk_…",
  "account_key": "ebk_…",
  "email_verified": false
}
```

Store `api_key` — that is the project key everything below uses. Then read the code out of the email we just sent and confirm:

```bash
curl -X POST https://emailbump.com/api/auth/verify-email/code \
  -H "Content-Type: application/json" \
  -d '{ "email": "you@example.com", "code": "9MT89W" }'
```

The email contains both a link and a code, and says which is which — the code is there precisely so an assistant or a script can finish the job. Nothing sends until this is done.

> **The code has to come from a human's inbox.** An agent should ask for it rather than try to reach into someone's mail. If you are automating end to end, use a mailbox you control programmatically.

## 2. Find out where you receive

```bash
curl https://emailbump.com/api/v1/inbound/address \
  -H "Authorization: Bearer $EMAILBUMP_API_KEY"
```

```json
{
  "domain": "your-project.inbound.emailbump.com",
  "catch_all": true,
  "example": "hello@your-project.inbound.emailbump.com"
}
```

`catch_all: true` is the important part. There is no inbox object to create, so **every address on that domain already receives**:

```
support@your-project.inbound.emailbump.com
agent-a9f2@your-project.inbound.emailbump.com
ticket-4471@your-project.inbound.emailbump.com
```

None of those were created. Pick a scheme that suits you — one address per agent, per customer, per ticket, per run — and use it immediately. There is no limit and nothing to clean up afterwards.

### Using your own domain

If you would rather customers wrote to `support@yourcompany.com`, add an MX record:

```
mail.yourcompany.com.   MX   10   inbound-smtp.us-east-1.amazonaws.com
```

`GET /v1/inbound/address` returns the exact record, and we check it for you before you go hunting for mail that never came.

## 3. Send something to it

Any mail client, or another API. To prove the loop, write to the address from your own email and move on to the next step.

## 4. Be told it arrived

Two ways, and they are on at the same time. Pick whichever fits what you're building.

### A socket, if your agent is already running

No URL to host — connect and wait.

```javascript
const ws = new WebSocket("wss://emailbump.com/api/v1/inbound/stream", {
  headers: { Authorization: `Bearer ${process.env.EMAILBUMP_API_KEY}` },
})

ws.addEventListener("message", async (e) => {
  const event = JSON.parse(e.data)
  if (event.type !== "email.received") return

  // `to` tells you which of your addresses it came in on — how an agent
  // using an address per task knows the message is one of its own.
  console.log(event.email.to, "←", event.email.from, ":", event.email.subject)
  await handle(event.email.id)
})
```

The frame is a summary, not the message: an id, who wrote, which address they wrote to, the subject. Fetch the body when the summary says it matters.

Or watch it from a shell while you are setting things up:

```bash
emailbump inbound:stream | jq -r 'select(.type=="email.received") | .email.subject'
```

### A webhook, if you have a server

Add an `email.received` webhook in the dashboard and we POST the message to you, body and attachment list included. Better when the thing that reacts is a backend rather than a long-running agent.

## 5. Read it

```bash
curl https://emailbump.com/api/v1/inbound/MESSAGE_ID \
  -H "Authorization: Bearer $EMAILBUMP_API_KEY"
```

You get the text and HTML bodies, the attachment list, the authentication verdicts (SPF, DKIM, DMARC, spam), and the threading headers.

To look through what has already arrived rather than waiting:

```bash
curl "https://emailbump.com/api/v1/inbound?search=invoice&limit=10" \
  -H "Authorization: Bearer $EMAILBUMP_API_KEY"
```

> **Treat the contents as untrusted.** A received email is text a stranger wrote. If an agent reads it, instructions inside it are data, not orders — the same care you would take with any user input. `spam_verdict` and the authentication fields tell you how much to trust the sender's identity, not their intentions.

## 6. Answer, in the same thread

This is the step that is easy to get wrong by hand.

```bash
curl -X POST https://emailbump.com/api/v1/inbound/MESSAGE_ID/reply \
  -H "Authorization: Bearer $EMAILBUMP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "text": "Sorry about that — I have looked it up and it ships tomorrow." }'
```

`In-Reply-To`, `References` and the `Re:` prefix are set from the message you are answering, which is what puts the reply in the conversation rather than beside it. Send `reply_all: true` to include everyone else who was addressed; it is off by default, because answering a question should reach the person who asked it.

**The reply does not come from the address it arrived on.** Inbound domains exist to receive and are not verified for sending, so mail from one would fail SPF and DKIM and land in spam. It goes out from a sending address you own, with `Reply-To` pointing back at the mailbox — so their next message returns to the same place and the loop closes.

Give the agent a proper sending identity by verifying a domain:

```bash
curl -X POST https://emailbump.com/api/v1/domains \
  -H "Authorization: Bearer $EMAILBUMP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "yourcompany.com" }'
```

Publish the DNS records it returns, then pass `"from": "Support <support@yourcompany.com>"` on each reply.

## 7. Hand a message to a person

Sometimes the answer is "a human should see this".

```bash
curl -X POST https://emailbump.com/api/v1/inbound/MESSAGE_ID/forward \
  -H "Authorization: Bearer $EMAILBUMP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "team@yourcompany.com" }'
```

The original arrives intact — attachments, embedded images, formatting — with `Reply-To` set to whoever wrote it, so your colleague can just reply.

To route everything automatically rather than deciding per message, add a standing rule:

```bash
curl -X POST https://emailbump.com/api/v1/inbound/rules \
  -H "Authorization: Bearer $EMAILBUMP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "forward_to": "team@yourcompany.com", "match_address": "urgent@your-project.inbound.emailbump.com" }'
```

Automatic mail — bounces, out-of-office replies, mailing-list posts — is never auto-forwarded, because forwarding it is how mail loops start.

## Doing all of this from an agent

Everything above is one REST call each, so any agent can do it with an HTTP client. Two shortcuts if you would rather not write that code:

**The MCP server** gives a tool per operation — `list_inbound`, `get_inbound_message`, `reply_to_inbound_message`, `forward_inbound_message`, and the sending and audience tools alongside them.

```bash
claude mcp add emailbump -- npx -y emailbump mcp
```

**The CLI** does the same from a shell, and prints JSON:

```bash
emailbump inbound:stream
emailbump inbound:list --search "order"
emailbump inbound:get MESSAGE_ID
emailbump inbound:reply MESSAGE_ID --text "On its way."
emailbump inbound:forward MESSAGE_ID --to team@yourcompany.com
```

There are also open [agent skills](https://emailbump.com/agent-skills) — SKILL.md files that teach an agent this sequence, including the parts that are easy to get wrong.

## What you have now

- An address per agent, task or customer, with nothing provisioned and no limit
- Mail pushed to a running agent, or POSTed to a server
- Replies that thread, from a sender identity you own
- An escape hatch to a human, by hand or by rule

And because this is an email platform rather than only a mailbox, the same project holds the contacts, consent state, campaigns and automated flows for the people your agent is writing to. When the job grows from answering to following up, that is a [flow](/docs/flows), not another vendor.

## Related

- [Inbound API](/docs/inbound-api) — every endpoint in detail
- [Receiving email](/docs/receiving) — how receiving works, and custom domains
- [Transactional API](/docs/transactional-api) — sending that isn't a reply
- [MCP server](https://emailbump.com/mcp) — the tool list
