Skip to content

Commit cc36616

Browse files
committed
Update the docs
1 parent 12e177b commit cc36616

52 files changed

Lines changed: 1302 additions & 15 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/latest/_modules/O365/subscriptions.html

Lines changed: 410 additions & 0 deletions
Large diffs are not rendered by default.

docs/latest/_modules/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ <h1>All modules for which code is available</h1>
8686
<li><a href="O365/message.html">O365.message</a></li>
8787
<li><a href="O365/planner.html">O365.planner</a></li>
8888
<li><a href="O365/sharepoint.html">O365.sharepoint</a></li>
89+
<li><a href="O365/subscriptions.html">O365.subscriptions</a></li>
8990
<li><a href="O365/tasks.html">O365.tasks</a></li>
9091
<li><a href="O365/teams.html">O365.teams</a></li>
9192
<li><a href="O365/utils/attachment.html">O365.utils.attachment</a></li>

docs/latest/_sources/api.rst.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ O365 API
1919
api/onedrive
2020
api/planner
2121
api/sharepoint
22+
api/subscriptions
2223
api/tasks
2324
api/teams
2425
api/utils
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Subscriptions
2+
-------------
3+
4+
.. include:: global.rst
5+
6+
.. automodule:: O365.subscriptions
7+
:members:
8+
:undoc-members:
9+
:show-inheritance:
10+
:member-order: groupwise

