{"id":25816,"date":"2026-06-11T13:25:22","date_gmt":"2026-06-11T20:25:22","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/?p=25816"},"modified":"2026-06-11T13:25:22","modified_gmt":"2026-06-11T20:25:22","slug":"migrating-ews-notifications-to-microsoft-graph","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/migrating-ews-notifications-to-microsoft-graph\/","title":{"rendered":"Migrating EWS notifications to Microsoft Graph"},"content":{"rendered":"<p><span data-contrast=\"auto\">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. <\/span><\/p>\n<p><span data-contrast=\"auto\">You can migrate your applications by integrating modern Microsoft Graph capabilities like <strong>r<\/strong><\/span><b><span data-contrast=\"auto\">ich notifications<\/span><\/b><span data-contrast=\"auto\"> for reduced latency and <strong>i<\/strong><\/span><b><span data-contrast=\"auto\">mmutable IDs<\/span><\/b><span data-contrast=\"auto\"> 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 <strong>d<\/strong><\/span><strong>elta queries<\/strong><span data-contrast=\"auto\"> for reconciliation, while navigating the strict concurrency and availability thresholds of a cloud-native environment.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"auto\">EWS notifications<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">An application can use three types of EWS notifications, each with different tradeoffs in terms of latency, scalability, and connection management:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"%1.\" data-font=\"\" data-listid=\"3\" data-list-defn-props=\"{&quot;335552541&quot;:0,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[65533,0],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;%1.&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"1\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Push notifications<\/span><\/b> &#8211; <span data-contrast=\"auto\">Exchange sends an HTTP\/HTTPS request to a listener endpoint hosted by your application whenever an event occurs.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"%1.\" data-font=\"\" data-listid=\"3\" data-list-defn-props=\"{&quot;335552541&quot;:0,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[65533,0],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;%1.&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"2\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Pull notifications<\/span><\/b> &#8211; <span data-contrast=\"auto\">The application periodically calls Exchange to check for new events.<\/span><span data-ccp-props=\"{}\">\u00a0<\/span><\/li>\n<\/ul>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"%1.\" data-font=\"\" data-listid=\"3\" data-list-defn-props=\"{&quot;335552541&quot;:0,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[65533,0],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;%1.&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"3\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Streaming notifications<\/span><\/b> &#8211; <span data-contrast=\"auto\">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.<\/span><span data-ccp-props=\"{&quot;335559739&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<h2><b><span data-contrast=\"auto\">Microsoft Graph change notifications<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">Microsoft Graph only has one type of change notification, which is delivered via webhooks\u2014HTTP 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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"auto\">Microsoft Graph rich notifications<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">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).<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<h2 aria-level=\"3\"><b><span data-contrast=\"none\">Pull notifications and change tracking in Microsoft Graph<\/span><\/b><span data-ccp-props=\"{&quot;134245418&quot;:false,&quot;134245529&quot;:false,&quot;335559738&quot;:280,&quot;335559739&quot;:80}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">In EWS, notifications relied on the <\/span><b><span data-contrast=\"auto\">GetEvents<\/span><\/b><span data-contrast=\"auto\"> 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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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\u00a0<\/span><b><span data-contrast=\"auto\">delta token<\/span><\/b><span data-contrast=\"auto\"> returned by Microsoft Graph and use it in subsequent requests to continue where they left off.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Microsoft Graph supports delta queries for the following resource types:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"7\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"1\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Folders:<\/span><\/b><span data-contrast=\"auto\">\u00a0Individual Mail, Contact, and Calendar folders.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"7\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"2\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Item collections:<\/span><\/b><span data-contrast=\"auto\"> Messages, contacts, events, and to do (tasks).<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<p><span data-contrast=\"auto\">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).<\/span><\/p>\n<h2><b><span data-contrast=\"auto\">Immutable IDs<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">Microsoft Graph introduces i<\/span><b><span data-contrast=\"auto\">mmutable IDs<\/span><\/b><span data-contrast=\"auto\"> for mailbox items, a capability that has no direct equivalent in EWS. An immutable ID is a stable, unique identifier for an item \u2014 such as a message, contact, or event \u2014 that remains constant for the lifetime of the item within a mailbox.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Unlike EWS and Microsoft Graph <strong>itemId<\/strong> 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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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 \u2014 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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Note that when items move across mailbox boundaries \u2014 such as between mailboxes or from a mailbox to an archive store \u2014 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.<\/span><\/p>\n<h2><b><span data-contrast=\"auto\">Differences in subscriptions between EWS and Microsoft Graph<\/span><\/b><span data-ccp-props=\"{&quot;335559737&quot;:600,&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">In EWS, subscriptions are typically created against a specific mailbox folder or across all folders within a mailbox.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">In Microsoft Graph, change notification subscriptions can be created on specific folder types (such as Inbox or Calendar) or on resource collections such as `<\/span>messages`<span data-contrast=\"auto\">, `<\/span>contacts`<span data-contrast=\"auto\">, or `<\/span>events`<span data-contrast=\"auto\">. However, this model is more constrained than EWS. It supports a reduced set of folder types and doesn&#8217;t provide the same level of granularity across all mailbox folders.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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 <em>p<\/em><\/span><i><span data-contrast=\"auto\">rocessed<\/span><\/i><span data-contrast=\"auto\"> folder. With <\/span>Microsoft Graph<span data-contrast=\"auto\">, the application instead subscribes to the <code>\/messages<\/code> collection to receive notifications for the entire mailbox.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">To track moves, the application monitors created and deleted events and\u00a0checks\u00a0the <strong>parentFolderId<\/strong> to determine the item&#8217;s location. Because standard item IDs change when a message moves between folders, the application uses immutable IDs to correlate the item\u2019s 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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"auto\">Custom folders gap<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">Microsoft Graph subscriptions don&#8217;t work for all mailbox folders. Custom folders or folders that are typically associated with legacy client features aren&#8217;t accessible through the Microsoft Graph <code>messages<\/code>, <code>contacts<\/code>, <code>events<\/code>, or <code>to do<\/code> endpoints. For custom folders, you can either find an alternative solution outside of Exchange or migrate content to a supported endpoint such as <code>messages<\/code>, where webhooks are available.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"auto\">Streaming subscription gap<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">Because Microsoft Graph doesn&#8217;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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"\u25cf\" data-font=\"\" data-listid=\"4\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u25cf&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"1\" data-aria-level=\"1\"><span data-contrast=\"auto\">Apple Push Notification service (APNs) for iOS<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"\u25cf\" data-font=\"\" data-listid=\"4\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u25cf&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"2\" data-aria-level=\"1\"><span data-contrast=\"auto\">Firebase Cloud Messaging (FCM) for Android<\/span><span data-ccp-props=\"{&quot;335559739&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<p><span data-contrast=\"auto\">For higher-volume or enterprise scenarios, Azure Event Hubs provides a more scalable and resilient pattern to ingest and process large numbers of notifications.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"auto\">Differences in event types<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">EWS provides more granular event types than Microsoft Graph. Consider this difference during migration.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<h3 aria-level=\"4\"><b><span data-contrast=\"none\">Item creation and new email arrival<\/span><\/b><span data-ccp-props=\"{&quot;134245418&quot;:false,&quot;134245529&quot;:false,&quot;335559738&quot;:240,&quot;335559739&quot;:40}\">\u00a0<\/span><\/h3>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"\u25cf\" data-font=\"\" data-listid=\"6\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u25cf&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"1\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">EWS:<\/span><\/b><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"none\">NewMail<\/span><span data-contrast=\"auto\">\u00a0(specific to Inbox) or\u00a0<\/span><span data-contrast=\"none\">Created<\/span><span data-contrast=\"auto\">\u00a0(other folders).<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"\u25cf\" data-font=\"\" data-listid=\"6\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u25cf&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"2\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Microsoft Graph:<\/span><\/b><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"none\">Created<\/span><span data-contrast=\"auto\">\u00a0(Unified for messages, contacts, and events).<\/span><span data-ccp-props=\"{&quot;335559739&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<p><span data-contrast=\"auto\">Microsoft Graph doesn&#8217;t expose a dedicated <\/span><strong>NewMail<\/strong><span data-contrast=\"auto\"> event\u2014new items are surfaced simply as\u00a0<\/span><i><span data-contrast=\"auto\">created<\/span><\/i><span data-contrast=\"auto\">. This means a <\/span><i><span data-contrast=\"auto\">created<\/span><\/i><span data-contrast=\"auto\">\u00a0event can represent either a newly delivered email or an item that has been copied or moved into a folder.<\/span><span data-ccp-props=\"{&quot;335559685&quot;:600,&quot;335559737&quot;:600,&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">If your application relies on\u00a0<\/span><strong>NewMail<\/strong><span data-contrast=\"auto\">-specific behavior, you need to infer this distinction by using message properties such as <\/span><strong>receivedDateTime<\/strong><span data-contrast=\"auto\">\u00a0and\u00a0<\/span><strong>createdDateTime<\/strong><span data-contrast=\"auto\"> to determine whether the message was delivered\u00a0or just moved or copied.<\/span><span data-ccp-props=\"{&quot;335559685&quot;:600,&quot;335559737&quot;:600,&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p aria-level=\"3\"><b><span data-contrast=\"none\">\u270f\ufe0f Modifications and updates<\/span><\/b><span data-ccp-props=\"{&quot;134245418&quot;:false,&quot;134245529&quot;:false,&quot;335559738&quot;:280,&quot;335559739&quot;:80}\">\u00a0<\/span><\/p>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"\u25cf\" data-font=\"\" data-listid=\"1\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u25cf&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"1\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">EWS:<\/span><\/b><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"none\">Modified<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"\u25cf\" data-font=\"\" data-listid=\"1\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u25cf&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"2\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Microsoft Graph:<\/span><\/b><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"none\">Updated<\/span><span data-ccp-props=\"{&quot;335559739&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<p><span data-contrast=\"auto\">These operations are functionally identical.<\/span><span data-ccp-props=\"{&quot;335559685&quot;:600,&quot;335559737&quot;:600,&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p aria-level=\"3\"><b><span data-contrast=\"none\">\ud83d\uddd1\ufe0f Deletions and lifecycle<\/span><\/b><span data-ccp-props=\"{&quot;134245418&quot;:false,&quot;134245529&quot;:false,&quot;335559738&quot;:280,&quot;335559739&quot;:80}\">\u00a0<\/span><\/p>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"\u25cf\" data-font=\"\" data-listid=\"5\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u25cf&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"1\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">EWS:<\/span><\/b><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"none\">Deleted<\/span><span data-contrast=\"auto\">,\u00a0<\/span><span data-contrast=\"none\">Moved<\/span><span data-contrast=\"auto\">,\u00a0<\/span><span data-contrast=\"none\">Copied<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<ul>\n<li aria-setsize=\"-1\" data-leveltext=\"\u25cf\" data-font=\"\" data-listid=\"5\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\u25cf&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" data-aria-posinset=\"2\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Microsoft Graph:<\/span><\/b><span data-contrast=\"auto\">\u00a0<\/span><span data-contrast=\"none\">Deleted<\/span><span data-ccp-props=\"{&quot;335559739&quot;:240}\">\u00a0<\/span><\/li>\n<\/ul>\n<p><span data-contrast=\"auto\">Microsoft Graph doesn&#8217;t expose explicit <strong>m<\/strong><\/span><b><span data-contrast=\"auto\">oved<\/span><\/b><span data-contrast=\"auto\"> or <strong>c<\/strong><\/span><b><span data-contrast=\"auto\">opied<\/span><\/b><span data-contrast=\"auto\"> event types. In scenarios where distinguishing between these actions is important, applications need to infer intent by correlating events across folders and using the <\/span><b><span data-contrast=\"auto\">immutableId<\/span><\/b><span data-contrast=\"auto\">.<\/span><span data-ccp-props=\"{&quot;335559685&quot;:600,&quot;335559737&quot;:600,&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">For example, when a message is moved from the Inbox to a custom folder, Microsoft Graph emits a <\/span><b><span data-contrast=\"auto\">delete<\/span><\/b><span data-contrast=\"auto\">\u00a0event in the Inbox and\u00a0a\u00a0<\/span><b><span data-contrast=\"auto\">create<\/span><\/b><span data-contrast=\"auto\"> event in the destination folder. Because the\u00a0<\/span><b><span data-contrast=\"auto\">immutableId<\/span><\/b><span data-contrast=\"auto\">\u00a0remains the same, these two events can be correlated to identify the operation as a move.<\/span><span data-ccp-props=\"{&quot;335559685&quot;:600,&quot;335559737&quot;:600,&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">In contrast, a copy operation results in a\u00a0<\/span><b><span data-contrast=\"auto\">create<\/span><\/b><span data-contrast=\"auto\"> event in the destination folder with a new\u00a0<\/span><b><span data-contrast=\"auto\">immutableId<\/span><\/b><span data-contrast=\"auto\">, and no corresponding delete event in the source folder.<\/span><span data-ccp-props=\"{&quot;335559685&quot;:600,&quot;335559737&quot;:600,&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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.<\/span><span data-ccp-props=\"{&quot;335559685&quot;:600,&quot;335559737&quot;:600,&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"auto\">Tips<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">When working with subscriptions, the\u00a0<\/span><b><span data-contrast=\"auto\">clientState<\/span><\/b><span data-contrast=\"auto\"> value is only returned when you retrieve a specific subscription by using a <\/span><b><span data-contrast=\"auto\">GET<\/span><\/b><span data-contrast=\"auto\"> request. It isn&#8217;t included when you enumerate subscriptions. In this case, the <\/span><b><span data-contrast=\"auto\">clientState<\/span><\/b><span data-contrast=\"auto\"> property is always null.<\/span><\/p>\n<h2><b><span data-contrast=\"auto\">Throttling<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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 \u2014 such as multiple create or update notifications for the same item \u2014 to avoid redundant work.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<h2><b><span data-contrast=\"auto\">Performance and throttling thresholds for webhook endpoints<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/h2>\n<p><span data-contrast=\"auto\">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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">A\u00a0<\/span><b><span data-contrast=\"auto\">slow state<\/span><\/b><span data-contrast=\"auto\">\u00a0is 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.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">A more severe\u00a0<\/span><b><span data-contrast=\"auto\">drop state<\/span><\/b><span data-contrast=\"auto\"> 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&#8217;t replayed after the endpoint recovers, which can result in missed events.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">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\u00a0<\/span><b><span data-contrast=\"auto\">delta queries<\/span><\/b><span data-contrast=\"auto\"> is a necessary to maintain data consistency.<\/span><span data-ccp-props=\"{&quot;335559738&quot;:240,&quot;335559739&quot;:240}\">\u00a0<\/span><\/p>\n<p class=\"elementtoproof\"><b>Glen Scales<\/b><span style=\"font-family: 'Arial',sans-serif;\">\u202f<\/span>is a Microsoft MVP and senior developer specializing in Exchange, Active Directory, Office 365, and Teams. You can follow his work on his <a href=\"https:\/\/glenscales.substack.com\/\">eMail Development Substack<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Migrating from the Exchange Web Services (EWS) notification framework, which supports push, pull, and streaming notification types \u2014 to the Microsoft Graph subscription model represents a fundamental transition toward a unified, stateless, and event-driven framework.<\/p>\n","protected":false},"author":69077,"featured_media":6153,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,3],"tags":[],"class_list":["post-25816","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microsoft-365-developer","category-microsoft-graph"],"acf":[],"blog_post_summary":"<p>Migrating from the Exchange Web Services (EWS) notification framework, which supports push, pull, and streaming notification types \u2014 to the Microsoft Graph subscription model represents a fundamental transition toward a unified, stateless, and event-driven framework.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/25816","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/users\/69077"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/comments?post=25816"}],"version-history":[{"count":2,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/25816\/revisions"}],"predecessor-version":[{"id":25820,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/25816\/revisions\/25820"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media\/6153"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media?parent=25816"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/categories?post=25816"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/tags?post=25816"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}