Skip to content

Integration setup · for IT

Microsoft 365 mailbox access

For the administrator of the customer's Microsoft 365 tenant. Everything is configured inside your own tenant; roughly 20 minutes.

~20 minutesApp-only OAuth, no user contextScoped to one mailbox

This page was almost certainly forwarded to you by a colleague who is setting up a BestTeam mailbox. What they are reading is the same procedure written for a non-administrator — worth a glance if you want to see what has been asked of them.

What is being requested

Permission
Office 365 Exchange Online → Application → IMAP.AccessAsApp
Grant type
OAuth 2.0 client credentials (app-only). No user context, no delegated permissions
Protocol
IMAP4 over TLS, outlook.office365.com:993, SASL XOAUTH2
Token scope
https://outlook.office365.com/.default
Mailbox scope
One named mailbox, enforced by an Exchange Application Access Policy
Operations used
SELECT, FETCH, SEARCH, and APPEND to Drafts. No \Deleted, no EXPUNGE, no SMTP
Redirect URI
None. There is no interactive sign-in and no reply URL
Inbound access
None. All connections are outbound from our host
This is not basic authentication. Blocking legacy authentication, security defaults and “disable basic auth for IMAP” all remain in force and do not affect this. The connection authenticates with an OAuth bearer token over XOAUTH2, which is the modern-auth path Microsoft provides for IMAP.
IMAP.AccessAsApp is not a Graph mail permission. It enables the IMAP protocol for the application. It grants no access to the Microsoft Graph mail API, no Mail.Read/Mail.ReadWrite, and nothing outside Exchange.

What the application does with the access

It polls the mailbox every few minutes, reads new messages, and APPENDs reply drafts to the Drafts folder. It never sends: the product has no SMTP client and no send operation anywhere in it, so a draft leaves the tenant only when a person opens it in Outlook and presses send.

Message bodies are redacted before anything is stored on our side. Attachments are parsed as text (PDF, Word, Excel, XML, plain text); images are not OCR'd.

Roles you need

StepRole
App registrationApplication Administrator (or Global Administrator)
Grant admin consent for an application permissionGlobal Administrator or Privileged Role Administrator
New-ServicePrincipal, Add-MailboxPermission,New-ApplicationAccessPolicyExchange Administrator (or Global Administrator)

Procedure

1

Register the application

entra.microsoft.com → Applications → App registrations → New registration
  • Name: BestTeam, or your own convention
  • Supported account types: single tenant — accounts in this organizational directory only
  • Redirect URI: leave empty

From Overview, record the Directory (tenant) ID and the Application (client) ID.

2

Add the permission and consent

API permissions → Add a permission → APIs my organization uses → Office 365 Exchange Online → Application permissions → IMAP → IMAP.AccessAsApp

Then Grant admin consent. Remove the default User.Read delegated permission if your baseline requires it; it is not used.

Verify the row reads Granted for <tenant>. A tenant-wide consent policy that blocks admin consent for application permissions will silently leave it ungranted — that surfaces later as an authentication failure whose message is indistinguishable from a bad secret.
3

Create a client secret

Certificates & secrets → Client secrets → New client secret (24 months maximum)

Record the Value (not the Secret ID) and the expiry date. The Value is retrievable only at creation.

Certificate credentials are not supported by this integration. If your policy forbids client secrets, tell us before you start — we would rather know now than have you discover it here.
4

Register the service principal in Exchange and grant mailbox access

The Object ID below is the service principal's object ID — Entra ID → Enterprise applications → your app → Object ID. It is not the object ID shown on the App registration blade.

Fill in once · the commands below update themselves

The client secret is not needed here and this page never asks for it. Values stay in your own browser.

Install the module and connect
Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser
Connect-ExchangeOnline -UserPrincipalName <admin-upn>
Register the principal, grant mailbox access
New-ServicePrincipal -AppId <application-id> -ServiceId <sp-object-id> -DisplayName "BestTeam"
Add-MailboxPermission -Identity <mailbox> -User <sp-object-id> -AccessRights FullAccess

