Migrating from the Exchange Web Services (EWS) notification framework, which supports push, pull, and streaming notification types, to the Microsoft Graph subscription model represents a transition toward a unified, stateless, and event-driven framework. This framework supports more than just Exchange data. Although Microsoft Graph streamlines notifications through webhooks, replacing the varied EWS push, pull, and long-lived connection models requires an architectural redesign.
You can migrate your applications by integrating modern Microsoft Graph capabilities like rich notifications for reduced latency and immutable IDs for stable item tracking. A successful migration involves moving beyond simple event listening to a hybrid strategy that combines near-real-time change notifications with delta queries for reconciliation, while navigating the strict concurrency and availability thresholds of a cloud-native environment.
EWS notifications
An application can use three types of EWS notifications, each with different tradeoffs in terms of latency, scalability, and connection management:
- Push notifications – Exchange sends an HTTP/HTTPS request to a listener endpoint hosted by your application whenever an event occurs.
- Pull notifications – The application periodically calls Exchange to check for new events.
- Streaming notifications – Establishes a long-lived connection to Exchange (via an HTTP get), allowing the server to push events down to the client as they occur. This eliminates the need for a public endpoint.
Microsoft Graph change notifications
Microsoft Graph only has one type of change notification, which is delivered via webhooks—HTTP POST requests sent to a listener endpoint hosted by your application when a subscribed event occurs. This model enables near real-time updates without the need for constant polling.
For more advanced scenarios, Microsoft Graph also supports delivering change notifications through Azure Event Hubs. This option is better suited to enterprise-grade applications, and provides enhanced security, scalability, and reliability, particularly in high-throughput or distributed processing environments.
Microsoft Graph rich notifications
Microsoft Graph rich notifications allow change notifications to include relevant data about the item that triggered the event. For real-time notification scenarios, this data inclusion reduces latency between when an item arrives and when the client is notified, and provides immediate access to key details (such as the subject of a new message and who the sender was).
Rich notifications simplify certain use cases compared to traditional EWS notifications. For applications where real-time notification is the primary requirement, rich notifications reduce the need for follow-up calls to retrieve item data.
Pull notifications and change tracking in Microsoft Graph
In EWS, notifications relied on the GetEvents operation to retrieve the changes since the last notification. In push and pull notifications, a watermark was available that acted as a subscription marker. In Microsoft Graph, the equivalent capability is provided through delta queries.
Delta queries enable applications to track changes by requesting only the data that has been added, updated, or deleted since the previous query. Instead of maintaining a connection or polling for events, applications store a delta token returned by Microsoft Graph and use it in subsequent requests to continue where they left off.
Microsoft Graph supports delta queries for the following resource types:
- Folders: Individual Mail, Contact, and Calendar folders.
- Item collections: Messages, contacts, events, and to do (tasks).
For calendar data, delta queries are supported on both event collections that expose unexpanded recurrence data (where a recurring series is represented as a single master event) and calendar views that return expanded instances of those recurrences (where each occurrence is expanded as an individual event within a specified time range).
Immutable IDs
Microsoft Graph introduces immutable IDs for mailbox items, a capability that has no direct equivalent in EWS. An immutable ID is a stable, unique identifier for an item — such as a message, contact, or event — that remains constant for the lifetime of the item within a mailbox.
Unlike EWS and Microsoft Graph itemId values, which change when an item is moved between folders, an immutable ID remains unchanged. This means that if an application stores the ID externally, it continues to reference the same item regardless of folder moves within the mailbox.
Immutable IDs simplify application design compared to EWS. With EWS, developers often needed to track and update externally stored item identifiers after item move operations — a common use case for notifications. With immutable IDs, that additional tracking logic is unnecessary. As a result, the code is more robust and easier to maintain.
Note that when items move across mailbox boundaries — such as between mailboxes or from a mailbox to an archive store — the immutable ID is invalid because the item is assigned a new ID. If your application needs to track items moved between a mailbox and an archive, consider using a custom extended property instead.
Differences in subscriptions between EWS and Microsoft Graph
In EWS, subscriptions are typically created against a specific mailbox folder or across all folders within a mailbox.
In Microsoft Graph, change notification subscriptions can be created on specific folder types (such as Inbox or Calendar) or on resource collections such as `messages`, `contacts`, or `events`. However, this model is more constrained than EWS. It supports a reduced set of folder types and doesn’t provide the same level of granularity across all mailbox folders.
For example, consider an EWS application that uses EWS notifications to subscribe to all mail folders in a mailbox. The application needs to detect when a new email arrives, as well as when an email is moved into a processed folder. With Microsoft Graph, the application instead subscribes to the /messages collection to receive notifications for the entire mailbox.
To track moves, the application monitors created and deleted events and checks the parentFolderId to determine the item’s location. Because standard item IDs change when a message moves between folders, the application uses immutable IDs to correlate the item’s identity across the mailbox. The application then uses delta queries to reconcile these changes, allowing it to distinguish between newly received messages and moved messages.
Custom folders gap
Microsoft Graph subscriptions don’t work for all mailbox folders. Custom folders or folders that are typically associated with legacy client features aren’t accessible through the Microsoft Graph messages, contacts, events, or to do endpoints. For custom folders, you can either find an alternative solution outside of Exchange or migrate content to a supported endpoint such as messages, where webhooks are available.
Streaming subscription gap
Because Microsoft Graph doesn’t provide an equivalent to the EWS streaming subscription model, applications that use streaming notifications typically require architectural redesign. Instead of maintaining long-lived connections, Microsoft Graph relies on webhook-based notifications, which require a publicly accessible endpoint.
A common approach is to host the application on a highly available platform that can expose a secure public endpoint, such as Microsoft Azure or a comparable cloud provider. This hosting ensures reliability, scalability, and proper handling of incoming notifications. For any device-based notification (such as mobile or desktop) applications, you can use a backend processing layer that forwards a simplified notification to a mobile push service, such as:
- Apple Push Notification service (APNs) for iOS
- Firebase Cloud Messaging (FCM) for Android
For higher-volume or enterprise scenarios, Azure Event Hubs provides a more scalable and resilient pattern to ingest and process large numbers of notifications.
Moving away from streaming subscriptions also reduces the security and operational risks associated with maintaining persistent connections. This approach results in a more robust and cloud-aligned architecture.
Differences in event types
EWS provides more granular event types than Microsoft Graph. Consider this difference during migration.
Item creation and new email arrival
- EWS: NewMail (specific to Inbox) or Created (other folders).
- Microsoft Graph: Created (Unified for messages, contacts, and events).
Microsoft Graph doesn’t expose a dedicated NewMail event—new items are surfaced simply as created. This means a created event can represent either a newly delivered email or an item that has been copied or moved into a folder.
If your application relies on NewMail-specific behavior, you need to infer this distinction by using message properties such as receivedDateTime and createdDateTime to determine whether the message was delivered or just moved or copied.
✏️ Modifications and updates
- EWS: Modified
- Microsoft Graph: Updated
These operations are functionally identical.
🗑️ Deletions and lifecycle
- EWS: Deleted, Moved, Copied
- Microsoft Graph: Deleted
Microsoft Graph doesn’t expose explicit moved or copied event types. In scenarios where distinguishing between these actions is important, applications need to infer intent by correlating events across folders and using the immutableId.
For example, when a message is moved from the Inbox to a custom folder, Microsoft Graph emits a delete event in the Inbox and a create event in the destination folder. Because the immutableId remains the same, these two events can be correlated to identify the operation as a move.
In contrast, a copy operation results in a create event in the destination folder with a new immutableId, and no corresponding delete event in the source folder.
This represents a shift from EWS, where move and copy operations were explicitly surfaced. With Microsoft Graph, developers must adopt a more interpretive approach, using event patterns and identifiers to determine the underlying action.
Tips
When working with subscriptions, the clientState value is only returned when you retrieve a specific subscription by using a GET request. It isn’t included when you enumerate subscriptions. In this case, the clientState property is always null.
Throttling
EWS and Microsoft Graph use different throttling models, and subscriptions are one area where these differences are important. In Microsoft Graph, Exchange enforces a strict limit of four concurrent connections per mailbox. This limit applies across all active requests, including those triggered by subscription processing. If your application processes large items or handles a high volume of events, it can exceed this limit and throttling can occur.
A common pitfall is treating each notification as an independent unit of work and creating parallel requests to process it. Under load, this can result in exceeding the concurrent connection limit, increased latency, and repeated throttling, which in turn slows overall throughput rather than improving it.
To operate efficiently within these constraints, adopt a more controlled processing model. Queue incoming events and process them in a managed pipeline rather than in parallel bursts. Implement deduplication logic to coalesce closely spaced events — such as multiple create or update notifications for the same item — to avoid redundant work.
In addition, enforce client-side concurrency controls (for example, using a bounded worker pool or semaphore) to ensure that no more than four concurrent requests are made against a mailbox at any given time. To further improve resilience and throughput, incorporate retry logic with backoff, and prioritize lightweight operations (such as delta queries) over repeated full item retrievals.
Performance and throttling thresholds for webhook endpoints
Another key difference between Microsoft Graph webhooks and EWS push notifications is how performance and availability of the notification endpoint are enforced. Microsoft Graph actively monitors your webhook responsiveness and applies back-pressure when thresholds are exceeded.
A slow state is triggered when more than 10% of responses take longer than 10 seconds within a 10-minute window. When this occurs, Microsoft Graph delays all new notifications by approximately 10 seconds before delivery. For real-time notification scenarios, this introduces noticeable latency and can cause notifications to fall out of sync with user expectations.
A more severe drop state is triggered when more than 15% of responses exceed 10 seconds within the same 10-minute window. In this case, Microsoft Graph temporarily stops delivering new notifications to the endpoint for up to 10 minutes. Any notifications generated during this period aren’t replayed after the endpoint recovers, which can result in missed events.
Microsoft Graph webhooks impose stricter performance requirements on the listening endpoint than EWS push and streaming notifications. Applications must acknowledge receipt quickly and incorporate logic for resilience and recovery. To account for missed or delayed notifications, a reconciliation process using delta queries is a necessary to maintain data consistency.
Glen Scales is a Microsoft MVP and senior developer specializing in Exchange, Active Directory, Office 365, and Teams. You can follow his work on his eMail Development Substack.
0 comments
Be the first to start the discussion.