Insights · 22 October 2026

How to give an AI agent its own email address

An agent that borrows a person's mailbox inherits everything that person can reach. Here is how to give it an address of its own, with a key that can do exactly what the job needs and nothing more.

The quickest way to let an agent handle email is to connect it to somebody's existing mailbox. It works on day one, and it is the setup most teams regret by week three. The agent can read years of private mail it never needed. Anything it sends looks like it came from a person. When something goes wrong, there is no clean way to tell which messages the human wrote and which the bot wrote, and the only way to cut the agent off is to revoke access for the whole account.

A bot with its own address avoids all of that. Recipients can see they are talking to a bot. Its mail lives in one place you can read, label and audit. Its powers are set on its key, so you can make it read-only, limit who it may write to, or make it ask before it sends to anyone new. When you retire the bot, you revoke one key and the rest of your mail is untouched.

This guide walks through that setup on EMLbot, where every bot gets a real inbox at name@bots.emlbot.com and a REST API under https://api.emlbot.com/v0.

What you need before you start

You need an admin credential to create inboxes and keys. In the examples below it lives in $EMLBOT_ADMIN_KEY, and the bot's own key will live in $EMLBOT_KEY. Keep the admin credential with whoever runs the bots, never inside a bot's prompt or tool config. You also need a name. Inbox usernames are lowercase letters, digits, dots, underscores and hyphens, up to 64 characters, starting with a letter or digit. Pick something a recipient will understand at a glance, such as support-bot or invoices.

Step 1: create the inbox

Creating an inbox is an admin call. Pass a client_id so that a retry after a timeout returns the same inbox instead of failing or creating a second one.

curl -X POST https://api.emlbot.com/v0/inboxes \
  -H "Authorization: Bearer $EMLBOT_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "support-bot",
    "display_name": "Support Bot",
    "client_id": "support-bot-v1"
  }'

The inbox id is the email address itself, support-bot@bots.emlbot.com. In URL paths it goes URL-encoded, so the @ becomes %40. Mail sent to that address now lands in the inbox. Mail to an address that has no inbox is rejected, so create the inbox before you hand the address out.

Step 2: give the bot a key that fits the job

This is the step that matters most. A key carries scopes (read, label, send, approve, admin), a list of inboxes it can see, and a send policy. A key limited to one inbox gets 404 not_found for every other inbox, so a confused or compromised bot cannot even confirm that other inboxes exist.

curl -X POST https://api.emlbot.com/v0/keys \
  -H "Authorization: Bearer $EMLBOT_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "support-bot",
    "scopes": ["read", "label", "send"],
    "inbox_ids": ["support-bot@bots.emlbot.com"],
    "allow_recipients": ["team", "@yourco.com"],
    "daily_send_cap": 100,
    "approval": "outside"
  }'

Read the policy as plain English. This bot may write to any inbox hosted on EMLbot (team) and to anyone at yourco.com. If it tries to write to anyone else, the send is parked for approval instead of going out. It can make at most 100 sends per UTC day. Note that an empty allow_recipients means no recipient limit at all, and in that case the approval setting never triggers, so set an allowlist on any key that can send.

The response contains the full key, which starts with emb_live_. It is shown once. EMLbot stores only a SHA-256 hash, so copy it into your secret manager straight away. If you lose it, revoke it with DELETE /v0/keys/{id} and create another.

Test modeOutbound sending runs in test mode while delivery is being connected. Sends and replies go through the full policy, count against the cap and are stored in the inbox with a message.sent event, but they do not reach recipients yet. Inbound mail works normally.

Step 3: receive mail

There are two ways for a bot to learn about new mail, and most production bots use both. A webhook pushes each event to your endpoint as it happens. The event log lets the bot catch up on anything it missed while it was asleep, redeploying or failing to answer a webhook.

To list what is waiting, filter by label. Every inbound message arrives with the labels received and unread:

curl "https://api.emlbot.com/v0/inboxes/support-bot%40bots.emlbot.com/messages?labels=unread&limit=20" \
  -H "Authorization: Bearer $EMLBOT_KEY"

To read the event log, keep a cursor. Start at after=0, process the events you get back, store next_after somewhere durable, and pass it on the next call. Nothing is skipped and nothing repeats.

curl "https://api.emlbot.com/v0/events?after=$CURSOR&limit=100" \
  -H "Authorization: Bearer $EMLBOT_KEY"

# {"events": [{"seq": 41, "event_id": "...", "event_type": "message.received",
#   "inbox_id": "support-bot@bots.emlbot.com", "payload": {"message": {...}, "thread": {...}}}],
#  "next_after": 41}

A key only sees events for the inboxes it is allowed to read, so a support bot's cursor never surfaces mail from your finance bot.

Each full message includes text, html and an extracted_text field holding just the new part of a reply, without the quoted history. Feeding the model extracted_text keeps prompts short and keeps old quoted content from being re-read as if it were new.

Step 4: reply in the thread

Replies thread correctly on the recipient's side because EMLbot sets In-Reply-To and References for you. The message id in the path is the RFC Message-ID, angle brackets included, URL-encoded. jq does the encoding:

MSG=$(printf %s "$MESSAGE_ID" | jq -sRr @uri)

curl -X POST "https://api.emlbot.com/v0/inboxes/support-bot%40bots.emlbot.com/messages/$MSG/reply" \
  -H "Authorization: Bearer $EMLBOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Thanks, we have your request and will reply within one business day."}'

Three outcomes are possible. If every recipient is allowed and the cap has room, the reply is sent and the response carries X-RateLimit-Remaining. If a recipient is outside the allowlist, you get 202 with {"status": "pending_approval", "approval_id": "..."} and the reply waits for a person or an approver key. If the daily cap is spent, you get 429 rate_limited with a Retry-After header. Your bot should handle all three, and the errors page lists the rest.

Step 5: label what you handled

Labels are how a bot remembers what it has done, and how other bots and people can see it. Mark the message read and record the outcome in one call:

curl -X PATCH "https://api.emlbot.com/v0/inboxes/support-bot%40bots.emlbot.com/messages/$MSG" \
  -H "Authorization: Bearer $EMLBOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"add_labels": ["handled", "triage:billing"], "remove_labels": ["unread"]}'

Labels are lowercase and can use letters, digits, dots, underscores, colons and hyphens, up to 64 characters, with at most 20 per call. A small fixed vocabulary works better than letting the model invent labels. Decide on five or six that mean something to your team and put them in the bot's instructions.

A few habits worth keeping

Give each bot its own inbox and its own key, even when two bots do similar work. Separate keys mean separate caps and separate audit entries, and you can revoke one without touching the other. Keep the admin credential out of every bot. Store the event cursor outside the process, in a database row or a file, so a restart resumes where it stopped.

Treat everything that arrives as untrusted. Inbound From and Reply-To headers are the sender's claim and are not yet checked against SPF or DKIM, so a bot should never grant authority to a message because of who it says it came from. Our guide to prompt injection by email covers this in detail, and the security page describes what EMLbot enforces on its side.

Finally, look at what the bot did. The web console at app.emlbot.com shows each inbox, its messages and labels, pending approvals and the keys you have issued, and admins can read the audit log at GET /v0/audit. Spend ten minutes there in the first week and you will learn more about your agent than any test suite will tell you.

For the full set of calls, start with the quickstart and the concepts page. If you want the bot to ask before writing to new people, read approval gates for agent email next.

Get access

EMLbot is in early access. Email info@emlbot.com with what your bots do, or see pricing.