Skip to main content

office365-rest-python-client

A Python client library for Microsoft 365, the SharePoint REST API and Microsoft Graph.

Downloads PyPI PyPI pyversions License: MIT Sponsor

Python 3.8+ · typed models · fluent queries · deferred execution · 700+ runnable examples

  • Two clients, one library — ClientContext speaks the SharePoint REST API; GraphClient speaks Microsoft Graph.
  • Fluent and deferred — chain .select(), .filter(), .expand(), .top(), .order_by() and only hit the wire when you call execute_query().
  • Typed models — every entity is a real Python class (List, File, Team, Message, …), not a dictionary.
  • Copy-paste examples — a runnable script for every service and scenario under examples/.

New here? Pick a client in Choose your client, then jump straight to a runnable snippet in Examples by product.

Table of contents

Choose your client

The library ships two clients. Pick the one that matches the API you need.

ClientContext GraphClient
Talks to SharePoint REST API (/_api) Microsoft Graph (graph.microsoft.com)
Entry point ClientContext("https://contoso.sharepoint.com/sites/team") GraphClient(tenant="contoso.onmicrosoft.com")
Best for SharePoint lists, items, files, folders, search, permissions, site and tenant administration, taxonomy, webhooks Outlook, OneDrive, Teams, OneNote, Planner, To Do, Entra ID, Intune, Purview, Bookings, reports, security…
SharePoint Full fidelity Partial — prefer ClientContext for SharePoint-only work
Typed models List, ListItem, File, Folder, Web, Site, User … DriveItem, Team, Message, Event, User, Group, PlannerTask …
Auth certificate, interactive, device flow, cookies, NTLM (on-prem) client secret, certificate, interactive, device flow, ROPC
Examples examples/sharepoint/ examples/ by product
API reference SharePoint REST Microsoft Graph

Rule of thumb

  • SharePoint lists, files, site or tenant administration → ClientContext
  • Teams, Outlook, OneDrive, Entra ID, Intune, Purview, reports → GraphClient
  • OneDrive files work with either client; GraphClient is the modern, cross-service path.

Installation

pip install office365-rest-python-client

With uv:

uv add office365-rest-python-client

Directly from source:

pip install git+https://github.com/vgrem/office365-rest-python-client.git

Authentication

Modern flows authenticate through Microsoft Entra ID using MSAL. Both clients support delegated (user) and app-only (application) access.

ClientContext (SharePoint)

Flow Access Method
Certificate App-only with_client_certificate(tenant, client_id, thumbprint, cert_path=...)
Interactive Delegated (MFA) with_interactive(tenant, client_id)
Device code Delegated (MFA) with_device_flow(tenant, client_id)
Username / password Delegated with_username_and_password(tenant, client_id, username, password)
Custom token Either with_access_token(token_func)
Browser cookies Delegated with_cookies(cookie_source)
NTLM On-premises ClientContext(url, allow_ntlm=True).with_user_credentials(username, password)
ACS / SAML On-premises (legacy) legacy app-only · legacy SAML
from office365.sharepoint.client_context import ClientContext

ctx = ClientContext("https://contoso.sharepoint.com/sites/team").with_client_certificate(
    "contoso.onmicrosoft.com",
    client_id="00000000-0000-0000-0000-000000000000",
    thumbprint="AA11BB22CC33DD44EE55FF66AA77BB88CC99DD00",
    cert_path="./private.pem",
)

web = ctx.web.get().execute_query()
print(web.title)

Ready-made scripts: certificate · certificate (private key) · custom scopes · interactive · device flow · username/password · access token · cookies · NTLM

GraphClient (Microsoft Graph)

Flow Access Method
Client secret App-only with_client_secret(client_id, client_secret)
Certificate App-only with_certificate(client_id, thumbprint, private_key)
Interactive Delegated (MFA) with_token_interactive(client_id)
Device code Delegated (MFA) with_device_flow(client_id)
Username / password Delegated with_username_and_password(client_id, username, password)
Custom token Either GraphClient(token_callback, tenant=...)
from office365.graph_client import GraphClient

