By KYN AI Advisory Team — AI implementation specialists, Singapore
A Microsoft 365 mail agent reads and drafts mail through Microsoft Graph. Application permissions such as Mail.Read apply to every mailbox in the tenant unless you restrict them, so the first job is to scope the app to the specific mailboxes it needs. The second is to design for Outlook's limit of 10,000 requests per 10 minutes per app per mailbox and four concurrent requests. Sending, deleting and moving mail should wait for a named person.
Which Graph permissions does a mail agent need?
Graph offers two permission types, and the choice decides how much the agent can see.
- Delegated permissions. The agent acts as a signed-in user and sees only what that user can see. Use these when a person works through the agent, for example a review screen where the user's own mailbox is the context.
- Application permissions. The agent acts as itself, with no user signed in. It runs on a schedule or on a webhook. An administrator must consent, and by default the permission covers all mailboxes in the tenant.
The mail permissions that matter:
| Permission | What it allows | |---|---| | Mail.ReadBasic | Read basic message properties without body or attachments | | Mail.Read | Read mail | | Mail.ReadWrite | Read, create, update and delete mail, including drafts | | Mail.Send | Send mail |
Check the Microsoft Graph permissions reference for the current list and descriptions. Choose the smallest. A bill-reading agent needs Mail.Read and no write. A reply-drafting agent needs Mail.ReadWrite to create drafts, and your code must keep sending behind an approval step, because Mail.Send is a separate grant and the agent should not hold it.
How do you limit an app to specific mailboxes?
This is the step most projects miss. Granting Mail.Read as an application permission lets the app read every mailbox in the tenant, including the finance director's and the CEO's. Microsoft's current method for limiting this is Role Based Access Control for Applications in Exchange Online. The older Application Access Policy approach still appears in documentation, but Microsoft's RBAC page is the one to follow.
The shape of the setup:
- Register the app in Microsoft Entra ID and create its service principal.
- Register that service principal in Exchange Online.
- Create a management scope, or use an administrative unit, that lists only the mailboxes the agent needs:
bills@,sales@, a named shared mailbox. - Assign an Exchange application role (for example Application Mail.Read) to the service principal, limited to that scope.
- Remove the broad grant from Entra. Microsoft warns that permissions assigned through RBAC for Applications act in addition to Entra grants, so a leftover tenant-wide
Mail.Readstill applies. - Test: call the Graph API for an in-scope mailbox and an out-of-scope one. The second must be refused. Microsoft notes a permissions cache that can take from 30 minutes to 2 hours to refresh, so allow for that when you test.
Put the test in a runbook and repeat it after any permission change. Scoping is a control only if you verify it.
What are the throttling limits?
Microsoft Graph throttles per service. The Graph throttling limits page lists the Outlook limits per app ID and mailbox combination:
- 10,000 API requests in a 10-minute period;
- 4 concurrent requests;
- 150 MB of uploads (PATCH, POST, PUT) in a 5-minute period.
Exceeding the limit for one mailbox does not affect access to another. When you are throttled, Graph returns HTTP 429. Microsoft documents Retry-After handling and headers that warn when you pass 80% of a limit.
Practical design:
- Concurrency of four per mailbox. Use one worker per mailbox with a small pool, not a free-for-all. JSON batch requests send up to four requests at a time to Outlook, so a batch is not a way around the limit.
- Honour Retry-After. Wait the stated seconds, then retry with backoff. Do not retry in a tight loop.
- Avoid polling. Use change notifications (webhooks) on the mailbox or a delta query to fetch only changes. Subscriptions expire and must be renewed, so schedule the renewal and alert when it fails.
- Page sensibly. Request only the fields you need with
$select, and page with$top. - Watch the warning header. Alert at 80% of the limit so you see the trend before throttling starts.
For a team mailbox, 10,000 requests in 10 minutes is a lot. Throttling is more likely to arrive from a bad loop, such as re-reading the whole inbox on each run, than from normal volume.
What tenant-level controls does the administrator hold?
The tenant owner decides what the agent can do, and the agent should assume that can change.
- Admin consent. Application permissions need an administrator. Record who consented and when.
- Credential type. Use a certificate or a managed identity, not a client secret you paste into a config file. Secrets expire, so track the expiry date. A silent expiry stops the agent at 08:00 on a Monday.
- Sign-in and audit logs. Entra sign-in logs and the Graph activity log show what the app did. Match them to your own agent log by correlation ID.
- Data location and retention. Know where your tenant stores mail and how long your agent keeps copies. Keep extracted fields, not duplicates of the mail.
In Singapore, the PDPC enforces the Personal Data Protection Act, and mailboxes hold personal data. Limit access, log reads and keep only what the job requires.
Which actions should wait for a person?
- sending any message that carries your name to a new contact;
- sending any message that quotes money, terms or dates;
- deleting, moving to another mailbox or changing mailbox rules;
- forwarding mail outside the tenant;
- replying to a complaint, a legal notice or a regulator.
The agent drafts into a review queue. A named person approves, and your backend sends using a separate, narrowly scoped identity. Mail contents are untrusted input, so an instruction inside an email must not change what the agent does. See prompt injection in business AI agents and approval gates for high-risk agent actions.
Where KYN fits
KYN builds mail agents on the identity service you already use. For an estate-planning document platform we built on Google Cloud with Microsoft Entra sign-on, and the same pattern applies to a Microsoft 365 tenant: named accounts, no shared logins, one restricted account per agent and row-level security in the database. Every action is logged with the actor, and outbound messages, money and deletions wait for a named person. See security and integrations.
The first 14 days are a review of your stack and interviews with your team. A full build ships in under 90 days.
Frequently asked questions
Does Mail.Read as an application permission read every mailbox?
Yes, unless you restrict it. Without a scope, the app can read any mailbox in the tenant. Use RBAC for Applications in Exchange Online to limit it to named mailboxes, and remove the broad grant in Entra.
Can the agent send mail as a shared mailbox?
It can, with the right permission and scope. Keep sending behind an approval step and use a separate identity for the send action, so the reading agent holds no send rights.
What happens when the agent hits a throttle?
Graph returns 429 with a Retry-After value. The agent waits, retries with backoff and logs the event. A rise in 429s means a design problem, such as polling too often, and is worth fixing.
Checked 30 October 2026.
Curious whether Marketing agents fits your business? Talk to KYN on WhatsApp — no forms, just a conversation.