docs/latest/_sources/usage.rst.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Detailed Usage
1717
usage/onedrive
1818
usage/planner
1919
usage/sharepoint
20+
usage/subscriptions
2021
usage/tasks
2122
usage/teams
2223
usage/utils
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
Subscriptions
2+
=============
3+
4+
Subscriptions provides the ability to create and manage webhook subscriptions for change notifications against Microsoft Graph. Read here for more details on MS Graph subscriptions
5+
6+
- https://learn.microsoft.com/en-us/graph/api/resources/subscription?view=graph-rest-1.0
7+
- https://learn.microsoft.com/en-us/graph/change-notifications-delivery-webhooks?tabs=http
8+
9+
Create a Subscription
10+
^^^^^^^^^^^^^^^^^^^^^
11+
12+
Assuming a web host (example uses `flask`) and an authenticated account, create a subscription to be notified about new emails.
13+
14+
.. code-block:: python
15+
16+
from flask import Flask, abort, jsonify, request
17+
18+
RESOURCE = "/me/mailFolders('inbox')/messages"
19+
DEFAULT_EXPIRATION_MINUTES = 10069 # Maximum expiration is 10,070 in the future for Outlook message.
20+
21+
app = Flask(__name__)
22+
23+
@app.get("/subscriptions")
24+
def create_subscription():
25+
"""Create a subscription."""
26+
notification_url = request.args.get("notification_url")
27+
if not notification_url:
28+
abort(400, description="notification_url is required")
29+
30+
expiration_minutes = int(request.args.get("expiration_minutes", DEFAULT_EXPIRATION_MINUTES))
31+
client_state = request.args.get("client_state")
32+
resource = request.args.get("resource", RESOURCE)
33+
34+
subscription = account.subscriptions().create_subscription(
35+
notification_url=notification_url,
36+
resource=resource,
37+
change_type="created",
38+
expiration_minutes=expiration_minutes,
39+
client_state=client_state,
40+
)
41+
return jsonify(subscription), 201
42+
43+
@app.post("/webhook")
44+
def webhook_handler():
45+
"""Handle Microsoft Graph webhook calls.
46+
47+
- During subscription validation, Graph sends POST with ?validationToken=... .
48+
We must echo the token as plain text within 10 seconds.
49+
- For change notifications, Graph posts JSON; we just log/ack.
50+
"""
51+
validation_token = request.args.get("validationToken")
52+
if validation_token:
53+
# Echo back token exactly as plain text with HTTP 200.
54+
return validation_token, 200, {"Content-Type": "text/plain"}
55+
56+
# Change notifications: inspect or log as needed.
57+
payload = request.get_json(silent=True) or {}
58+
print("Received notification payload:", payload)
59+
return ("", 202)
60+
61+
Use this url:
62+
63+
``https://<your-tunnel-host>/subscriptions?notification_url=https%3A%2F%2F<your-tunnel-host>%2Fwebhook&client_state=abc123``
64+
65+
HTTP status 201 and the following should be returned:
66+
67+
.. code-block:: JSON
68+
69+
{
70+
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
71+
"applicationId": "12345678-bad9-4c34-94d6-f9a1388522f8",
72+
"changeType": "created",
73+
"clientState": "abc123",
74+
"creatorId": "12345678-a5c7-46da-8107-b25090a1ed66",
75+
"encryptionCertificate": null,
76+
"encryptionCertificateId": null,
77+
"expirationDateTime": "2026-01-07T11:20:42.305776Z",
78+
"id": "548355f8-c2c0-47ae-aac7-3ad02b2dfdb1",
79+
"includeResourceData": null,
80+
"latestSupportedTlsVersion": "v1_2",
81+
"lifecycleNotificationUrl": null,
82+
"notificationQueryOptions": null,
83+
"notificationUrl": "https://<your-tunnel-host>/webhook",
84+
"notificationUrlAppId": null,
85+
"resource": "/me/mailFolders('inbox')/messages"
86+
}
87+
88+
List Subscriptions
89+
^^^^^^^^^^^^^^^^^^
90+
91+
.. code-block:: python
92+
93+
@app.get("/subscriptions/list")
94+
def list_subscriptions():
95+
"""List all subscriptions."""
96+
limit = int(request.args.get("limit"))
97+
subscriptions = account.subscriptions().list_subscriptions(limit=limit)
98+
return jsonify(list(subscriptions)), 200
99+
100+
Use this url:
101+
102+
``https://<your-tunnel-host>/subscriptions/list``
103+
104+
HTTP status 200 and the following should be returned:
105+
106+
.. code-block:: JSON
107+
108+
[
109+
{
110+
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
111+
"applicationId": "12345678-bad9-4c34-94d6-f9a1388522f8",
112+
"changeType": "created",
113+
"clientState": "abc123",
114+
"creatorId": "12345678-a5c7-46da-8107-b25090a1ed66",
115+
"encryptionCertificate": null,
116+
"encryptionCertificateId": null,
117+
"expirationDateTime": "2026-01-07T11:20:42.305776Z",
118+
"id": "548355f8-c2c0-47ae-aac7-3ad02b2dfdb1",
119+
"includeResourceData": null,
120+
"latestSupportedTlsVersion": "v1_2",
121+
"lifecycleNotificationUrl": null,
122+
"notificationQueryOptions": null,
123+
"notificationUrl": "https://<your-tunnel-host>/webhook",
124+
"notificationUrlAppId": null,
125+
"resource": "/me/mailFolders('inbox')/messages"
126+
}
127+
]
128+
129+
Renew a Subscription
130+
^^^^^^^^^^^^^^^^^^^^
131+
132+
.. code-block:: python
133+
134+
@app.get("/subscriptions/<subscription_id>/renew")
135+
def renew_subscription(subscription_id: str):
136+
"""Renew a subscription."""
137+
expiration_minutes = int(request.args.get("expiration_minutes", DEFAULT_EXPIRATION_MINUTES))
138+
updated = account.subscriptions().renew_subscription(
139+
subscription_id,
140+
expiration_minutes=expiration_minutes,
141+
)
142+
return jsonify(updated), 200
143+
144+
Use this url:
145+
146+
``http://<your-tunnel-host>/subscriptions/548355f8-c2c0-47ae-aac7-3ad02b2dfdb1/renew?expiration_minutes=10069``
147+
148+
HTTP status 200 and the following should be returned:
149+
150+
.. code-block:: JSON
151+
152+
{
153+
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
154+
"applicationId": "12345678-bad9-4c34-94d6-f9a1388522f8",
155+
"changeType": "created",
156+
"clientState": "abc123",
157+
"creatorId": "12345678-a5c7-46da-8107-b25090a1ed66",
158+
"encryptionCertificate": null,
159+
"encryptionCertificateId": null,
160+
"expirationDateTime": "2026-01-07T11:35:40.301594Z",
161+
"id": "548355f8-c2c0-47ae-aac7-3ad02b2dfdb1",
162+
"includeResourceData": null,
163+
"latestSupportedTlsVersion": "v1_2",
164+
"lifecycleNotificationUrl": null,
165+
"notificationQueryOptions": null,
166+
"notificationUrl": "https://<your-tunnel-host>/webhook",
167+
"notificationUrlAppId": null,
168+
"resource": "/me/mailFolders('inbox')/messages"
169+
}
170+
171+
Delete a Subscription
172+
^^^^^^^^^^^^^^^^^^^^^
173+
174+
.. code-block:: python
175+
176+
@app.get("/subscriptions/<subscription_id>/delete")
177+
def delete_subscription(subscription_id: str):
178+
"""Delete a subscription."""
179+
deleted = account.subscriptions().delete_subscription(subscription_id)
180+
if not deleted:
181+
abort(404, description="Subscription not found")
182+
return ("", 204)
183+
184+
Use this url:
185+
186+
``http://<your-tunnel-host>/subscriptions/548355f8-c2c0-47ae-aac7-3ad02b2dfdb1/delete``
187+
188+
HTTP status 204 should be returned.
189+
190+
Webhook
191+
^^^^^^^
192+
193+
With a subscription as described above and an email sent to the inbox, a webhook will be received as below:
194+
195+
.. code-block:: python
196+
197+
{
198+
'value': [
199+
{
200+
'subscriptionId': '548355f8-c2c0-47ae-aac7-3ad02b2dfdb12',
201+
'subscriptionExpirationDateTime': '2026-01-07T11:35:40.301594+00:00',
202+
'changeType': 'created',
203+
'resource': 'Users/12345678-a5c7-46da-8107-b25090a1ed66/Messages/<long_guid>=',
204+
'resourceData': {
205+
'@odata.type': '#Microsoft.Graph.Message',
206+
'@odata.id': 'Users/12345678-a5c7-46da-8107-b25090a1ed66/Messages/<long_guid>=',
207+
'@odata.etag': 'W/"CQAAABYACCCoiRErLbiNRJDCFyMjq4khBBnH4N7A"',
208+
'id': '<long_guid>='
209+
},
210+
'clientState': 'abc123',
211+
'tenantId': '12345678-abcd-1234-abcd-1234567890ab'
212+
}
213+
]
214+
}
215+
216+
The client state should be validated for accuracy and if correct, the message can be acted upon as approriate for the type of subscription.
217+
218+
An example application can be found in the examples directory here - https://github.com/O365/python-o365/blob/master/examples/subscriptions_example.py