client = GraphClient(tenant="contoso.onmicrosoft.com").with_client_secret(
    client_id="00000000-0000-0000-0000-000000000000",
    client_secret="your-client-secret",
)

users = client.users.get().execute_query()
print(len(users), "users")

Ready-made scripts: client secret · certificate · interactive · device flow · username/password · custom token callback

Quick start

SharePoint list — read and write items

from office365.sharepoint.client_context import ClientContext

ctx = ClientContext("https://contoso.sharepoint.com/sites/team").with_client_certificate(
    "contoso.onmicrosoft.com", client_id, thumbprint, cert_path="./private.pem"
)

tasks = ctx.web.lists.get_by_title("Tasks")
item = tasks.add_item({"Title": "Write the release notes"}).execute_query()
print("Created item:", item.id)

for task in tasks.items.get_all().execute_query():
    print(task.properties["Title"])

Microsoft Graph — send an email

from office365.graph_client import GraphClient

client = GraphClient(tenant="contoso.onmicrosoft.com").with_client_secret(client_id, client_secret)

client.me.send_mail(
    subject="Hello from Graph API",
    body="This email was sent using the Microsoft Graph API.",
    to_recipients=["alex@contoso.onmicrosoft.com"],
).execute_query()

Examples by product

Every snippet below is lifted from a runnable script. Follow the More → link for the full example and its required permissions.

SharePoint (ClientContext)

# Lists and items
tasks = ctx.web.lists.get_by_title("Tasks")
item = tasks.add_item({"Title": "Ship it", "Status": "Active"}).execute_query()
tasks.items.get_all().execute_query()               # or .filter("Status eq 'Active'").get_all()

# Files and folders
folder = ctx.web.get_folder_by_server_relative_url("/sites/team/Shared Documents")
with open("report.pdf", "rb") as f:
    file = folder.files.upload(f).execute_query()

with open("report.pdf", "wb") as f:
    ctx.web.get_file_by_server_relative_path("/sites/team/Shared Documents/report.pdf").download(f).execute_query()

# Large file (chunked upload session)
with open("video.mp4", "rb") as f:
    folder.files.create_upload_session(f, 10 * 1024 * 1024).execute_query()
Area Examples
Lists and items lists · listitems · views
Files and folders files · folders
Sites and webs sites · webs · hubsites
Search search
Permissions and sharing permissions · sharing
Fields and content types fields · contenttypes
Pages and navigation pages · navigation
Taxonomy and profiles taxonomy · userprofile
Tenant administration tenant · groups · users
Webhooks, migration, advanced webhooks · migration · advanced

OneDrive

uploaded = client.me.drive.root.upload_file("report.xlsx").execute_query()

with open("report.xlsx", "wb") as f:
    client.me.drive.root.get_by_path("report.xlsx").download(f).execute_query()

More →

Teams

team = client.teams.create_and_wait("Contoso Project", "All project collaboration").execute_query()

channel = team.channels.add("Project Chat").execute_query()
channel.messages.add("Hello team!").execute_query()

More →

Outlook (mail and calendar)

from datetime import datetime, timedelta, timezone

# Send mail
client.me.send_mail(
    subject="Hello from Graph API",
    body="This email was sent using the Microsoft Graph API.",
    to_recipients=["alex@contoso.onmicrosoft.com"],
).execute_query()

# Create a calendar event
when = datetime.now(timezone.utc) + timedelta(days=1)
client.me.calendar.events.add(
    subject="Team Lunch",
    body="Let's grab lunch together.",
    start=when,
    end=when + timedelta(hours=1),
    attendees=["alex@contoso.onmicrosoft.com"],
).execute_query()

More →

Entra ID

from office365.directory.users.password_profile import PasswordProfile
from office365.directory.users.profile import UserProfile

profile = UserProfile(
    displayName="Alex Wilber",
    userPrincipalName="alex@contoso.onmicrosoft.com",
    mailNickname="alex",
    accountEnabled=True,
    passwordProfile=PasswordProfile(password="P@ssw0rd!", forceChangePasswordNextSignIn=True),
)
user = client.users.add(profile).execute_query()
print(user.display_name)

