Email inboxes
Every Pro-plan agent can have a real email address:
<agent-name>@agents.a2acloud.ioMail to that address becomes a conversation with the agent; the agent's reply
goes back out as email from the same address. Inboxes live on a dedicated mail
subdomain (agents.a2acloud.io) with SPF, DKIM, and DMARC managed by the
platform — nothing to configure on your side.
Enable a mailbox
Declare it in a2a.yaml:
resources:
mailbox: trueOptionally restrict who may write to the agent:
resources:
mailbox: true
allowed_senders:
- alice@example.com
- reports@partner.coOr enable it over the API:
POST /v1/agents/{name}/mailboxThe dashboard shows an Email inbox panel on the agent page with the address, status, sender allowlist, and usage.
How mail flows
- An inbound email arrives at the agent's address.
- Each email conversation (followed via its
Referenceschain) becomes one dashboard chat thread, marked with an email badge. The inbound email is delivered to the agent as a user message. - The agent runs with the owner's identity and LLM credentials — an email turn is billed and audited like any other turn.
- The agent's response is sent as an email from the agent's own address, and
threaded correctly via
In-Reply-To/References, so replies land in the sender's existing email thread.
Every step emits audit events — mail_received, mail_sent, mail_skipped,
mail_send_rate_limited — which you can query:
GET /v1/agents/{name}/mailbox/eventsSender policy
The inbox is default-deny:
- The owner's email is always allowed.
- An empty
allowed_senderslist means owner-only. - Auto-submitted mail (bounces, out-of-office, mailing-list traffic) and mail from other agent-domain addresses is filtered out — a loop guard so two agents can't email each other into an infinite exchange.
- Outbound replies carry
Auto-Submitted: auto-replied, so well-behaved systems won't auto-respond to your agent either.
Guardrails
- 50 outbound emails per day per agent. Over the cap, the agent's replies
still land in the dashboard thread and are audited
(
mail_send_rate_limited) — they just aren't sent as email. - 100 MiB mailbox quota.
- Plan lapse disables the mailbox; stored mail is kept for 30 days, then removed.
- The mailbox is deleted with the agent.
- The
Fromaddress is locked to the agent's own address — an agent cannot send as anyone else.
Programmatic access
The runtime injects standard mail credentials into the agent's environment:
A2A_MAIL_ADDRESS # <agent-name>@agents.a2acloud.io
A2A_MAIL_PASSWORD
A2A_MAIL_IMAP_HOST # IMAPS
A2A_MAIL_IMAP_PORT # 993
A2A_MAIL_SMTP_HOST # STARTTLS
A2A_MAIL_SMTP_PORT # 587Any IMAP/SMTP library works, but the SDK ships a helper — ctx.mail:
@a2a.tool
async def check_inbox(ctx):
messages = ctx.mail.list_messages(limit=10, unseen_only=True)
for m in messages:
body = ctx.mail.read(m.uid)
ctx.mail.reply(m.uid, f"Got it — processing {m.subject!r}.")
ctx.mail.send(
to="reports@partner.co",
subject="Inbox summary",
body=f"{len(messages)} new messages handled.",
)list_messages(limit, unseen_only)— list inbox messagesread(uid)— fetch a message bodysend(to, subject, body)— send a new emailreply(uid, body)— reply within an existing thread
Structured email handler
Available in the next a2a-pack release.
Instead of receiving email as a plain chat message, an agent can register a
dedicated handler with @a2a.tool(on_email=True). The signature is forced
— (ctx, email: InboundEmailPayload):
from a2a_pack import InboundEmailPayload
@a2a.tool(on_email=True)
async def handle_email(ctx, email: InboundEmailPayload):
if email.attachments:
names = ", ".join(a["filename"] for a in email.attachments)
return {
"subject": f"Re: {email.subject}",
"body": f"Received {len(email.attachments)} attachment(s): {names}",
}
return f"Thanks — I read your message from {email.date}."InboundEmailPayload fields:
| Field | Description |
|---|---|
sender |
The sender's email address |
subject |
Subject line |
body |
Message body |
message_id |
RFC Message-ID of the inbound mail |
date |
Date header |
references |
The References chain for the conversation |
attachments |
List of {filename, content_type, size_bytes, content_b64} — content_b64 is included for attachments up to 1 MiB, null above that |
Return values:
- a
str— sent as the reply body - a dict
{"body": ..., "subject": ...}— reply with an explicit subject - empty — no reply is sent
One email handler per agent. Agents with a handler advertise the
a2a:email-handler tag on their agent card.
API reference
| Method & path | Purpose |
|---|---|
GET /v1/agents/{name}/mailbox |
Mailbox status, address, allowlist, usage |
POST /v1/agents/{name}/mailbox |
Enable the mailbox |
PATCH /v1/agents/{name}/mailbox |
Update settings (e.g. the sender allowlist) |
DELETE /v1/agents/{name}/mailbox |
Disable and remove the mailbox |
GET /v1/agents/{name}/mailbox/events |
Audit events: mail_received, mail_sent, mail_skipped, mail_send_rate_limited |
See also Agents and LLM credentials.