Microsoft Graph Python SDK
The Microsoft Graph Python SDK is a client library for interacting with the Microsoft Graph API, enabling Python applications to access data across Microsoft 365, Windows, and Enterprise Mobility + Security. It supports the v1.0 of Microsoft Graph and is asynchronous by default, designed for modern Python applications. The library is actively maintained with frequent releases, currently at version 1.55.0, and leverages the underlying `msgraph-core` library and `kiota-authentication-azure` for core functionalities and authentication.
Warnings
- breaking Major breaking changes were introduced with version 1.0.0, specifically in how authentication providers are configured and the client is instantiated. The 'GraphClient' from 'msgraph.core' was replaced by 'GraphServiceClient' from 'msgraph', and authentication moved to 'AzureIdentityAuthenticationProvider' from 'kiota_authentication_azure'.
- gotcha The SDK is asynchronous by default, meaning all API calls return coroutines. You must use `await` and run your code within an `asyncio` event loop or similar async framework (`anyio`, `trio`).
- gotcha When sending attachments, the `content_bytes` field in attachment models (e.g., `FileAttachment`) expects raw bytes, not a base64 encoded string. The SDK handles the base64 encoding internally.
- gotcha The `msgraph-sdk` package is large, and its initial installation might take a few minutes. On Windows, users might encounter `OSError` related to long paths, requiring enabling long path support.
- gotcha There are two separate SDKs: `msgraph-sdk` for the v1.0 Microsoft Graph API endpoint and `msgraph-beta-sdk` for the latest beta endpoint. Mixing them or using the wrong one can lead to unexpected behavior or missing functionalities.
- gotcha The Microsoft Graph API itself can return 5xx status codes (e.g., 500 Internal Server Error, 503 Service Unavailable, 504 Gateway Timeout) which indicate server-side issues. While the SDK has a built-in retry-handler, these errors can still occur and may require application-level retry logic.
Install
-
pip install msgraph-sdk -
pip install msgraph-beta-sdk
Imports
- GraphServiceClient
from msgraph import GraphServiceClient
- AzureIdentityAuthenticationProvider
from kiota_authentication_azure.azure_identity_authentication_provider import AzureIdentityAuthenticationProvider
- ClientSecretCredential
from azure.identity.aio import ClientSecretCredential
Quickstart
import asyncio
import os
from azure.identity.aio import ClientSecretCredential
from kiota_authentication_azure.azure_identity_authentication_provider import AzureIdentityAuthenticationProvider
from msgraph import GraphServiceClient
from msgraph.generated.models.message import Message
async def main():
# Environment variables for client credentials flow
tenant_id = os.environ.get('TENANT_ID', 'YOUR_TENANT_ID')
client_id = os.environ.get('CLIENT_ID', 'YOUR_CLIENT_ID')
client_secret = os.environ.get('CLIENT_SECRET', 'YOUR_CLIENT_SECRET')
user_id = os.environ.get('USER_ID', 'YOUR_USER_ID') # User to fetch messages from
# Ensure required environment variables are set
if not all([tenant_id, client_id, client_secret, user_id]):
print("Please set TENANT_ID, CLIENT_ID, CLIENT_SECRET, and USER_ID environment variables.")
return
# For app-only permissions, use the .default scope
scopes = ['https://graph.microsoft.com/.default']
# Create a credential object
credential = ClientSecretCredential(
tenant_id=tenant_id,
client_id=client_id,
client_secret=client_secret
)
# Create an authentication provider
auth_provider = AzureIdentityAuthenticationProvider(credential, scopes=scopes)
# Create a GraphServiceClient
client = GraphServiceClient(auth_provider)
try:
# Fetch messages for a specific user
# Note: This requires Mail.Read.All application permission or Mail.Read delegated permission for the user_id
# if using delegated flow.
messages_collection = await client.users.by_user_id(user_id).messages.get()
if messages_collection and messages_collection.value:
print(f"Successfully fetched {len(messages_collection.value)} messages for user {user_id}:")
for msg in messages_collection.value:
print(f" Subject: {msg.subject}, From: {msg.sender.email_address.address}")
else:
print(f"No messages found for user {user_id}.")
except Exception as e:
print(f"Error fetching messages: {e}")
if __name__ == '__main__':
asyncio.run(main())