How to Integrate with Microsoft Outlook
March 5, 2026
If your product needs inbox access, email sending, scheduling, or calendar sync, a Microsoft Outlook API integration usually means building on Microsoft Graph. That gives you access to mail folders, messages, calendars, events, and change notifications across Microsoft 365 accounts.
But a production-grade Outlook integration involves more than calling /me/messages. You need to register an app in Microsoft Entra ID, choose the right delegated permissions, implement OAuth correctly, decide between delta sync and change notifications, and handle throttling safely.
This guide covers:
- How to integrate directly with Microsoft Graph for Outlook email and calendar
- The operational complexity you will own
- How to integrate Outlook using Unified's Messaging and Calendar APIs
- When to build direct vs use an integration layer
If you are comparing adjacent integrations, you may also want our guides on Gmail API integration and Salesforce API integration.
Direct Microsoft Graph setup
Step 1: Register your app in Microsoft Entra ID
In the Microsoft Entra admin center, create a new app under App registrations. Registration gives you an Application (client) ID and lets you configure one or more redirect URIs under the app's Authentication section. Microsoft documents app registration and redirect URI setup in its Graph authentication guidance.
For a B2B SaaS integration, you will usually choose a multi-tenant app registration so customers in different Microsoft 365 tenants can authorize your app. That decision depends on your product and customer base, but the Entra registration flow is where you set it.
Step 2: Choose delegated vs application permissions
For inbox and calendar integrations in SaaS products, delegated permissions are usually the default. They let your app act on behalf of the signed-in user, and /me/... endpoints only work in delegated scenarios. Application permissions are app-only and are generally used for background services or tenant-wide access with admin consent.
That distinction matters immediately:
- Use delegated when each user connects their own mailbox and calendar
- Use application only when you truly need service-level access to mailboxes across a tenant and can support admin consent workflows
Step 3: Configure the right Graph permissions
For Outlook email and calendar, the common delegated permissions include:
Mail.ReadBasicorMail.Readfor reading mailMail.ReadWritefor updating or deleting messagesMail.Sendfor sending mailCalendars.ReadBasicorCalendars.Readfor reading calendars and eventsCalendars.ReadWritefor creating or editing eventsoffline_accessif you need refresh tokens for long-lived connections
As with every OAuth integration, request the least privilege you need.
Step 4: Implement OAuth 2.0 authorization code flow
For user-connected Outlook integrations, the standard flow is the Microsoft identity platform's authorization code flow.
You send the user to the authorize endpoint with:
client_idresponse_type=coderedirect_uriscopestate
Then you exchange the returned code at the token endpoint, typically including:
client_idclient_secretfor confidential clientscoderedirect_urigrant_type=authorization_code
Request offline_access if you need a refresh token so the integration can continue working after the original access token expires. Microsoft's OAuth documentation explicitly calls this out.
Core Microsoft Graph endpoints for Outlook email and calendar
List mail folders
To list Outlook folders, use:
GET /me/mailFolders
GET /users/{id}/mailFolders
You can also include includeHiddenFolders=true, and Graph supports common OData parameters like $top, $skip, $select, $filter, and $orderby here.
List messages
To list all messages:
GET /me/messages
GET /users/{id}/messages
To list messages in a specific folder:
GET /me/mailFolders/{id}/messages
GET /users/{id}/mailFolders/{id}/messages
Graph supports $select and $top, and Microsoft documents some important rules when combining $filter and $orderby.
Get a message
To retrieve a single message:
GET /me/messages/{id}
GET /users/{id}/messages/{id}
If you need MIME content, append /$value. You can also use the Prefer: outlook.body-content-type header to request text or HTML body formatting.
Send mail
To send an email:
POST /me/sendMail
POST /users/{id}/sendMail
This requires Mail.Send. Microsoft Graph returns 202 Accepted for successful send requests.
List calendars
To list calendars:
GET /me/calendars
GET /users/{id}/calendars
You can also list calendars within a calendar group. OData parameters are supported here as well.
List events
To list events from the default calendar:
GET /me/calendar/events
GET /users/{id}/calendar/events
To list events from a specific calendar:
GET /me/calendars/{id}/events
GET /users/{id}/calendars/{id}/events
You can set Prefer: outlook.timezone to control how start and end times are returned.
Create and update events
To create an event:
POST /me/events
POST /users/{id}/events
POST /me/calendars/{id}/events
To update an event:
PATCH /me/events/{id}
PATCH /users/{id}/events/{id}
PATCH /me/calendars/{id}/events/{id}
Graph supports partial updates, and Microsoft recommends using transactionId on create requests for idempotency.
Change sync options: delta queries vs change notifications
Delta queries
Microsoft Graph supports delta queries for both messages and events.
For mail, you can use:
GET /me/messages/delta
GET /me/mailFolders/{id}/messages/delta
For calendar sync, Graph supports delta on calendar views, for example:
GET /me/calendarView/delta?startDateTime=...&endDateTime=...
The pattern is:
- Make the initial delta request
- Follow
@odata.nextLinkuntil exhausted - Persist the final
@odata.deltaLink - Reuse that delta link later to retrieve only changes since the last checkpoint
This is the right pattern for efficient pull-based sync.
Change notifications (webhooks)
Graph also supports change notifications for Outlook resources including messages and events. You create a subscription via POST /subscriptions, provide your notificationUrl, specify the monitored resource, and include changeType, expirationDateTime, and clientState.
Important operational details:
- Graph validates your webhook by sending a
validationToken - Your endpoint must return the plain-text token within 10 seconds
- Subscriptions expire and must be renewed
- Outlook resources have bounded subscription lifetimes, so renewal logic is mandatory
In practice, many robust integrations use change notifications to trigger work and delta queries to fetch the actual changes. That reduces missed updates and keeps sync logic simpler.
Throttling and retry behavior
Microsoft Graph returns 429 Too Many Requests when you hit throttling limits. When that happens, Graph usually includes a Retry-After header, and Microsoft's guidance is clear: wait the specified number of seconds, then retry. If no Retry-After header is present, implement exponential backoff.
Microsoft also recommends avoiding aggressive polling and using delta queries and change notifications instead, which is especially relevant for inbox and calendar sync.
Where direct Outlook integrations become operationally expensive
A direct Microsoft Graph integration means you own:
- Entra app registration and tenant configuration
- Delegated vs application permission strategy
- OAuth flow implementation and refresh token handling
- Mail + calendar endpoint orchestration
- Delta checkpoint storage
- Webhook subscription creation, validation, and renewal
- Throttling management and backoff
- Multi-tenant mailbox isolation
- Admin-consent-heavy scenarios for broader directory access
For a single internal tool, this may be acceptable.
For a customer-facing SaaS product serving many Microsoft 365 tenants, this is real infrastructure work.
Integrating Microsoft Outlook via Unified
Using the Unified Outlook configuration you shared, the flow is simpler.
Step 1: Register Outlook OAuth for Unified
For Unified, the redirect URI is:
https://api.unified.to/oauth/code
You also noted region-specific variants:
https://eu.api.unified.to/oauth/codehttps://au.api.unified.to/oauth/code
On the Outlook side, Unified scopes map to Microsoft Graph scopes like:
messaging_channel_read→Mail.ReadBasicmessaging_message_read→Mail.Readmessaging_message_write→Mail.Read,Mail.Send,Mail.ReadWritecalendar_calendar_read/calendar_event_read/calendar_busy_read→Calendars.Readcalendar_calendar_write/calendar_event_write→Calendars.ReadWrite
Plus identity scopes such as openid, email, profile, and offline_access, based on the integration sheet you shared.
Step 2: Authorize a connection
Unified's pattern is:
- Activate the Outlook integration in your workspace
- Redirect the user through Unified's authorization flow
- Receive a
connection_idafter successful authorization
That gives you a stable identifier for future Messaging and Calendar API calls.
Step 3: Call Unified's Messaging API
Based on the integration details you shared, Outlook under Unified supports:
- Channel: list, get
- Message: list, get, create, update, remove
A first-call example to list folders/channels looks like:
curl -X GET "https://api.unified.to/messaging/CONNECTION_ID/channel?limit=50&offset=0" \
-H "Authorization: Bearer ACCESS_TOKEN"
And to list messages in a folder:
curl -X GET "https://api.unified.to/messaging/CONNECTION_ID/message?channel_id=CHANNEL_ID&limit=50" \
-H "Authorization: Bearer ACCESS_TOKEN"
To create or send a message:
curl -X POST "https://api.unified.to/messaging/CONNECTION_ID/message" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channels": ["CHANNEL_ID"],
"subject": "Hello",
"message": "This is the body",
"message_html": "<p>This is the <strong>HTML</strong> body</p>",
"attachments": []
}'
Step 4: Call Unified's Calendar API
From the Outlook mapping you shared, Unified supports:
- Calendar: list, get
- Event: list, get, create, update, remove
- Busy: list
Examples:
List calendars:
curl -X GET "https://api.unified.to/calendar/CONNECTION_ID/calendar?limit=50&offset=0" \
-H "Authorization: Bearer ACCESS_TOKEN"
List events:
curl -X GET "https://api.unified.to/calendar/CONNECTION_ID/event?calendar_id=CALENDAR_ID&limit=50" \
-H "Authorization: Bearer ACCESS_TOKEN"
Create an event:
curl -X POST "https://api.unified.to/calendar/CONNECTION_ID/event" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"calendar_id": "CALENDAR_ID",
"start": "2026-03-10T15:00:00Z",
"end": "2026-03-10T16:00:00Z",
"summary": "Planning meeting",
"description": "Weekly planning meeting",
"attendees": [{"email": "user@example.com", "name": "User Name"}]
}'
List free/busy data:
curl -X GET "https://api.unified.to/calendar/CONNECTION_ID/busy?calendar_ids[]=CALENDAR_ID&start=2026-03-10T00:00:00Z&end=2026-03-10T23:59:59Z" \
-H "Authorization: Bearer ACCESS_TOKEN"
Step 5: Use passthrough when needed
The Outlook integration details you shared also include passthrough methods (get, post, put, patch, delete). That gives you a fallback path for Graph features not covered by Unified's normalized Messaging and Calendar models.
Unified webhooks for Outlook
Based on the Unified Outlook notes you shared:
- Outlook supports both native and virtual webhooks in Unified for messages and calendar events
- Native webhooks are used when Graph supports subscriptions for the resource
- Virtual webhooks are used when polling is needed or selected
- Unified recommends webhooks over polling and applies built-in retry/backoff behavior
That means you can get standardized change notifications without implementing Graph subscription validation and renewal yourself, depending on how you configure the integration.
Direct vs Unified: when to choose each
Build direct with Microsoft Graph if:
- Outlook is one of your core product surfaces
- You need full Graph flexibility for mail and calendar features
- You are comfortable owning delta sync, webhook subscriptions, renewal, and throttling logic
- You need app-only scenarios, tenant-wide access, or highly custom Microsoft 365 behavior
Use Unified if:
- You want one integration surface across Outlook and other providers
- You prefer not to manage Graph-specific OAuth, webhook validation, and renewal logic
- Your product mainly needs common email + calendar behavior
- You want normalized channel, message, calendar, event, and busy abstractions
- You want passthrough available for edge cases
Final thoughts
A Microsoft Outlook integration is straightforward at the endpoint level.
The engineering complexity shows up in:
- delegated vs application permission decisions
- long-lived OAuth handling
- mailbox and calendar sync design
- webhook validation and renewal
- delta checkpoint management
- throttling and retry behavior
If Outlook email and calendar are central to your product, building directly on Microsoft Graph can make sense.
If they are critical but not differentiating, using a normalized integration layer can reduce time-to-market and lower long-term maintenance.