Skip to main content

Set up Microsoft Graph mailbox access

Prepare Microsoft Graph application access before importing or synchronizing a Microsoft mailbox. This guide covers MailGen's backend application identity. Configure interactive sign-in separately through account login setup.

Before you start​

You need a Microsoft Entra tenant, an application registration you can manage, administrator authority to grant consent, and an Exchange Online mailbox. You also need this deployment's supported runtime configuration.

Three identities serve different purposes:

IdentityPurpose
App login / actorThe signed-in MailGen user that requests an action
Connected account / mailboxThe verified binding to a specific provider mailbox
Backend service principalThe application identity that gets Graph tokens and calls Microsoft

Better Auth access/refresh tokens identify app login. MailGen does not use them as its backend Graph mailbox credential. Backend Graph uses application permissions and the client-credentials .default scope. See Microsoft's app-only authentication contract.

Register and authorize the application​

  1. Open Microsoft Entra admin center → App registrations and select or create the backend application.
  2. Record its Directory (tenant) ID and Application (client) ID in the deployment's secret configuration.
  3. Prepare the supported application credential. Keep secret values or private files outside source control.
  4. Open API permissions → Add a permission → Microsoft Graph → Application permissions.
  5. Add the permissions for the enabled operations below.

Then choose Grant admin consent for your tenant. Adding permission names without granting consent does not authorize the service principal. Interactive login consent is a separate operation.

FeatureGraph application permission
Mandatory production onboarding exportMailboxItem.Export.All
Mail reads/importMail.Read or the broader Mail.ReadWrite needed for writes
Draft, message, and folder writesMail.ReadWrite
SendingMail.Send
Personal contact readsContacts.Read
Personal contact writesContacts.ReadWrite
Calendar readsCalendars.Read
Calendar writes, when enabledCalendars.ReadWrite
Mailbox settings/category readsMailboxSettings.Read
Mailbox settings/category writesMailboxSettings.ReadWrite
Directory people and user license dataUser.Read.All
Directory public groups and user membership IDsGroupMember.Read.All
Tenant license catalogLicenseAssignment.Read.All
Active Global Administrator proofRoleManagement.Read.Directory

Production onboarding requires MailboxItem.Export.All with tenant administrator consent for POST /admin/exchange/mailboxes/{id}/exportItems. Normal mail-read/write permissions do not authorize this export. The importer requires raw export and attachment extraction before its completion barrier can pass. MailboxItem.ImportExport.All is broader and unnecessary for this export-only workflow. See the exportItems permission contract.

Directory groups require separate read authority from people. Grant GroupMember.Read.All with tenant consent for group listing and member enumeration. An existing supported broader read permission can satisfy these endpoints. No directory-write permission is needed. Group refresh can fail while the base people refresh succeeds.

The standalone CLI and dashboard do not run the production importer. Their normal mailbox operations do not require its export permission. Use only the permissions required by the selected workflow. A wider permission does not implement an unsupported MailGen feature. Do not grant directory-write roles for read-only authorization checks. See external-service prerequisites for entitlement and reset scope.

Exchange application restrictions can still limit which mailboxes the application can reach after tenant consent. Make sure the intended mailbox lies within the permitted scope. Test with a designated mailbox before enabling writes.

Connect runtime credentials​

Backend bootstrap and GraphOneTimeUserOnboarder require BACKEND_TENANT_ID, BACKEND_CLIENT_ID, and BACKEND_CLIENT_SECRET, including standalone worker execution. The root Compose environment passes these names through unchanged. The worker's committed .env.example still shows stale unprefixed Graph names. Use the BACKEND_* names from the runtime contract instead.

The standalone CLI and lab dashboard use TENANT_ID, CLIENT_ID, and CLIENT_SECRET. These names are not interchangeable with the production worker names. See the environment reference.

Mailbox-scoped Graph transport resolves msintegrationv2.tenant_connections. It checks granted consent and credential expiry before requesting a token. Supported connection modes include client secret, certificate, managed identity, and workload identity. A missing mailbox connection does not fall back to another tenant's credential.