New-ServicePrincipal fails with already exists on tenants where Exchange has already synced the principal; that is benign, continue.

On FullAccess

FullAccess on the target mailbox is what Microsoft's app-only IMAP flow requires — there is no narrower mailbox right that permits IMAPSELECT and APPEND. It is granted on one mailbox, not tenant-wide, and step 5 is what prevents the application from using its permission against any other mailbox. If you skip step 5, the permission is effectively tenant-wide.

A shared mailbox is a good fit here and needs no licence under the usual size limit. If the mailbox does not exist yet, create it as a shared mailbox rather than a licensed user.

5

Scope it to the one mailbox

Create the access policy
New-ApplicationAccessPolicy -AppId <application-id> -PolicyScopeGroupId <mailbox> -AccessRight RestrictAccess -Description "BestTeam: single mailbox"
Verify: Granted here, Denied elsewhere
Test-ApplicationAccessPolicy -Identity <mailbox> -AppId <application-id>
End the session
Disconnect-ExchangeOnline

Scope to a mail-enabled security group instead of a single address if that fits your model better — pass the group as -PolicyScopeGroupId.

Policy changes take up to an hour to propagate. A connection test run immediately afterwards can fail on a policy that is in fact correct.

If you already use RBAC for Applications for this class of scoping, it is a reasonable substitute for the access policy. We have verified this integration against New-ApplicationAccessPolicy and not against RBAC for Applications, so if you take that route, tell us and expect one extra round of testing.

6

Hand back four values

ValueWhere
Directory (tenant) IDStep 1, Overview
Application (client) IDStep 1, Overview
Client secret ValueStep 3
Secret expiry dateStep 3

Plus the mailbox SMTP address.

Please do not send the secret by email or chat. Use whatever your organisation already uses for credential handover — a password manager share link, a one-time secret service, or read it to us on the call. On our side it is encrypted at rest with a Fernet key held outside the database.

The expiry date is not decorative: we store it and warn a month ahead. Without it, the first symptom of expiry is a mailbox that silently stops being processed, with an error indistinguishable from a wrong secret.

Network egress

Outbound from our host only:

DestinationPortPurpose
login.microsoftonline.com443Token acquisition
outlook.office365.com993IMAP over TLS

Nothing connects inbound to your network, there is no on-premises component, and no service account of yours is used for interactive sign-in. Tokens last about an hour and are refreshed roughly a minute before expiry.

Auditing and revocation

If authentication fails

The error our side reports distinguishes these, because the fixes differ:

SymptomCause
Token request rejectedWrong tenant ID, wrong client ID, or wrong/expired secret — most often the Secret ID was handed over instead of the Value
Token issued, AUTHENTICATE XOAUTH2 refusedAdmin consent missing (step 2), the step 4 commands not run, or the access policy excludes this mailbox (step 5)
Mailbox not foundAddress is not a mailbox in this tenant, or it is a distribution list or a Microsoft 365 group rather than a mailbox
If your tenant applies Conditional Access for workload identities, a policy scoped to service principals can block this application's sign-in. It surfaces in the service principal sign-in logs as a CA failure rather than a credential failure — worth checking before rotating anything.

Questions we get asked

Why IMAP rather than Graph?

The per-organisation mailbox path in this product is IMAP with XOAUTH2. IMAP.AccessAsApp also has a narrower blast radius than Mail.ReadWrite: it enables one protocol rather than the whole Graph mail surface.

Can it be scoped to a folder?

No. Neither IMAP permissions nor application access policies scope below the mailbox. The mailbox is the unit, which is the argument for pointing this at a dedicated shared mailbox rather than someone's personal one.

Can we use a certificate instead of a secret?

Not in the current build. See the note in step 3.

What happens if we delete the access policy?

The application regains the ability to reach every mailbox in the tenant, up to the limit of its IMAP.AccessAsApp grant. Keep the policy.

Anything unclear or refused by your policy, tell the person who sent you this document, or write to us directly at admin@bestteam.online. It is a normal outcome and we would rather adjust than have you work around it.