---
title: "Least privilege for email agents: scope, separate, test"
description: "Restrict email agents with group-scoped API keys, separate reading from approved sending, and test unauthorized operations before deployment."
url: https://mailera.app/en/blog/least-privilege-email-agents
published: 2026-10-25
updated: 2026-10-25
---

# Least privilege for email agents: scope, separate, test

Give a reader access to one mailbox group, keep sending in a separate service, and test the operations that should fail.

## What does least privilege mean for an email agent?

Start with a task you can state narrowly: “Summarize messages in the support mailbox group without sending, moving, sharing, importing, or managing mailboxes.” Then give the workload only the access that task requires.

To control an email agent's access, define four things: the principal using the credential, the mailbox resources it may access, its permitted operations, and how long the credential should remain usable.

[Mailera connects existing mailboxes to applications and agents](https://mailera.app/en/product). Its authorization layers should remain distinct:

| Layer | What to consider |
| --- | --- |
| Provider connection | Authorization granted when connecting the mailbox |
| Mailera user roles | Who may perform administrative actions |
| API key | Mailbox-group scope and permitted operations |
| Your application | Recipient rules, exact-message approval, and access to credentials |

Only Admin or Leader roles can add mailboxes through **Mailboxes → Add mailbox**. That role boundary is separate from the permissions on an agent's key. See [workspaces and roles for email-agent teams](https://mailera.app/en/blog/email-workspace-roles-agent-access) for team administration.

[Microsoft Graph's permissions overview](https://learn.microsoft.com/en-us/graph/permissions-overview) explains that delegated permissions cannot give an application access beyond the signed-in user's access. Reducing a Mailera key's permissions is a separate control; don't treat it as a change to upstream provider consent.

![Four authorization layers: provider connection, Mailera administration, API-key scope, and application policy.](https://mailera.app/media/c2a44cec35ec8554/least-privilege-for-email-agents-scope-separate-test-en-1200.jpg)
_Provider authorization, Mailera controls, and application policy are separate layers. Narrowing an API key does not change provider consent._

If you are still choosing how to connect your agent, start with [email for AI agents using existing mailboxes](https://mailera.app/en/blog/email-for-ai-agents).

## Which permissions does each mailbox task need?

Use this task-to-permission matrix before creating credentials. Keep resource scope narrow even when an operation genuinely needs write access.

| Task | Mailbox scope | Minimum permissions | Representative endpoint or MCP tool | Deliberately excluded |
| --- | --- | --- | --- | --- |
| Summarize messages | One designated group | `read` | `list_messages`, `get_message` | Sending, moving, sharing, management |
| Search message content | One designated group | `read` | `search_messages`, `GET /messages/search` | All mutation permissions |
| Read and move messages for triage | One designated group | `read`, `move` | `get_message`, `move_message` | Sending and management |
| Execute an approved outbound message | Intended sending group | `send` | `POST /mailboxes/{id}/send` | Reading unless actually needed; other operations |
| Check a send attempt's status | Intended sending group | `send` | `get_send_status`, `GET /sends/{id}` | Reading and unrelated operations |

Sending an approved message requires send permission. Add read only if the sender also needs a read-scoped operation, such as retrieving message content, listing mailboxes, or checking mailbox status. Passing an approved message from your application to the sender does not, by itself, justify adding read access.

**Read includes sensitive content.** It authorizes `get_message` and `get_latest_otp`, as well as the REST message-content and OTP endpoints. It is neither metadata-only access nor an OTP-excluding permission. Keep personal or otherwise unrelated mailboxes outside the reader's group.

Leave `import`, `sync`, `manage`, `webhooks`, and `share` absent unless the workload requires those operations. For example, `sync_mailbox` requires `sync`; it isn't an implicit part of a read-only workflow. Similarly, a send-status lookup requires `send`, not `read`.

The [Mailera MCP overview](https://mailera.app/en/mcp) describes the agent interface. Tool selection should follow the credential design, not replace it.

## How do you create a group-scoped API key?

1. **Check the group's membership.** Identify the mailboxes the workload needs and verify that the intended group contains only those mailboxes. Treat later membership changes as access changes worth reviewing.
2. Open **Settings → API key tab → Create key**. Enter a workload-specific **Descriptive name**, such as `support-summary-reader`.
3. Set **Mailbox scope** to one group. Admins can also select all groups, but a group-specific summarizer does not need that breadth.
4. Select only **Read** for the reader. Leave **Move messages**, **Import mailboxes**, **Sync**, **Send messages**, **Manage mailboxes**, **Webhook**, and **Sharing** unselected. Configure **Expiration** for the workload. Consider **IP restrictions (optional)** when its outbound IP addresses are predictable.
5. At **Key created — copy it now**, copy the key into a server-side secret store. The key is displayed only once. Use **Copy MCP config** only in the intended Claude, Cursor, or VS Code environment; treat the copied configuration as a credential-bearing secret.

![Mailera API-key dialog with one mailbox group selected and only Read permission enabled.](https://mailera.app/media/217ef7f9fc71e178/why-a-mailera-mailbox-goes-to-sleep-and-how-to-wake-it-wake-en-1200.jpg)
_Choose the resource scope and operation permissions separately. A reader needs neither Send messages nor Manage mailboxes._

Keep the credential outside model-visible context. Review [Mailera's security information](https://mailera.app/en/security) alongside your own deployment's secret-handling rules.

## How do you separate reading from approved sending?

The reader should produce a proposed response, not execute a send. Put the `send` credential in a separate application service that the reader cannot access directly.

Your application must implement the approval gate. Require a human to confirm the exact sender mailbox, recipients, subject, body, and attachments. If any of those change after approval, require approval again. Validate mailbox IDs and permitted recipients in trusted application code rather than relying only on the model prompt.

![Untrusted email reaches a read-only agent, whose proposed response must pass application approval before an isolated sender executes it.](https://mailera.app/media/432bc90bb2b76e1d/least-privilege-for-email-agents-scope-separate-test-en-1200.jpg)
_Build approval and policy checks in your application. The reader cannot access the send credential, and email content cannot authorize a send._

The [MCP tools specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools) requires servers to implement access controls and recommends that clients request confirmation for sensitive operations. That recommendation is not an application approval service: you still need to build the checks and connect approval to the exact content sent.

Hiding `send_email` from a tool menu while leaving a broadly privileged key accessible to the reader is not an authorization boundary. Remove `send` from the reader's credential and isolate the sender's credential and execution path.

Once sending is authorized, retries are a separate concern. Use the [guide to preventing duplicate sends with Idempotency-Key](https://mailera.app/en/blog/email-api-idempotency-key) when implementing the sender.

## What safety controls are still needed for untrusted email?

Incoming subjects, bodies, attachments, and quoted messages are untrusted data. They are never instructions that can change access policy.

An email asking the agent to reveal a key, widen mailbox scope, enable a tool, or skip confirmation must not trigger those actions. Keep access decisions in application code. Minimize the message content passed to the model and retained in logs.

Read-only access reduces mutation risk, but it does not prevent disclosure through model output or another available tool. Review where summaries can go and which external tools the reader can invoke. A group-scoped key does not make the content inside that group trustworthy.

For adversarial email examples and defensive exercises, use the [email prompt-injection lab](https://mailera.app/en/blog/email-prompt-injection-lab). Keep those content-level tests separate from the authorization checks below.

## How do you verify the boundary before deployment?

Use test mailboxes you own and synthetic messages. Prepare an allowed group and a separate excluded group. Keep mutation tests away from production mailboxes, because a failed boundary could allow the operation.

For each case, record the credential's scope, request or tool call, expected outcome, actual response, and any side effects. Redact credentials and message content from retained records. Do not count a malformed-request failure as proof that authorization worked.

1. **Confirm an allowed read.** Use a mailbox and message in the permitted group. Set `$MAILERA_API_KEY`, `$MAILBOX_ID`, and `$MESSAGE_ID` in your server-side environment, then retrieve the synthetic message:

```bash
curl -i "https://mailera.app/api/public/v1/mailboxes/$MAILBOX_ID/messages/$MESSAGE_ID" \
  -H "Authorization: Bearer $MAILERA_API_KEY"
```

2. **Test direct access outside the group.** Keep the reader key unchanged. Replace the mailbox and message variables with IDs from your excluded test group and repeat the request. The expected boundary is no access to that message's content; record the actual response rather than assuming a particular status code.
3. **Test cross-mailbox search.** Put a unique synthetic marker in an excluded-group message. Search without a mailbox filter, then repeat with the `mailbox` parameter targeting that excluded mailbox. Neither path should expose its message. Inspect each result's `mailbox_id` and follow `next_cursor` where present. A starting request is:

```bash
curl -i --get "https://mailera.app/api/public/v1/messages/search" \
  -H "Authorization: Bearer $MAILERA_API_KEY" \
  --data-urlencode "q=scope-boundary-marker" \
  --data-urlencode "limit=10"
```

4. **Attempt prohibited operations with the reader key.** On disposable test resources, submit valid requests to send, move a message, create a share, and manage a mailbox. Use the request formats in the [Mailera API documentation](https://mailera.app/en/docs). Record responses and verify that no message was sent or moved, no share was created, and no management change occurred.
5. **Repeat relevant checks through MCP.** Test `get_message` and `search_messages` against the resource boundary, then attempt `send_email` and `move_message`. Test both interfaces if your deployment exposes both; one REST result is not a substitute for exercising the MCP path.
6. **Test the application boundary.** Confirm that the reader cannot obtain the sender credential or execute a send without approval. Change a recipient or message body after approval and verify that your application requires renewed confirmation.
7. **Test credential lifecycle controls.** Check access after the configured expiration and after revocation. Mailera rejects calls immediately after a key is revoked. If IP restrictions are enabled, test from both permitted and excluded egress addresses.

Do not deploy if an excluded message becomes readable or a prohibited mutation succeeds. Fix the boundary and rerun the affected cases.

## What mistakes commonly weaken the design?

**One all-groups key for unrelated agents.** Give workloads separate credentials and only the group and operations their tasks need. Don't grant every permission to make an authorization error disappear.

**Request filters mistaken for authorization.** A `mailbox` search filter or `group_id` listing filter selects results. It is not a substitute for credential-enforced resource scope. Your negative tests should include requests that omit or change those filters.

**“Read-only” mistaken for harmless.** The `read` permission includes message content and OTP retrieval. Conversely, `get_send_status` requires `send`; its read-like name does not change that permission mapping.

**Two keys in the same model-accessible runtime.** Separate names do not provide isolation if the reader can retrieve both secrets. Also avoid logging full bodies, authorization headers, or copied MCP configurations while troubleshooting.

## Where do Mailera's controls stop?

Choose a mailbox group and the required operation permissions for each key. Implement exact-message approval and recipient checks in your application. Scoped credentials are not a prompt-injection defense and cannot prevent every disclosure through an agent's other tools.

Mailera does not provide bulk or marketing sending. Design the isolated sender for the approved mailbox task, rather than treating send permission as permission for unrelated outbound workflows.

**Do this with the API** — Every action in this article is available via the REST API, with curl examples, API keys and webhooks. [View API docs](https://mailera.app/en/docs)
