<!-- Canonical: https://staging.startupmail.dev/guides/secure-ai-agent-email -->
<!-- Last reviewed: 2026-08-26 -->

# How to secure an AI agent that reads email

> Build a safer email agent with a narrow threat model, mailbox-scoped access, recipient rules, stored drafts, human approval, and audit records.

Treat every email as untrusted input. Give the agent access to one mailbox, not a founder's
inbox or an entire workspace. Let code enforce recipients and sensitive actions. Start with
read-only access, move to stored drafts, and allow automatic sending only for narrow cases
where a wrong reply would cause little harm.

No prompt can make an email agent safe on its own. The useful controls sit around the model:
credentials, permissions, policy checks, approval, current thread state, and logs.

## Start with a small threat model

List what the agent can read and what it can change. Then ask what happens if an unknown sender
controls every word in a message and attachment.

An email agent normally faces five risks:

1. **Prompt injection.** A message tells the agent to ignore its rules, reveal private data, or
   call another tool.
2. **Excess access.** A stolen key or a bad tool call reaches mailboxes that have nothing to do
   with the job.
3. **Unsafe sending.** The agent contacts the wrong person, includes private material, or agrees
   to a refund, contract, or payment change.
4. **Stale state.** A person replies while the agent is drafting, or a retried event causes the
   same action twice.
5. **Data leakage.** Message bodies, attachments, access tokens, or model prompts end up in logs
   and systems that do not need them.

Each risk needs a control that your application can test.

## Why email prompt injection is different

An agent receives instructions from its developer and text from other people. A model may not
reliably distinguish the two when hostile instructions appear inside a normal-looking email.