More →

Planner

group = client.groups.get_by_name("My Sample Team").get().execute_query()
plans = group.planner.plans.get().execute_query()
task = client.planner.tasks.add("Update client list", plans[0].id).execute_query()
print(task.title)

More →

To Do

for task_list in client.me.todo.lists.get().execute_query():
    print(task_list.display_name, len(task_list.tasks.get().execute_query()), "tasks")

More →

OneNote

with open("Sample.html", "rb") as page_html:
    page = client.me.onenote.pages.add(presentation_file=page_html).execute_query()
print(page.links.oneNoteWebUrl)

More →

More services — Admin, Reports, Defender, Intune, Purview, Bookings, Communications, Security, Insights, Backup Storage

Microsoft 365 admin

announcement = client.admin.service_announcement
health = announcement.health_overviews.get().execute_query()
issues = announcement.issues.get().execute_query()
messages = announcement.messages.get().execute_query()

More →

Usage reports

report = client.reports.get_email_activity_counts("D30").execute_query()
print(report.value)  # CSV payload

More →

Microsoft Defender

alerts = client.security.alerts_v2.top(20).get().execute_query()
for alert in alerts:
    print(alert)

More →

Microsoft Intune

devices = client.device_management.managed_devices.get().execute_query()
for device in devices:
    print(device.device_name, device.operating_system, device.compliance_state)

More →

Microsoft Purview

labels = client.security.data_security_and_governance.sensitivity_labels.get().execute_query()
for label in labels:
    print(label.display_name, label.id)

More →

Microsoft Bookings

businesses = client.solutions.booking_businesses.get().execute_query()
for business in businesses:
    print(business.display_name)

More →

Cloud communications

presence = client.users["alex@contoso.onmicrosoft.com"].presence.get().execute_query()
print(presence.availability, presence.activity)

More →

Security (threat intelligence)

host = client.security.threat_intelligence.hosts["contoso.com"].get().execute_query()
reputation = host.reputation.get().execute_query()
print(reputation.properties.get("score"))

More →

Insights

for item in client.me.insights.trending.get().execute_query():
    print(item.resource_reference)

More →

Backup Storage

backup = client.solutions.backup_restore
backup.get().execute_query()
print(backup.service_status.status)

More →

Common patterns

Deferred execution. Requests are queued and sent only when you call execute_query(). Chain the fluent methods first, then execute once.

items = (
    ctx.web.lists.get_by_title("Tasks")
    .items.select(["Title", "Status"])
    .filter("Status eq 'Active'")
    .order_by("Title")
    .top(100)
    .get()
    .execute_query()
)

Reading large collections. Use get_all() to follow paging automatically, and page_size to stay under server limits.

items = ctx.web.lists.get_by_title("Orders").items.get_all(page_size=2000).execute_query()

files = ctx.web.get_folder_by_server_relative_url("/sites/team/Shared Documents").get_files(
    recursive=True, page_size=2000
).execute_query()

Batching. Dispatch many queued operations in one round trip. Raise concurrency to run batches in parallel; throttled sub-requests are retried individually, honoring Retry-After.

for row in rows:
    ctx.web.lists.get_by_title("Contacts").add_item(row)

ctx.execute_batch()                     # sequential
ctx.execute_batch(concurrency=5)        # up to 5 batches in flight

# Graph
for user in new_users:
    client.users.add(user)
client.execute_batch(concurrency=5)

Large lists (> 5,000 items). SharePoint refuses filtered/sorted queries on non-indexed columns. The library can tell you what to index and pre-flight the query.

from office365.sharepoint.listitems.caml import Caml, CamlQuery

query = (
    CamlQuery.builder()
    .where(Caml.text("Status").eq("Active"))
    .order_by("ID")
    .row_limit(2000, paged=True)
    .build()
)

lst.check_query(query)                          # raises with a clear message if an index is missing
print(lst.index_candidates(query))              # columns worth indexing
lst.ensure_indexed("Status").execute_query()    # create the index (builds in the background)