Use the configured mode and reference format for the deployment. env:// references resolve a named runtime value. file:// references identify a mounted credential file. Neither the browser nor an administrator form needs the Graph secret itself.

Configure notifications and storage​

Configure the deployment's own public HTTPS callback URLs:

GRAPH_WEBHOOK_URL=https://<your-public-host>/graph/webhook
GRAPH_LIFECYCLE_WEBHOOK_URL=https://<your-public-host>/graph/lifecycle

Route both paths to WebhookCatcher while preserving the full path. Do not use another developer's tunnel or InstantUserDataGetter as the external webhook target. Configure a stable GRAPH_WEBHOOK_CLIENT_STATE.

Follow Graph cryptography setup for the notification certificate, private key, certificate ID, and DELTA_LINK_ENCRYPTION_KEY. These are distinct from the app credential and personal mail-encryption key.

Prepare PostgreSQL, Kafka, S3, and search through installation. Import stores bodies and attachments in object storage. A database connection alone is insufficient.

Connect and provision one mailbox​

This procedure requires a prepared Microsoft deployment. Complete account login setup and the Graph, notification, storage, and queue prerequisites above. The signed-in actor needs mail.onboarding permission. See authorization for actor rights.

The Microsoft connector also requires a persisted tenant connection with granted consent, a service-principal ID, and a credential reference. The credential must not be expired. The connection must satisfy the configured Microsoft tenant selection. Environment credentials alone do not satisfy this availability check.

This procedure starts with that tenant connection already prepared. It does not initialize the first tenant connection in an empty database. An unavailable Microsoft action means the connector configuration or persisted-connection availability check did not pass. It does not mean that a mailbox row must be created first.

  1. Open /onboarding after signing in to MailGen. The page title is Connect Account.
  2. If the intended Microsoft account is not linked, choose Continue with Microsoft when available. Complete Microsoft identity linking and return to /onboarding?sync=1.
  3. Select the intended connected account owned by your MailGen login. Use Switch mailbox where offered. Check its email address and Microsoft provider before starting.
  4. Choose Start onboarding. The workspace setup gate uses the equivalent Set up mailbox action.
  5. Follow the selected account's saved step progress until ready. The interface then opens the workspace. Confirm import and search readiness separately.

Microsoft identity linking requests openid, profile, email, offline_access, User.Read, and Mail.ReadWrite. These are delegated identity/link grants. They do not grant the backend its app-only permissions. The importer uses the separate BACKEND_* application credentials and tenant administrator consent described above.

The start action checks ownership of the connected account and fresh mail.onboarding permission. It accepts the request into the queue. An existing mailbox row or non-null mailboxId is not required to start.

The .NET worker resolves the linked email through Graph. It checks that the returned user matches the authorized Entra subject. It then creates or updates the local mailbox and tenant-connection records. Request acceptance is not import completion. Follow the saved run and step status rather than starting another import because progress appears late.

For failed or failedRetryable, inspect the displayed step error and use Retry onboarding when offered. The workspace gate calls this Retry mailbox setup. If Microsoft linking reports no usable identity, reconnect through the Microsoft action and approve its requested profile permissions. A content-key request needs the correct existing key backup and unlock.

Check the result​

Use Connect and provision one mailbox, then follow onboarding progress. Confirm import and search readiness separately. Open Sync Center to inspect subscription and operation health.

A webhook acknowledgement means durable hint acceptance. Delta reconciliation establishes current provider content. An operation marked accepted does not prove a provider write. Wait for its final state before treating it as confirmed.

FailureCheck
Token acquisition failsTenant/client identity, credential reference, expiry, consent state
Graph 403Application permission, admin consent, Exchange mailbox scope
Login works, mailbox failsSeparate backend Graph connection and mailbox binding
Notifications absentPublic HTTPS route, subscription state, certificate, client state
Content work waits for a keyCorrect owner encryption key and active unlock

For Google mailboxes, use Google Cloud setup. Microsoft application consent does not authorize Gmail.