[OWASP's prompt-injection guidance](https://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html)
lists email and attachments as sources of indirect prompt injection. The attack does not need
to say "ignore previous instructions" in plain text. It can hide directions in HTML, a document,
an image, or a link the agent opens.

Keep email content in a clearly marked data field. Do not join it to system instructions as if
both came from the same authority. Extract only the parts needed for the task. A parcel-status
agent may need an order number and sender address, not the sender's whole signature, linked web
pages, and every attachment.

Screening helps, but it is not a security boundary. Google gives the same warning for its
[Gmail remote MCP server](https://developers.google.com/workspace/gmail/api/guides/configure-mcp-server):
email may contain instructions that hijack an agent session. Google recommends trusted clients,
screening, and review of actions. Design the system so one missed injection still cannot cross
the mailbox or sending rules.

## Give the agent one identity

A useful agent address describes one job, such as `returns@company.com` or
`invoices@agents.company.com`. It should not begin life inside `founder@company.com`.

A dedicated mailbox reduces the data exposed to the model. It also gives people a clear place
to inspect the same conversation and take over. If the job needs several customer mailboxes,
put them inside a tenant boundary rather than handing the runtime an organization-wide key.

In Startup Mail, an API key can be scoped to an organization, tenant, or mailbox. Give a
single-mailbox agent a mailbox-scoped key. Keep the broader provisioning key in a separate
server process. Startup Mail does not support IMAP or SMTP. REST, the TypeScript SDK, and MCP
read or act on the mailbox; signed webhooks notify your application that something changed.

## Separate resource access from allowed actions

The mailbox boundary answers, "Which mail can this key reach?" Capabilities answer, "What may it
do there?"

Capabilities are one explicit operation allowlist. `drafts:send` is required to send a stored draft.
Startup Mail's current MCP tools do not manage drafts. Use REST or the TypeScript SDK for the
draft-first workflow described below.

Start with access such as:

| Agent job             | Typical capabilities                                 |
| --------------------- | ---------------------------------------------------- |
| Classify new messages | `mail:read`; add `mailboxes:read` for discovery      |
| Prepare replies       | `mail:read`, `drafts:read`, and `drafts:write`       |
| Send approved drafts  | `drafts:read`, `drafts:write`, and `drafts:send`     |
| Send without a draft  | `mail:send` after policy checks                      |
| Change address rules  | `policies:write`; omit this from most runtime agents |

Do not give the agent permission to change the policy that constrains it. A classifier does not
need send access. A drafting agent does not need to provision mailboxes or keys.

Use a separate key for each deployed workload. Give each key a clear name and expiry. Store it
in a secret manager, not in a prompt, repository, browser bundle, or email. Revoke it when the
agent is retired.

## Enforce communication rules outside the model

The model may propose a recipient. Your application should decide whether that address is
allowed.

A support workflow might permit replies only to the sender of the current thread. It might
block new outbound conversations, added recipients, external forwarding, payment-detail
changes, and attachments until a person approves them.

Startup Mail communication policies can allow or block addresses and domains. The `send`
direction checks every outbound recipient, including outbound replies. For inbound mail,
`receive` applies to a new conversation and `reply` applies after Startup Mail has matched the
message to an existing thread. These policies provide a useful service-side backstop. They do
not understand refund limits, legal promises, account ownership, or the meaning of an
attachment. Keep those business rules in your application.

Check the final request, not only the model's first answer. Validate every `to`, `cc`, and `bcc`
address after tools or people have edited a draft. Check attachment IDs against the same
mailbox. Reject a reply if its message ID does not belong to the expected thread.

## Use drafts as the default write path

A stored draft creates a clean break between generation and sending. The agent writes the
proposed text. Another step checks recipients, attachments, and policy. A person can review or
amend the draft before it is sent.

Startup Mail supports stored drafts and scheduled sends. The technical ability to schedule a
message is not an approval system by itself. Your application must record who approved it and
cancel or replace it when the thread changes.

Require a person to approve messages that:

- Add a new recipient or attachment
- Share customer, employee, medical, legal, or financial information
- Change bank, payment, delivery, or account details
- Offer a refund, discount, credit, or other commitment
- Start a new conversation outside a fixed allowlist
- Respond to a suspected security incident

Automatic replies can make sense for receipts, acknowledgements, and tightly constrained
status updates. Even then, test the exact data fields that can enter the message.

## Fetch current state before sending

Webhooks and queues can deliver more than once. A person may answer between the incoming event
and the agent's draft.

Use the webhook as a signal, then fetch the current thread. Record the triggering message ID.
Before sending, fetch the thread again and check for a newer reply or a closed case. Give each
outbound action an idempotency key so a retry does not send a duplicate.

A successful API response may mean the service accepted the job, not that the recipient's mail
server accepted the message. Track later delivery events when the workflow depends on a firm
outcome.

## Limit attachments and links

Do not let the agent open every link or execute every file it receives. Parse attachments in an
isolated service with strict file, time, and memory limits. Reject types the workflow does not
need. Disable macros and active content.

If the model needs one page of an invoice, do not send it the full mailbox archive. Less context
means less private data and fewer places to hide hostile instructions.

HTML sanitising and malware checks are useful, but neither proves that a document is safe for a
model to follow. Treat extracted text as untrusted after scanning.

## Keep an audit trail without copying the mailbox

Record enough to reconstruct an action:

- Mailbox, thread, and triggering message IDs
- Key or workload identity
- Policy result and approval identity
- Draft version and final recipient list
- Send idempotency key and delivery state

Avoid logging access tokens, complete message bodies, or attachment contents unless an incident
process needs them. Set a retention period for audit data and model traces. Make revocation and
human takeover simple enough to use during an incident.

## A safer rollout plan

Run the agent in stages:

1. Read and classify mail, but take no external action.
2. Create drafts that people compare with the original thread.
3. Auto-send one low-risk message type to an address or domain allowlist.
4. Expand only after reviewing errors, blocked attempts, duplicate events, and takeover cases.

Test with hostile emails before each stage. Ask whether an attacker can change a recipient,
obtain another thread, send a secret, or trigger the same action twice. A good test proves that
the application blocks the action even when the model agrees to it.

[OpenAI's safety guidance](https://developers.openai.com/api/docs/guides/safety-best-practices)
also recommends adversarial testing and human review before model output is used in practice.
Reviewers need the original thread, not only the agent's summary.

## Frequently asked questions

### Can a system prompt stop email prompt injection?

No. A clear system prompt helps the model follow the intended task, but it is not a reliable
access-control system. Use mailbox-scoped credentials, narrow tools, recipient checks, stored
drafts, and approval around it.

### Should an email agent have send permission?

Not at first. Begin with read-only or draft access. Add send permission only for a defined
message type after you can enforce recipients, content rules, retries, and human takeover.

### Is MCP less secure than a REST API?

Not by definition. Risk depends on the tools, credentials, client, and approval flow. MCP can
expose a small tool set, while a careless REST integration can expose a broad key. Apply the
same least-privilege and untrusted-input rules to both.

### Does Startup Mail provide a complete agent-security system?

No. It provides mailbox and tenant boundaries, scoped keys, drafts, scheduled sends,
communication policies, and human mailbox access. Your application must still enforce business
rules, run approval workflows, secure the model and other tools, and decide what to log.

For the wider architecture, read [The complete guide to email for AI agents](https://staging.startupmail.dev/guides/email-for-ai-agents.md).
For the account decision, read
[Should an AI agent use Gmail or a dedicated mailbox?](https://staging.startupmail.dev/guides/ai-agent-gmail-vs-dedicated-mailbox.md).

## Sources

- [Gmail remote MCP server and security notes](https://developers.google.com/workspace/gmail/api/guides/configure-mcp-server)
- [Google Workspace MCP security configuration](https://developers.google.com/workspace/guides/configure-mcp-security)
- [OWASP prompt-injection prevention guidance](https://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html)
- [Model Context Protocol security best practices](https://modelcontextprotocol.io/docs/2025-11-25/tutorials/security/security_best_practices)
- [OpenAI safety best practices](https://developers.openai.com/api/docs/guides/safety-best-practices)
- [Startup Mail agent inbox guide](https://staging.startupmail.dev/docs/agent-inboxes.md)
- [Startup Mail security guide](https://staging.startupmail.dev/docs/security.md)
- [Startup Mail webhook guide](https://staging.startupmail.dev/docs/webhooks.md)

## Related reading

- [The complete guide to email for AI agents](https://staging.startupmail.dev/guides/email-for-ai-agents.md): Learn how to give an AI agent a real mailbox with scoped access, durable threads, safe sending, webhooks, MCP tools, and human review.
- [Should an AI agent use Gmail or a dedicated mailbox?](https://staging.startupmail.dev/guides/ai-agent-gmail-vs-dedicated-mailbox.md): Choose between connecting an AI agent to Gmail and giving it a dedicated mailbox by comparing identity, OAuth access, isolation, human use, and cost.
- [How to give an AI agent an email address on your domain](https://staging.startupmail.dev/guides/give-ai-agent-email-address.md): Set up a custom-domain mailbox for an AI agent with safe DNS changes, narrow permissions, MCP or webhook access, and human approval.
