Change notifications for Outlook resources in Microsoft Graph
The Microsoft Graph API lets you subscribe to changes to a resource—including creation, update, or deletion of the resource—and receive notifications via webhooks. A subscription specifies the desired types of changes to monitor for a specific resource, and includes a URL for an endpoint to receive notifications of those changes.
Setting up a subscription reduces the overhead of otherwise having to query and compare resources to deduce any changes. You can optionally specify in the subscription request to encrypt and include as part of a notification the resource data that has changed, saving a separate subsequent API call to get the resource payload.
There is a maximum limit of 1000 active subscriptions for Outlook resources per mailbox for all applications. You can subscribe to changes in contacts, events, or messages in the mailbox.
Subscribe to changes in contacts, calendar, or mail
To subscribe to change notifications of Outlook resources, first create a subscription.
The following Outlook resources support subscriptions with or without resource data in the change notification payload.
Create a subscription
To create a subscription, specify the Outlook resource and the type of changes (creation, update, or deletion) for which you want to receive notifications. See an example.
Request permissions
Creating and managing (getting, updating, and deleting) a subscription requires a read scope to the resource. For example, to get change notifications on messages, your app needs the Mail.Read permission. Outlook change notifications support delegated and application permission scopes. Note the following limitations:
Delegated permission supports subscribing to items in folders in only the signed-in user's mailbox. For example, you can't use the delegated permission Calendars.Read to subscribe to events in another user’s mailbox.
To subscribe to change notifications of Outlook contacts, events, or messages in shared or delegated folders:
- Use the corresponding application permission to subscribe to changes of items in a folder or mailbox of any user in the tenant.
- Don't use the Outlook sharing permissions (Contacts.Read.Shared, Calendars.Read.Shared, Mail.Read.Shared, and their read/write counterparts), as they do not support subscribing to change notifications on items in shared or delegated folders.
Depending on the resource, use the least privileged permission specified in the following table to call this API.
Resource | Supported Resource Paths | Delegated (work or school account) | Delegated (personal Microsoft account) | Application |
---|---|---|---|---|
contact | Changes to all personal contacts in a user's mailbox: /me/contacts /users/{id}/contacts Changes to contacts in a user's contactFolder: /users/{id}/contactFolders/{id}/contacts |
Contacts.Read | Contacts.Read | Contacts.Read |
event | Changes to all events in a user's mailbox: /me/events /users/{id}/events |
Calendars.Read | Calendars.Read | Calendars.Read |
message | Changes to all messages in a user's mailbox: /me/messages /users/{id}/messages Changes to messages in a user's mailFolder: /users/{id}/mailFolders/{id}/messages |
Mail.ReadBasic, Mail.Read | Mail.ReadBasic, Mail.Read | Mail.ReadBasic, Mail.Read |
Include resource data in notification payload
To have resource data included in a change notification, you must specify the following properties, in addition to those you normally include when creating a subscription:
includeResourceData: Set this property to
true
to explicitly request resource data.resource: This property specifies the resource URL. Make sure to use the
$select
query parameter to explicitly specify the Outlook resource properties to include in the notification payload.Note
Do not include in the URL
$top
,$skip
,$orderby
,$select=Body,UniqueBody
, and$expand
other than singleValueExtendedProperties or multiValueExtendedProperties.encryptionCertificate: This property contains only the public key that Microsoft Graph uses to encrypt resource data. Keep the corresponding private key to decrypt the content.
encryptionCertificateId: This property is your own identifier for the certificate. Use this ID to match in each change notification which certificate to use for decryption.
See an example for subscribing to change notifications with resource data for the message resource.
Refine the conditions for a notification
You can further refine the conditions for a notification by using the $filter
query parameter. See an example.
One common application of $filter
is to get notified upon a change in a specific resource property. For example, you can use $filter
to subscribe to unread messages in a folder (the isRead property is false
), and include all the change types:
- A message added to or marked unread in the folder would trigger a
Created
notification. - Reading a message or marking it as read in the folder would trigger a
Deleted
notification. - A change to any property, other than isRead, of a message resource in the folder would trigger an
Updated
notification.
If you don't use a $filter
when creating the subscription:
- Adding a message to the folder would result in a
Created
notification. - Reading a message in the folder, marking the message as read, or changing any other property of a message in that folder would result in an
Updated
notification. - Deleting the message would result in a
Delete
notification.
Subscribe to lifecycle notifications
The Outlook contact, event, and message resources also support subscribing to lifecycle notifications. Lifecycle notifications are needed in case your app gets their subscriptions removed or misses some change notifications. Apps should implement logic to detect and recover from the loss, and resume a continuous change notification flow. To learn more, see subscribing to lifecycle notifications.
Keep track of subscription lifetime
Make sure to extend a subscription before it expires. The maximum lifetime for a subscription without Outlook resource data can be found in the subscription lifetime table.
If you lose the permission granted earlier for a subscription and the subscription expires meanwhile, request permission again to create a new subscription.
Receive notification payloads
Depending on your subscription, notifications may include resource data. Subscriptions with resource data allow you to get the resource payload along with the notification, avoiding the overhead for a separate API call to get the changed resource data.
Receive notifications with resource data
The following is an example of the payload of a notification with resource data of a message resource. The resource and resourceData properties correspond to the message instance that triggered the notification. Use the encryptedContent property to decrypt the resource data.
{
"value": [
{
"subscriptionId": "dfd11b2f-8222-4189-9545-4205c95d6235",
"subscriptionExpirationDateTime": "2021-12-31T16:16:44.9907405+05:30",
"changeType": "created",
"resource": "Users('722effaf-0433-4272-9ac4-d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"encryptedContent": {
"data": "<<--EncryptedContent-->>",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"dataSignature": "Qw/9ubWeUYJPWWXvNiGgct2FkNG2MXTRm/BLUpJM66k=",
"encryptionCertificateId": "<<--IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"resourceData": {
"@odata.type": "#microsoft.graph.message",
"@odata.id": "Users('722effaf-0433-4272-9ac4-d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUR8n\"",
"id": "AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA="
}
}
]
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change notifications that include resource data.
The following is an example of a decrypted notification payload. The decrypted payload conforms to the Outlook message schema. The payload is similar to that returned by a GET message operation. However, the notification payload contains only those properties specified with a $select
parameter in the resource property of the subscription. Notification payloads for other Outlook resources like contact and event follow their respective schemas.
{
"[email protected]":"#DateTimeOffset",
"receivedDateTime":"2021-12-30T10:53:35Z",
"subject":"TEST MESSAGE FOR RICH NOTIFICATIONS",
"bodyPreview":"Hello,\r\n\r\nWhat\u2019s up?\r\n\r\nThanks\r\nMegan",
"[email protected]":"#microsoft.graph.importance",
"importance":"normal",
"from": {
"@odata.type":"#microsoft.graph.recipient",
"emailAddress": {
"@odata.type":"#microsoft.graph.emailAddress",
"name":"Megan Brown",
"address":"[email protected]"
}
}
}
Receive notifications without resource data
Notifications without resource data give you enough information to make GET calls to get the resource. Subscriptions for notifications without resource data don't require an encryption certificate, because the actual resource data is not sent over.
The next example shows the payload of a notification that corresponds to an Outlook message resource. It includes the resource and resourceData properties, which represent the resource that triggered the notification. Use the resource and @odata.id properties to make calls to Microsoft Graph to get the payload of the resource.
Note
GET calls always return the current state of the resource. If the resource is changed between the time the notification is sent and the time the resource is retrieved, the operation returns the state of the resource on retrieval.
"value": [
{
"subscriptionId": "c6126aa3-0ed8-412f-a988-71e6cee627c4",
"subscriptionExpirationDateTime": "2022-01-02T03:12:18.2257768+05:30",
"changeType": "created",
"resource": "Users/622eaaff-0683-4862-9de4-f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIxAAA=",
"resourceData": {
"@odata.type": "#Microsoft.Graph.Message",
"@odata.id": "Users/622eaaff-0683-4862-9de4-f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIAAA=",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUUXn\"",
"id": "AAMkAGUwNjQ4ZjIxAAA="
},
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}
]
Examples
Example 1: Create a subscription to get change notifications without resource data when the user receives a new message
The following example requests a notification for a message being created in the user's mailbox.
Request
POST https://graph.microsoft.com/v1.0/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl": "https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"expirationDateTime": "2021-07-07T21:42:18.2257768+00:00",
"clientState": "secretClientState"
}
Response
The following example shows the response.
Note: The response object shown here might be shortened for readability.
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
"id": "5522bd62-7c96-4530-85b0-00b916f6151a",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientState",
"notificationUrl": "https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T21:42:18.2257768Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null,
"notificationUrlAppId": null
}
Example 2: Create a subscription to get change notifications with resource data when the user receives a new message
The following example subscribes to notifications with resource data for a message being created in the user's mailbox. The properties of the message resource to be included in the notification payload are specified using the $select
query parameter.
Request
POST https://graph.microsoft.com/v1.0/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl": "https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?$select=Subject,bodyPreview,importance,receivedDateTime,from",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following example shows the response.
Note: The response object shown here might be shortened for readability.
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
"id": "178eec5f-cf3c-4e7e-8a9c-8640deb5b5c5",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?$select=Subject,bodyPreview,importance,receivedDateTime,from",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl": "https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
Example 3: Create a subscription to get change notifications with resource data for a message based on a condition
The following example subscribes to notifications with resource data for a message being created in the Drafts folder, containing one or more attachments, and of high importance.
Request
POST https://graph.microsoft.com/v1.0/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl": "https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "me/mailfolders('Drafts')/messages?$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance eq 'High'",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following example shows the response.
Note: The response object shown here might be shortened for readability.
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
"id": "239dbc5f-cf3c-4e7e-8c9c-3340abc5b5c5",
"resource": "me/mailfolders('Drafts')/messages?$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance eq 'High'",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl": "https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-20T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}