An application granted Mail.Read as an application permission can read every mailbox in the tenant without a signed-in user, and that access survives password resets, MFA and the departure of whoever approved it. Most Microsoft 365 tenants hold a mix of backup tools, CRM connectors, scanners, test apps and forgotten proofs of concept with exactly that power. This page is the hands-on review: read-only Microsoft Graph PowerShell to find every app with mail access, how to judge each one, how to scope or revoke the access using commands from Microsoft documentation, and how to confirm the change took effect. It is written for Entra ID and Exchange Online administrators and for security teams running app reviews. The scoping model itself is explained in the Microsoft 365 Application Access Policies and RBAC for Applications Guide.
Key takeaways
Look in two places. Mail access comes from application permissions (app role assignments on Microsoft Graph and on the Office 365 Exchange Online resource) and from delegated grants, which may be tenant-wide (AllPrincipals) or per user.
Resolve permission IDs from the tenant, not from a blog. Query the Graph service principal's appRoles for the IDs of Mail.Read, Mail.ReadWrite and Mail.Send, so a mistyped GUID cannot hide an app from your review.
Scoping only works after you remove the unscoped grant. Microsoft states that Exchange RBAC for Applications permissions are a union with Entra ID grants, so an unscoped Mail.Read consent in Entra cancels any scoping you add in Exchange.
Disable before you delete. Microsoft's consent incident playbook says disabling a suspicious app stops new tokens and new consent, while deleting it lets it return if someone consents again.
Credentials are part of the review. A mailbox-capable app with an old client secret, or a secret held by a vendor, is a standing key to your mail. Check its credentials and sign-ins, not only its permissions.
When you need this
Periodic access review: apps with tenant-wide mail access should be reviewed at least quarterly, with a named owner for each.
After a vendor incident: in the Commvault Metallic breach, a nation-state actor may have obtained client secrets that a Microsoft 365 backup service used to reach customer tenants. Every customer had to find that app, review its permissions and rotate its credentials.
Legacy and test apps: in the Microsoft Midnight Blizzard breach, the attacker abused a legacy test OAuth app with elevated access and obtained the Exchange Online full_access_as_app role to read corporate mailboxes. Test tenants and old apps are where this review finds the worst surprises.
Before moving to RBAC for Applications: Microsoft states that RBAC for Applications replaces Application Access Policies; an inventory is the first step of that migration.
Before you start
Item
Detail
Read-only role
Global Reader or Security Reader is enough for discovery; connect with Connect-MgGraph -Scopes "Application.Read.All"
Change role
Cloud Application Administrator or Application Administrator to revoke grants (per Microsoft); Exchange administrator for RBAC for Applications
Modules
Microsoft Graph PowerShell (Install-Module Microsoft.Graph) and Exchange Online PowerShell
Audit
Unified audit log enabled; MailItemsAccessed is part of Audit (Standard) and on by default for E3 and E5 licensed users
Change record
Owners of business-critical apps (backup, archiving, journaling, CRM) informed before any revocation
Step-by-step
Steps 1 to 5 are read-only. Steps 7 to 9 change access and are flagged.
Get the resource service principals and their mail roles (read-only).$graph = Get-MgServicePrincipal -Filter "appId eq '00000003-0000-0000-c000-000000000000'" returns Microsoft Graph in your tenant. $mailRoles = $graph.AppRoles | Where-Object { $_.Value -like 'Mail*' -or $_.Value -like 'MailboxSettings*' } gives the application permission IDs for Mail.Read, Mail.ReadBasic, Mail.ReadWrite, Mail.Send and related roles. Repeat for the Office 365 Exchange Online resource (appId 00000002-0000-0ff1-ce00-000000000000), whose roles include full_access_as_app and the IMAP, POP and SMTP app access roles.
List every app holding those application permissions (read-only).Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $graph.Id -All | Where-Object { $mailRoles.Id -contains $_.AppRoleId }. Each result names the client app (PrincipalDisplayName and PrincipalId) and the role. Do the same against the Exchange Online service principal.
List delegated mail grants (read-only).Get-MgOauth2PermissionGrant -All | Where-Object { $_.Scope -match 'Mail\.|MailboxSettings|EWS\.|IMAP\.|SMTP\.' }. ConsentType AllPrincipals means an admin consented for everyone; Microsoft's playbook says every non-Microsoft application with this should be reviewed carefully. Principal means one user's grant.
Enrich each app (read-only). For each client service principal record: publisher and verified publisher status, owning tenant (your own or external), owners, creation date, reply URLs, and credentials (Get-MgServicePrincipal -ServicePrincipalId <id> | Select DisplayName,AppId,AppOwnerOrganizationId,PasswordCredentials,KeyCredentials; for apps registered in your tenant, also check the application object). Check service principal sign-ins in the Entra sign-in logs for last use and source IPs.
Check existing Exchange scoping (read-only). In Exchange Online PowerShell, Get-ApplicationAccessPolicy shows legacy policies and Get-ServicePrincipal shows RBAC for Applications pointers. Test-ServicePrincipalAuthorization -Identity <AppId> -Resource <mailbox> simulates whether the app is authorised for a given mailbox.
Decide per app. Use the decision table below and record the outcome and owner.
Scope with RBAC for Applications (change). Create the pointer: New-ServicePrincipal -AppId <AppId> -ObjectId <SP object ID> -DisplayName <name>. Define the mailboxes: New-ManagementScope -Name "<scope>" -RecipientRestrictionFilter "<filter>", or use an administrative unit. Assign: New-ManagementRoleAssignment -App <AppId> -Role "Application Mail.Read" -CustomResourceScope "<scope>". Then remove the unscoped Entra grant (step 8), or the scope has no effect.
Revoke unscoped or unneeded grants (destructive). Application permissions: Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All to find the assignment, then remove the single mail role, for example via Graph DELETE https://graph.microsoft.com/v1.0/servicePrincipals/{resource-servicePrincipal-id}/appRoleAssignedTo/{appRoleAssignment-id}. Delegated grants: Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId <id>. In the portal: Entra ID, Enterprise apps, All applications, the app, Permissions, Admin consent tab, Revoke permission. Microsoft notes the portal cannot revoke user consent grants; use Graph for those. Remove only the mail roles you mean to remove, not every role the app holds.
Disable suspicious apps (destructive). Set the service principal to disabled (Update-MgServicePrincipal -ServicePrincipalId <id> -AccountEnabled:$false, or Properties, Enabled for users to sign in: No). Microsoft's playbook prefers disabling to deleting so the app cannot return through new consent, then reporting it to Microsoft.
Deciding what to do with each app
Finding
Risk
Action
Application Mail.ReadWrite, Mail.Send or full_access_as_app, no owner
Critical
Disable now, find the owner, revoke if unclaimed
Application Mail.Read for a defined set of mailboxes (for example a shared inbox processor)
High
Scope with RBAC for Applications, then remove the unscoped Entra grant
Tenant-wide backup, archiving or eDiscovery tool
High, by design
Keep; confirm owner, vendor security posture, credential type and sign-in locations; review quarterly
Delegated Mail.Read with AllPrincipals consent
High
Confirm need; replace with per-user consent or admin consent workflow
Grant is gone: re-run steps 2 and 3; the app no longer appears for the removed role.
Scope is enforced:Test-ServicePrincipalAuthorization returns authorised for an in-scope mailbox and not for an out-of-scope one.
App still works where it should: the owner confirms the integration ran against in-scope mailboxes.
No out-of-scope reads: search for app access with Search-UnifiedAuditLog -StartDate <date> -EndDate <date> -Operations MailItemsAccessed -ResultSize 1000 and inspect AuditData for the app's ID. MailItemsAccessed covers POP, IMAP, MAPI, EWS, Exchange ActiveSync and REST access.
Allow for token lifetime: access tokens already issued remain valid until they expire, so recheck after an hour.
Rollback and common errors
Rollback
Before any change, export each app's current app role assignments and delegated grants to CSV.
To restore an application permission, an administrator grants admin consent again for that role on the app (portal: the app's API permissions, Grant admin consent), or recreates the app role assignment through Graph.
To undo scoping, remove the management role assignment and restore the Entra grant; to re-enable a disabled app, set AccountEnabled back to true.
Common errors
Symptom
Likely cause
Fix
App still reads every mailbox after scoping
Unscoped Entra grant still present (permissions are a union)
Remove the Entra application permission
App reappears after deletion
A user consented again
Disable instead of delete; restrict user consent
Review misses EWS or IMAP apps
Only the Graph resource was queried
Query the Exchange Online resource too
Cannot revoke a user's consent in the portal
Portal does not revoke user consent
Use Remove-MgOauth2PermissionGrant
Revocation script removed unrelated permissions
Script removed all roles for the app
Filter on the specific AppRoleId
No MailItemsAccessed records
User not licensed for Audit (Standard) or auditing off
Check licensing and mailbox auditing
Hardening afterwards
Restrict user consent: Enterprise apps, Consent and permissions, User consent settings. Microsoft's low-impact option (policy managePermissionGrantsForSelf.microsoft-user-default-low) limits consent to verified publishers and permissions you classify as low impact; do not classify any Mail permission as low impact. Turn on the admin consent workflow.
Alert on new grants and credentials: alert on the "Consent to application" audit activity, new app role assignments to mail roles and new credentials on mailbox-capable apps (ATT&CK T1098.001 Additional Cloud Credentials).
Prefer certificates and federation: replace client secrets on mailbox-capable apps with certificates or workload identity federation, and restrict where they can sign in. See the Entra Client Secrets Security Guide.
Measure: track apps with tenant-wide mail application permissions, the share of them scoped with RBAC for Applications, AllPrincipals delegated mail grants, mailbox-capable apps with no owner, and the age of their oldest secret.
Framework mapping
Framework
Reference
Relevance
NIST CSF 2.0
PR.AA-05, ID.AM-02, DE.CM-09
Least-privilege app access, inventory, monitoring
NIST SP 800-53 Rev. 5
AC-6, AC-6(7), AC-2, AU-12, SA-9
Least privilege and privilege review, account management, audit generation, external services
NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 28 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security.
nhimg.org
Free weekly newsletter
Subscribe to the NHI & AI Identity Journal
The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.