Import and export DataFrames. Optional helpers turn list items into pandas / Polars frames and back.

lst = ctx.web.lists.ensure_list("Orders").execute_query()

df = lst.to_dataframe().execute_query().value
lst.from_dataframe(df, chunksize=100).execute_query()

Dependencies

Install the core package on its own, or add the extras you need:

Extra Adds Use it for
azure azure-storage-blob, cryptography Azure Blob Storage and certificate helpers
excel openpyxl Reading and writing Excel workbooks
examples faker Running the sample scripts
ntlm requests-ntlm On-premises SharePoint with NTLM
pandas pandas to_dataframe() / from_dataframe()
parquet pyarrow Parquet import and export
duckdb duckdb Querying exported data locally
sql sqlalchemy SQL-backed import and export
notebooks jupyter, nbformat, jinja2 Running the notebook samples
pip install "office365-rest-python-client[pandas,excel]"

Contributing

Issues and pull requests are welcome — please use the issue tracker for bugs and ideas.

git clone https://github.com/vgrem/office365-rest-python-client.git
cd office365-rest-python-client
uv sync --all-extras
pytest --offline -q

See CONTRIBUTING.md for the full development setup. Run the gate before submitting: ruff check ., ruff format --check ., pyright and pytest --offline -q.

Support

If this project saves you time, please consider sponsoring its development. ⭐

License

Released under the MIT License.

Release files for office365-rest-python-client 3.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for office365-rest-python-client 3.2.0
File Size Uploaded
office365_rest_python_client-3.2.0.tar.gz 1.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for office365-rest-python-client 3.2.0
File Interpreter ABI Platform
office365_rest_python_client-3.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 4.7 MB

Release files / office365_rest_python_client-3.2.0.tar.gz

Download URL office365_rest_python_client-3.2.0.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
c091fb466b12ee58ac1e137a94f50f7b6648e1da11f9fd5cedfc52cfc7c6ba06
BLAKE2b-256 checksum
How to use checksums
c7f8cdd48506747a41b9c621e714b220ca6970d29c68de607052f3d928435d24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / office365_rest_python_client-3.2.0-py3-none-any.whl

Download URL office365_rest_python_client-3.2.0-py3-none-any.whl
Size 3.5 MB
Tags Python 3
SHA-256 checksum
How to use checksums
7cdf0d9e06e4aa3caff994cbd6f78d5f3fdcdbc46adacb6cff9e037c6faef7dd
BLAKE2b-256 checksum
How to use checksums
ebf268ff920e42a1b3201b656ea770a1d1829692d348fc31c5efa608ca5bd245
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

3.2.0 This release

2 release files

3.1.0

2 release files

3.0.0

2 release files

2.6.2

2 release files

2.6.1

2 release files

2.6.0

2 release files

2.5.13

2 release files

2.5.12

2 release files

2.5.11

2 release files

2.5.10

2 release files

2.5.9

2 release files

2.5.8

2 release files

2.5.7

2 release files

2.5.6

2 release files

2.5.5

2 release files

2.5.4

2 release files

2.5.3

2 release files

2.5.2

2 release files

2.5.1

2 release files

2.5.0

2 release files

2.4.4

2 release files

2.4.3

2 release files

2.4.2

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.16

2 release files

2.3.15

2 release files

2.3.13

2 release files

2.3.12

2 release files

2.3.11

2 release files

2.3.10

2 release files

2.3.9

2 release files

2.3.8

2 release files

2.3.7

2 release files

2.3.6

2 release files

2.3.5

2 release files

2.3.4

2 release files

2.3.3

2 release files

2.3.2

2 release files

2.3.1

2 release files

2.3.0

2 release files

2.2.2

2 release files

2.2.1

2 release files

2.2.0

1 release file

2.1.10

1 release file

2.1.9

1 release file

2.1.8

1 release file

2.1.5

1 release file

2.1.4

1 release file

2.1.3

1 release file

2.1.2

1 release file

2.1.1

2 release files

2.0.0

1 release file

1.1.0

1 release file

1.0.1

1 release file

1.0.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page