# Microsoft Graph API alternative

Source: https://developer.nylas.com/docs/cookbook/email/microsoft-graph-api-alternative/

Reading one Outlook inbox through the Microsoft Graph API starts with an Azure app registration, a set of delegated or application permissions, and an admin who approves them. Add a second tenant and you repeat the consent dance. Add calendar and you wire up per-resource subscriptions that expire every few days. Graph covers nearly every Microsoft 365 surface, but the setup and operational cost is real, and most of it has nothing to do with the email or events you actually want.

This guide compares the Graph API with a unified alternative for Outlook and Microsoft 365 email and calendar, shows what each approach costs to stand up, and is honest about when calling Graph directly is still the right choice.

## Microsoft Graph API vs a unified alternative

A unified API puts one schema and one OAuth flow in front of Microsoft 365, Outlook.com, and Exchange Online, so you read mail and calendar through `GET /v3/grants/{grant_id}/messages` and `GET /v3/grants/{grant_id}/events?calendar_id=<CALENDAR_ID>` instead of managing Graph permissions and subscriptions yourself. The same grant also reaches Google and iCloud, which Graph can't.

The two approaches solve different problems. Graph is Microsoft's complete surface: mail, calendar, Teams, SharePoint, OneDrive, and Planner, all behind one Azure app. If you need those Microsoft-only services, nothing replaces it. If you need email and calendar across more than one provider, the unified layer removes the Azure registration, the per-resource subscription renewals, and the provider-specific retry logic. The table below compares the two on the work email and calendar integrations actually require.

| Task | Microsoft Graph directly | Unified alternative |
| --- | --- | --- |
| **Auth setup** | Azure app registration plus admin consent per tenant | 1 connector, OAuth handled for you |
| **Read mail** | `GET /me/messages` with `Mail.Read` | `GET /v3/grants/{grant_id}/messages` |
| **Read calendar** | `GET /me/events` with `Calendars.Read` | `GET /v3/grants/{grant_id}/events?calendar_id=<CALENDAR_ID>` |
| **Real-time updates** | Per-resource subscriptions, renew every ~3 days | One webhook subscription, no renewal |
| **Other providers** | Microsoft only | Google, iCloud, Yahoo, IMAP, and more |

## What does Microsoft Graph require to read email and calendar?

Graph requires an Azure app registration, OAuth permissions scoped to mail or calendar, and admin consent before your app can touch a single mailbox. You register the app in Microsoft Entra, request scopes like `Mail.Read` or `Calendars.ReadWrite`, and an administrator approves them for the tenant. Application permissions need consent before any user can connect.

Two operational facts shape every Graph integration. First, basic authentication is gone: Microsoft deprecated it for all Exchange Online accounts on October 1, 2022, so OAuth is the only path. Second, Graph throttles aggressively. Outlook applies a per-mailbox limit of 10,000 requests per 10-minute window per app, returning a `429` with a `Retry-After` header when you cross it. Graph also enforces a global per-app ceiling of 130,000 requests every 10 seconds across all its services, not just Outlook. The exact mail and calendar endpoints are real and stable: `GET /me/messages` for mail and `GET /me/events` for calendar. For the Azure setup itself, see [create an Azure app](/docs/provider-guides/microsoft/create-azure-app/) and the [Microsoft Graph throttling limits](https://learn.microsoft.com/en-us/graph/throttling-limits) documentation.

## How do I read Outlook calendar events without Microsoft Graph?

Send a single `GET` to `/v3/grants/{grant_id}/events` with a `calendar_id` query parameter. The unified endpoint returns Outlook and Microsoft 365 events in the same JSON shape it uses for Google and iCloud, so you write one parser instead of mapping Graph's `event` resource by hand. The `grant_id` stands in for the Azure app registration and the per-mailbox token Graph would otherwise require.

The request below lists events from a connected Microsoft account. The `calendar_id` is required; pass `primary` for the account's default calendar. The response includes a `when` object, `participants`, and a `recurrence` array on the recurring series, identical to every other provider, which is the difference from parsing Graph's response per field.

```bash
curl --request GET \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events?calendar_id=primary&limit=50' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>'
```

```python [graphAlt-Python SDK]
from nylas import Client

nylas = Client(api_key="<NYLAS_API_KEY>")

events = nylas.events.list(
    "<NYLAS_GRANT_ID>",
    query_params={"calendar_id": "primary", "limit": 50},
)

for event in events.data:
    print(event.title, event.when)
```

For the full read flow, filters, and pagination on Microsoft accounts, see [list Microsoft calendar events](/docs/cookbook/calendar/events/list-events-microsoft/). Reading mail works the same way through [list Microsoft email messages](/docs/cookbook/email/messages/list-messages-microsoft/).

## How do I handle enterprise OAuth at scale?

Use admin consent once per tenant, then connect users without per-user approval prompts. For enterprise Microsoft 365 integrations, an administrator grants consent to your application's permissions in the Microsoft Entra admin center, which authorizes every user in that tenant at once. This is the same Graph consent model, fronted by a single connector instead of a raw Azure app your code manages directly.

At scale, two things matter: getting consent approved and connecting many mailboxes efficiently. Admin consent unblocks application permissions that individual users can't approve on their own, and the [admin approval guide](/docs/provider-guides/microsoft/admin-approval/) walks through the Entra request flow. To onboard mailboxes in bulk after consent, a Microsoft application grant connects accounts without sending each user through an interactive login, which suits provisioning hundreds of seats. The limit of 10,000 requests per mailbox per 10 minutes still applies per account, so favor webhooks over polling when you watch many inboxes at once.

## When should you use Microsoft Graph directly?

Use Graph directly when your app is Microsoft-only and depends on services outside email and calendar. Graph is the only API that reaches Teams messages, SharePoint files, OneDrive, Planner tasks, and Entra directory data. If your roadmap lives entirely inside Microsoft 365 and touches those surfaces, the Azure registration you set up pays for itself, and a unified layer would just sit in the way.

Direct Graph holds up until you add a second provider or need only mail and calendar. Supporting Google plus Microsoft through Graph means a second, unrelated integration against the Gmail API, with its own OAuth project, ID formats, and quotas. One unified schema collapses that into a single code path across both, and the same grant reaches 6 providers, so adding iCloud or Exchange later costs no new integration. If you have already decided to consolidate, the [migrate from Gmail API and Microsoft Graph](/docs/cookbook/use-cases/build/migrate-from-gmail-graph/) guide covers the concept mapping and migration steps in detail.

## What's next

- [List Microsoft email messages](/docs/cookbook/email/messages/list-messages-microsoft/) for the unified read call on Outlook and Microsoft 365 accounts
- [Migrate from Gmail API and Microsoft Graph](/docs/cookbook/use-cases/build/migrate-from-gmail-graph/) for the full concept mapping and migration plan
- [Create an Azure app](/docs/provider-guides/microsoft/create-azure-app/) if you connect Microsoft accounts through your own Azure registration
- [Getting started with Nylas](/docs/v3/getting-started/) to create a project, connector, and your first grant