O365 Python Library

repository·master·Indexed 23 days ago

https://github.com/o365/python-o365

A Python library providing a Pythonic abstraction layer for the Microsoft Graph REST API and Office 365 services, including Email, Calendar, Contacts, OneDrive, and SharePoint. It features full OAuth support with automatic refresh tokens, OData query helpers, pagination for infinite item retrieval, and multiple authentication flows (authorization, public, and credentials).

Tokens
22.8K
Snippets
60
Records
95
Agent score
83%

What's inside O365

  1. Overview of O365 features

    master

    O365 provides a Pythonic abstraction layer for the Microsoft Graph REST API, enabling access to services like Email, Calendar, Contacts, OneDrive, and SharePoint.

    Key capabilities include:

    • Full OAuth Support: Automatic handling of refresh tokens.
    • Datetime Management: Automatic conversion between local and server datetimes.
    • Resource Switching: Easy access to shared mailboxes, other users' resources, and SharePoint.
    • Pagination: Custom iterators that handle future requests automatically for infinite item retrieval.
    • Querying: A query helper for building OData queries (filter, order, select, and search).
    • Extensibility: Modular ApiComponents for building custom functionality.
  2. Key features of python-o365

    master

    The python-o365 library provides several high-level abstractions for interacting with Microsoft Graph:

    • Full OAuth support: Automatically handles refresh tokens.
    • Datetime handling: Automatically manages conversions between local datetimes and server datetimes.
    • Resource switching: Easily switch between shared mailboxes, other users' resources, and SharePoint resources.
    • Pagination: Uses a custom iterator that automatically handles future requests for infinite item retrieval.
    • OData Query Helper: Simplifies building custom OData queries using filter, order, select, and search.
    • Modular API: Supports creating modular ApiComponents for extended functionality.
  3. Handle incoming webhook notifications

    master

    When a subscribed event occurs, Microsoft Graph sends a POST request to your notification_url with a JSON payload.

    Payload Structure: The payload contains a value array of notification objects. Each object includes:

    • subscriptionId: The ID of the subscription triggered.
    • changeType: The type of change (e.g., created).
    • resource: The specific resource that changed.
    • resourceData: Metadata about the changed resource (e.g., @odata.id, id).
    • clientState: The state you provided during creation, which must be validated to ensure the request is authentic.

    Example Payload:

    {
        'value': [
            {
                'subscriptionId': '548355f8-c2c0-47ae-aac7-3ad02b2dfdb12',
                'subscriptionExpirationDateTime': '2026-01-07T11:35:40.301594+00:00',
                'changeType': 'created',
                'resource': 'Users/12345678-a5c7-46da-8107-b25090a1ed66/Messages/<long_guid>=',
                'resourceData': {
                    '@odata.type': '#Microsoft.Graph.Message',
                    '@odata.id': 'Users/12345678-a5c7-46da-8107-b25090a1ed66/Messages/<long_guid>=',
                    '@odata.etag': 'W/"CQAAABYACCCoiRErLbiNRJDCFyMjq4khBBnH4N7A"',
                    'id': '<long_guid>='
                },
                'clientState': 'abc123',
                'tenantId': '12345678-abcd-1234-abcd-1234567890ab'
            }
        ]
    }
  4. How Schedule, Calendar, and Event work together

    master

    Calendar and event functionality is managed through a hierarchy of three main classes:

    1. Schedule: The entry point. An instance of Schedule (obtained via account.schedule()) is used to list or create calendars and to manage events on the default user calendar.
    2. Calendar: Represents a specific calendar. You can retrieve the default calendar from a Schedule instance using get_default_calendar() or retrieve a specific calendar by name using get_calendar(calendar_name='...').
    3. Event: Represents a calendar entry. You create a new event via a Calendar instance using calendar.new_event().

    To interact with specific calendars other than the default one, you must first obtain a Calendar instance from the Schedule object.

  5. Manage Token Storage with TokenBackends

    master

    To avoid re-authenticating every time, you must store OAuth tokens using a TokenBackend. The library abstracts storage so you can choose the most appropriate method for your environment.

    Available TokenBackends:

    • FileSystemTokenBackend (Default): Stores tokens as text files in a specified directory.
    • MemoryTokenBackend: Stores tokens in memory (not persistent).
    • EnvTokenBackend: Uses environment variables.
    • FirestoreTokenBackend: Uses Google Firestore.
    • AWSS3Backend: Uses AWS S3 buckets.
    • AWSSecretsBackend: Uses AWS Secrets Manager.
    • BitwardenSecretsManagerBackend: Uses Bitwarden Secrets Manager.
    • DjangoTokenBackend: Uses a Django model.

    Security Warning: Access and refresh tokens must be protected. You can use a cryptography_manager (an object with encrypt and decrypt methods) in a TokenBackend to secure stored tokens.

  6. Handle large datasets with Pagination

    master

    When requesting more items than a single API call can return, the library returns a Pagination object. This object is an iterator that abstracts the process of following "next link" URLs. It automatically requests more data from the API as you iterate through the items.

    To optimize memory or network latency, you can use the batch parameter to specify how many items to request per API call. This is useful when you want to control the size of the data chunks being fetched.

  7. How OneDrive and SharePoint storage works

    master

    The Storage class is the entry point for interacting with OneDrive and SharePoint Document Library storage.

    • Storage: Handles all storage-related functionality and allows you to retrieve Drive instances.
    • Drive: Represents a specific drive (like a personal OneDrive or a SharePoint library) and allows you to work with Folders and Files within it.
    • DriveItem: Both Files and Folders are types of DriveItem. Specific subtypes like Image and Photo inherit from File, which in turn inherits from DriveItem. Use properties like .is_folder, .is_file, .is_photo, and .is_image to distinguish between them.

    To interact with storage, you first obtain a Storage instance from your Account object.

    account = Account(credentials=my_credentials)
    storage = account.storage()
    my_drive = storage.get_default_drive()
  8. Choose an authentication flow

    master

    The python-o365 library uses OAuth authentication. There are three primary authentication methods depending on your application type and target resources:

    1. On behalf of a user (auth_flow_type='authorization'): The default method. Uses the authorization code grant flow. The user provides consent for the app to access their resources. Works for any Microsoft account type.
    2. On behalf of a user (public) (auth_flow_type='public'): Similar to the above but for public apps where a client secret cannot be securely stored. No client secret is required.
    3. With your own identity (auth_flow_type='credentials'): Uses the client credentials grant flow (app identity). Requires a tenant_id and is not allowed for Microsoft Personal accounts. It uses application permissions to access all Azure AD users the app has access to.

    Note: For all methods, if you add the offline_access permission, the library can automatically refresh tokens. Refresh tokens last 90 days, but are refreshed upon each connection within that window.

  9. Manage API Resources and Shared Mailboxes

    master

    A 'resource' defines the owner of the data being accessed. By default, protocols use 'ME' (the user who gave consent). You can change the resource at three different levels:

    1. Protocol level: Sets a default resource for all accounts using that protocol.
    2. Account level: Sets a default resource for all objects (mailboxes, messages, etc.) created from that account instance.
    3. Per-use case: Overrides the resource for a specific object instance.

    Common resource formats include:

    • 'me': The consenting user (default).
    • 'user:user@domain.com': A shared mailbox or specific user account (the user: prefix is optional and will be inferred).
    • 'site:sharepoint-site-id': A SharePoint site.
    • 'group:group-site-id': An Microsoft 365 group.
    # 1. Protocol level
    protocol = MSGraphProtocol(default_resource='shared_mailbox@example.com')
    account = Account(credentials=my_credentials, protocol=protocol)
    
    # 2. Account level
    account = Account(credentials=my_credentials, main_resource='shared_mailbox@example.com')
    
    # 3. Per-use case (Object level)
    account = Account(credentials=my_credentials)
    mailbox = account.mailbox('shared_mailbox@example.com')
    # OR
    message = Message(parent=account, main_resource='shared_mailbox@example.com')
  10. How datetime handling works in Tasks

    master
    When setting task properties like due, naive datetime objects are automatically converted to timezone-aware datetime objects. The conversion uses either the local timezone detected by the system or the timezone provided by the protocol, matching the behavior of the Calendar functionality.
  11. Configure Workbook Sessions

    master

    When performing numerous changes to an Excel file, you can use Workbook Sessions to improve efficiency.

    By default, WorkBook uses a persistent session that automatically recreates itself if it expires due to inactivity. If you want to avoid using sessions or want to ensure they are non-persistent, you can configure this during the instantiation of the WorkBook object using use_session and persist parameters.

  12. Handle multiple users with a single Account object

    master

    In version 2.1+, a single Account object can manage multiple authenticated users. The token backend stores authentication for each user, and you can switch between them using the account.username property.

    If account.username is not set, it defaults to the first user found in the token backend. Performing a new authenticate() call will automatically set the username to the user currently authenticating.

    account.username = 'user1@domain.com'
    # Perform actions as user1
    
    account.username = 'user2@domain.com'
    # Perform actions as user2
    account.username = 'user1@domain.com'
    #  issue some calls to retrieve data using the auth of the user1
    account.username = 'user2@domain.com'
    #  now every call will use the auth of the user2