docs/latest/api.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
<li class="toctree-l2"><a class="reference internal" href="api/onedrive.html">One Drive</a></li>
6464
<li class="toctree-l2"><a class="reference internal" href="api/planner.html">Planner</a></li>
6565
<li class="toctree-l2"><a class="reference internal" href="api/sharepoint.html">Sharepoint</a></li>
66+
<li class="toctree-l2"><a class="reference internal" href="api/subscriptions.html">Subscriptions</a></li>
6667
<li class="toctree-l2"><a class="reference internal" href="api/tasks.html">Tasks</a></li>
6768
<li class="toctree-l2"><a class="reference internal" href="api/teams.html">Teams</a></li>
6869
<li class="toctree-l2"><a class="reference internal" href="api/utils.html">Utils</a></li>
@@ -223,6 +224,10 @@ <h1>O365 API<a class="headerlink" href="#o365-api" title="Link to this heading">
223224
<li class="toctree-l2"><a class="reference internal" href="api/sharepoint.html#O365.sharepoint.Site"><code class="docutils literal notranslate"><span class="pre">Site</span></code></a></li>
224225
</ul>
225226
</li>
227+
<li class="toctree-l1"><a class="reference internal" href="api/subscriptions.html">Subscriptions</a><ul>
228+
<li class="toctree-l2"><a class="reference internal" href="api/subscriptions.html#O365.subscriptions.Subscriptions"><code class="docutils literal notranslate"><span class="pre">Subscriptions</span></code></a></li>
229+
</ul>
230+
</li>
226231
<li class="toctree-l1"><a class="reference internal" href="api/tasks.html">Tasks</a><ul>
227232
<li class="toctree-l2"><a class="reference internal" href="api/tasks.html#O365.tasks.ChecklistItem"><code class="docutils literal notranslate"><span class="pre">ChecklistItem</span></code></a></li>
228233
<li class="toctree-l2"><a class="reference internal" href="api/tasks.html#O365.tasks.Folder"><code class="docutils literal notranslate"><span class="pre">Folder</span></code></a></li>

docs/latest/api/account.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
<li class="toctree-l2"><a class="reference internal" href="onedrive.html">One Drive</a></li>
9292
<li class="toctree-l2"><a class="reference internal" href="planner.html">Planner</a></li>
9393
<li class="toctree-l2"><a class="reference internal" href="sharepoint.html">Sharepoint</a></li>
94+
<li class="toctree-l2"><a class="reference internal" href="subscriptions.html">Subscriptions</a></li>
9495
<li class="toctree-l2"><a class="reference internal" href="tasks.html">Tasks</a></li>
9596
<li class="toctree-l2"><a class="reference internal" href="teams.html">Teams</a></li>
9697
<li class="toctree-l2"><a class="reference internal" href="utils.html">Utils</a></li>

docs/latest/api/address_book.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
<li class="toctree-l2"><a class="reference internal" href="onedrive.html">One Drive</a></li>
126126
<li class="toctree-l2"><a class="reference internal" href="planner.html">Planner</a></li>
127127
<li class="toctree-l2"><a class="reference internal" href="sharepoint.html">Sharepoint</a></li>
128+
<li class="toctree-l2"><a class="reference internal" href="subscriptions.html">Subscriptions</a></li>
128129
<li class="toctree-l2"><a class="reference internal" href="tasks.html">Tasks</a></li>
129130
<li class="toctree-l2"><a class="reference internal" href="teams.html">Teams</a></li>
130131
<li class="toctree-l2"><a class="reference internal" href="utils.html">Utils</a></li>

docs/latest/api/calendar.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@
250250
<li class="toctree-l2"><a class="reference internal" href="onedrive.html">One Drive</a></li>
251251
<li class="toctree-l2"><a class="reference internal" href="planner.html">Planner</a></li>
252252
<li class="toctree-l2"><a class="reference internal" href="sharepoint.html">Sharepoint</a></li>
253+
<li class="toctree-l2"><a class="reference internal" href="subscriptions.html">Subscriptions</a></li>
253254
<li class="toctree-l2"><a class="reference internal" href="tasks.html">Tasks</a></li>
254255
<li class="toctree-l2"><a class="reference internal" href="teams.html">Teams</a></li>
255256
<li class="toctree-l2"><a class="reference internal" href="utils.html">Utils</a></li>

0 commit comments

Comments
 (0)