{"id":107,"date":"2026-07-22T19:27:16","date_gmt":"2026-07-23T02:27:16","guid":{"rendered":"https:\/\/gozera.ai\/blog\/?p=107"},"modified":"2026-07-22T19:27:16","modified_gmt":"2026-07-23T02:27:16","slug":"microsoft-365-automation-with-python","status":"publish","type":"post","link":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/","title":{"rendered":"Microsoft 365 Automation with Python: 2026 Production Guide"},"content":{"rendered":"<\/p>\n<p>Python is the most practical tool available for automating Microsoft 365 at scale. Using the <a href=\"https:\/\/learn.microsoft.com\/en-us\/graph\/tutorials\/python\" rel=\"nofollow noopener noreferrer\" target=\"_blank\">Microsoft Graph SDK for Python<\/a>, the Office365-REST-Python-Client library, and the Azure Connectors Python SDK, you can automate virtually every Microsoft 365 service your firm runs: Outlook mail, Calendar, SharePoint, OneDrive, and Teams. Authentication runs through OAuth2 managed by MSAL (Microsoft Authentication Library) for Python, which handles token acquisition and refresh without custom wrappers. The result is production-grade automation that IT teams at law firms, accounting practices, and consulting companies can deploy and maintain without constant intervention.<\/p>\n<p>Here is what you can automate with these tools:<\/p>\n<ul>\n<li><strong>Outlook email<\/strong>: send, read, filter, and manage messages and attachments programmatically<\/li>\n<li><strong>Calendar<\/strong>: create, update, and delete events; manage attendees and recurring appointments<\/li>\n<li><strong>SharePoint Online<\/strong>: upload, download, and manage files, lists, and site permissions<\/li>\n<li><strong>OneDrive<\/strong>: sync files, move folders, and trigger file-based workflows<\/li>\n<li><strong>Teams<\/strong>: post channel messages, create teams, and manage memberships<\/li>\n<li><strong>Task scheduling<\/strong>: run scripts on cron, APScheduler, or Azure Automation runbooks<\/li>\n<li><strong>Advanced Graph REST calls<\/strong>: paginate large datasets, handle complex resources, and build custom integrations<\/li>\n<\/ul>\n<hr>\n<h2 id=\"how-to-set-up-your-microsoft-365-environment-for-python-automation\">How to set up your Microsoft 365 environment for Python automation<\/h2>\n<p><img decoding=\"async\" src=\"https:\/\/csuxjmfbwmkxiegfpljm.supabase.co\/storage\/v1\/object\/public\/blog-images\/organization-42891\/1784475443386_Infographic-showing-Python-automation-workflow-steps.jpeg\" alt=\"Infographic showing Python automation workflow steps\"><\/p>\n<p>Before writing a single line of automation code, you need a registered app in Microsoft Entra (formerly Azure AD) and a properly configured Python environment.<\/p>\n<h3 id=\"app-registration-in-microsoft-entra\">App registration in Microsoft Entra<\/h3>\n<ol>\n<li>Sign in to the <a href=\"https:\/\/entra.microsoft.com\" rel=\"nofollow noopener noreferrer\" target=\"_blank\">Microsoft Entra admin center<\/a> and navigate to <strong>App registrations<\/strong>.<\/li>\n<li>Select <strong>New registration<\/strong>, give the app a name (e.g., <code>M365-Python-Automation<\/code>), and choose the appropriate account type for your tenant.<\/li>\n<li>On the <strong>Overview<\/strong> page, copy the <strong>Application (client) ID<\/strong> and <strong>Directory (tenant) ID<\/strong>.<\/li>\n<li>Under <strong>Certificates &amp; secrets<\/strong>, create a new client secret and copy the value immediately. It will not be shown again.<\/li>\n<li>Under <strong>API permissions<\/strong>, add the Microsoft Graph permissions your scripts need (e.g., <code>Mail.ReadWrite<\/code>, <code>Calendars.ReadWrite<\/code>, <code>Files.ReadWrite.All<\/code>, <code>Sites.ReadWrite.All<\/code>).<\/li>\n<li>Grant <strong>admin consent<\/strong> for the permissions you added.<\/li>\n<\/ol>\n<h3 id=\"python-environment-prerequisites\">Python environment prerequisites<\/h3>\n<ul>\n<li>Python 3.8 or higher (Python 3.10 recommended for Azure Automation runbooks)<\/li>\n<li><code>pip<\/code> for package management<\/li>\n<li>Core libraries:<\/li>\n<\/ul>\n<pre><code>pip install msgraph-sdk azure-identity msal Office365-REST-Python-Client requests\n<\/code><\/pre>\n<h3 id=\"secure-credential-storage\">Secure credential storage<\/h3>\n<p>Never hardcode credentials in scripts. Store your <code>client_id<\/code>, <code>tenant_id<\/code>, and <code>client_secret<\/code> in environment variables or a <code>.env<\/code> file loaded with <code>python-dotenv<\/code>, and add that file to <code>.gitignore<\/code> immediately.<\/p>\n<pre><code class=\"language-python\">import os\nCLIENT_ID = os.environ[&quot;AZURE_CLIENT_ID&quot;]\nTENANT_ID = os.environ[&quot;AZURE_TENANT_ID&quot;]\nCLIENT_SECRET = os.environ[&quot;AZURE_CLIENT_SECRET&quot;]\n<\/code><\/pre>\n<blockquote>\n<p><strong>Secure credential management is not optional in production.<\/strong> Hardcoded secrets in source code are the leading cause of credential leaks in enterprise automation projects. Use environment variables, Azure Key Vault references, or managed identities for every deployment.<\/p>\n<\/blockquote>\n<p><strong>Pro Tip:<\/strong> <em>For Azure Automation runbooks, skip client secrets entirely and use managed identities instead. Microsoft\u2019s own tutorials recommend this approach because it eliminates secret rotation overhead and ties authentication directly to the Azure resource.<\/em><\/p>\n<hr>\n<h2 id=\"how-to-connect-to-microsoft-365-apis-and-authenticate-with-python\">How to connect to Microsoft 365 APIs and authenticate with Python<\/h2>\n<p>Authentication is where most Microsoft 365 automation projects break down in production. The fix is straightforward: use MSAL for Python and never build a custom OAuth2 flow.<\/p>\n<h3 id=\"msal-token-acquisition-for-app-only-access\">MSAL token acquisition for app-only access<\/h3>\n<pre><code class=\"language-python\">import msal\n\nauthority = f&quot;https:\/\/login.microsoftonline.com\/{TENANT_ID}&quot;\napp = msal.ConfidentialClientApplication(\n    client_id=CLIENT_ID,\n    client_credential=CLIENT_SECRET,\n    authority=authority\n)\n\ntoken_response = app.acquire_token_for_client(\n    scopes=[&quot;https:\/\/graph.microsoft.com\/.default&quot;]\n)\naccess_token = token_response[&quot;access_token&quot;]\n<\/code><\/pre>\n<p>This is <strong>app-only authentication<\/strong>, which runs without a signed-in user. It is the right choice for unattended automation scripts. For workflows that act on behalf of a specific user, use <strong>delegated permissions<\/strong> with the device code flow instead.<\/p>\n<h3 id=\"token-lifecycle-management\">Token lifecycle management<\/h3>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/introducing-the-microsoft-graph-python-sdk-now-available-for-public-preview\/\" rel=\"nofollow noopener noreferrer\" target=\"_blank\">Refresh tokens expire<\/a> after 90 days without re-authentication. In unattended automation, that means a script that worked in january can silently fail in april. MSAL\u2019s built-in token cache handles refresh automatically when you serialize and persist the cache between runs.<\/p>\n<blockquote>\n<p><strong>All Microsoft 365 API authentication must use OAuth2 managed with MSAL.<\/strong> Basic authentication was deprecated by Microsoft, and any script still relying on username\/password auth will fail in production environments.<\/p>\n<\/blockquote>\n<p><strong>Best practices for token management:<\/strong><\/p>\n<ul>\n<li>Use <code>msal.SerializableTokenCache<\/code> and persist it to disk or Azure Key Vault between script runs<\/li>\n<li>Never log or print access tokens<\/li>\n<li>Scope requests to the minimum permissions required (least-privilege principle)<\/li>\n<li>For Azure-hosted scripts, prefer managed identities over client secrets<\/li>\n<\/ul>\n<p><strong>Pro Tip:<\/strong> <em>The <a href=\"https:\/\/github.com\/Azure\/Connectors-python-sdk\" rel=\"nofollow noopener noreferrer\" target=\"_blank\">Azure Connectors Python SDK<\/a> has built-in authentication via <code>ManagedIdentityTokenProvider<\/code> and <code>DefaultAzureCredential<\/code>, which means you skip the MSAL setup entirely for Azure-hosted scripts. It is the fastest path to production for teams running automation inside Azure Functions or Automation Accounts.<\/em><\/p>\n<hr>\n<h2 id=\"how-to-automate-outlook-email-with-python\">How to automate Outlook email with Python<\/h2>\n<p>The two primary libraries for Python automation with Outlook are the Microsoft Graph SDK (<code>msgraph-sdk<\/code>) and the Office365-REST-Python-Client. Both work well; the Graph SDK is the more modern choice for new projects.<\/p>\n<h3 id=\"sending-email-with-the-graph-sdk\">Sending email with the Graph SDK<\/h3>\n<pre><code class=\"language-python\">from msgraph import GraphServiceClient\nfrom msgraph.generated.users.item.send_mail.send_mail_post_request_body import SendMailPostRequestBody\nfrom msgraph.generated.models.message import Message\nfrom msgraph.generated.models.item_body import ItemBody\nfrom msgraph.generated.models.recipient import Recipient\nfrom msgraph.generated.models.email_address import EmailAddress\nfrom azure.identity import ClientSecretCredential\n\ncredential = ClientSecretCredential(TENANT_ID, CLIENT_ID, CLIENT_SECRET)\nclient = GraphServiceClient(credential)\n\nmessage = Message()\nmessage.subject = &quot;Automated Report&quot;\nmessage.body = ItemBody()\nmessage.body.content = &quot;Your weekly summary is attached.&quot;\nrecipient = Recipient()\nrecipient.email_address = EmailAddress()\nrecipient.email_address.address = &quot;partner@yourfirm.com&quot;\nmessage.to_recipients = [recipient]\n\nrequest_body = SendMailPostRequestBody()\nrequest_body.message = message\nawait client.users.by_user_id(&quot;me&quot;).send_mail.post(request_body)\n<\/code><\/pre>\n<h3 id=\"reading-the-inbox-and-managing-messages\">Reading the inbox and managing messages<\/h3>\n<pre><code class=\"language-python\">messages = await client.users.by_user_id(&quot;me&quot;).mail_folders.by_mail_folder_id(&quot;inbox&quot;).messages.get()\nfor msg in messages.value:\n    print(msg.subject, msg.received_date_time)\n<\/code><\/pre>\n<p>To mark a message as read, patch the <code>is_read<\/code> property. To move it to a folder, use the <code>move<\/code> action with the target folder ID.<\/p>\n<h3 id=\"key-email-automation-scenarios-for-professional-services-firms\">Key email automation scenarios for professional services firms<\/h3>\n<ul>\n<li>Auto-forwarding client intake emails to matter management systems<\/li>\n<li>Sending scheduled billing reminders with PDF attachments<\/li>\n<li>Parsing incoming invoices and routing them to the right approver<\/li>\n<li>Archiving emails by client matter number into SharePoint folders<\/li>\n<\/ul>\n<p><strong>Pro Tip:<\/strong> <em>Microsoft Graph enforces API throttling on mail endpoints. If you are processing large volumes, add exponential backoff on HTTP 429 responses. The Graph SDK surfaces these as <code>ODataError<\/code> exceptions, so wrap your calls in a try\/except block and retry after the <code>Retry-After<\/code> header value.<\/em><\/p>\n<hr>\n<h2 id=\"how-to-automate-microsoft-365-calendar-with-python\">How to automate Microsoft 365 Calendar with Python<\/h2>\n<p>Calendar automation is one of the highest-ROI use cases for professional services firms. Scheduling client meetings, sending reminders, and syncing appointments with billing systems are all achievable with a few dozen lines of Python.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/csuxjmfbwmkxiegfpljm.supabase.co\/storage\/v1\/object\/public\/blog-images\/organization-42891\/1784475031386_Hands-typing-Python-code-for-calendar-automation.jpeg\" alt=\"Hands typing Python code for calendar automation\"><\/p>\n<h3 id=\"creating-a-calendar-event\">Creating a calendar event<\/h3>\n<pre><code class=\"language-python\">from msgraph.generated.models.event import Event\nfrom msgraph.generated.models.date_time_time_zone import DateTimeTimeZone\nfrom msgraph.generated.models.attendee import Attendee\n\nevent = Event()\nevent.subject = &quot;Quarterly Review&quot;\nevent.start = DateTimeTimeZone()\nevent.start.date_time = &quot;2026-03-15T10:00:00&quot;\nevent.start.time_zone = &quot;America\/New_York&quot;\nevent.end = DateTimeTimeZone()\nevent.end.date_time = &quot;2026-03-15T11:00:00&quot;\nevent.end.time_zone = &quot;America\/New_York&quot;\n\nattendee = Attendee()\nattendee.email_address = EmailAddress()\nattendee.email_address.address = &quot;client@example.com&quot;\nevent.attendees = [attendee]\n\nawait client.users.by_user_id(&quot;me&quot;).events.post(event)\n<\/code><\/pre>\n<h3 id=\"best-practices-for-time-zone-and-date-handling\">Best practices for time zone and date handling<\/h3>\n<ul>\n<li>Always specify <code>time_zone<\/code> explicitly. Omitting it defaults to UTC, which causes meeting time mismatches for US-based attendees.<\/li>\n<li>Store and compare datetimes as UTC internally; convert to local time only at the display layer.<\/li>\n<li>For recurring events, set the <code>recurrence<\/code> property using <code>PatternedRecurrence<\/code> with the appropriate <code>RecurrencePattern<\/code> type (<code>weekly<\/code>, <code>monthly<\/code>, etc.).<\/li>\n<\/ul>\n<h3 id=\"common-calendar-automation-use-cases\">Common calendar automation use cases<\/h3>\n<ul>\n<li>Auto-scheduling follow-up calls after a contract is signed<\/li>\n<li>Blocking time for recurring compliance deadlines (tax filings, audit windows)<\/li>\n<li>Syncing court dates or deposition schedules from external case management systems<\/li>\n<li>Sending calendar invites when a new client matter is opened<\/li>\n<\/ul>\n<p><strong>Pro Tip:<\/strong> <em>When updating an existing event, retrieve the event\u2019s <code>id<\/code> first and use a PATCH request rather than deleting and recreating it. This preserves the original invite thread and avoids confusing attendees with duplicate notifications.<\/em><\/p>\n<hr>\n<h2 id=\"how-to-schedule-tasks-and-trigger-workflows-with-python\">How to schedule tasks and trigger workflows with Python<\/h2>\n<p>Python scripts do not run themselves. You need a scheduler or a trigger mechanism, and the right choice depends on where your script lives.<\/p>\n<h3 id=\"local-and-server-based-scheduling\">Local and server-based scheduling<\/h3>\n<p>For scripts running on a Windows or Linux server, the two most common options are:<\/p>\n<ul>\n<li><strong>APScheduler<\/strong>: a Python library that supports cron-style, interval, and date-based triggers with a clean API<\/li>\n<li><strong>OS cron jobs<\/strong> (Linux) or <strong>Windows Task Scheduler<\/strong>: reliable for simple, time-based execution without additional dependencies<\/li>\n<\/ul>\n<pre><code class=\"language-python\">from apscheduler.schedulers.blocking import BlockingScheduler\n\nscheduler = BlockingScheduler()\n\n@scheduler.scheduled_job('cron', hour=8, minute=0)\ndef morning_report():\n    # your Graph API calls here\n    pass\n\nscheduler.start()\n<\/code><\/pre>\n<h3 id=\"azure-hosted-scheduling\">Azure-hosted scheduling<\/h3>\n<p>For production deployments, Azure Automation runbooks are the right tool. You write a Python script, upload it as a runbook, attach a schedule, and Azure handles execution. Runbooks use managed identities for authentication, which removes the need for stored secrets entirely.<\/p>\n<p>Power Automate Cloud does not execute Python natively. <a href=\"https:\/\/stackoverflow.com\/questions\/77751515\/running-python-scripts-in-microsoft-power-automate-cloud\" rel=\"nofollow noopener noreferrer\" target=\"_blank\">Python scripts in Power Automate Cloud<\/a> require hosting in an Azure Automation Account or as an Azure Function with an HTTP trigger. The Power Automate flow calls the Azure Function URL, passes data as JSON, and the Python function returns a result. This hybrid pattern is the standard approach for <a href=\"https:\/\/gozera.ai\/blog\/power-automate-alternatives-4-agencies\" target=\"_blank\" rel=\"noopener\">combining event-driven orchestration<\/a> with Python business logic.<\/p>\n<p><strong>Pro Tip:<\/strong> <em>For failure recovery, configure Azure Automation runbooks with retry settings and alert rules in Azure Monitor. A runbook that fails silently is worse than no automation at all.<\/em><\/p>\n<hr>\n<h2 id=\"how-to-use-microsoft-graph-rest-apis-directly-in-python\">How to use Microsoft Graph REST APIs directly in Python<\/h2>\n<p>Sometimes the SDKs do not expose a specific endpoint, or you need fine-grained control over the request. Direct REST calls with the <code>requests<\/code> library fill that gap.<\/p>\n<h3 id=\"making-a-raw-graph-api-call\">Making a raw Graph API call<\/h3>\n<pre><code class=\"language-python\">import requests\n\nheaders = {\n    &quot;Authorization&quot;: f&quot;Bearer {access_token}&quot;,\n    &quot;Content-Type&quot;: &quot;application\/json&quot;\n}\n\nresponse = requests.get(\n    &quot;https:\/\/graph.microsoft.com\/v1.0\/me\/messages&quot;,\n    headers=headers,\n    params={&quot;$top&quot;: 50, &quot;$select&quot;: &quot;subject,receivedDateTime,from&quot;}\n)\nresponse.raise_for_status()\ndata = response.json()\n<\/code><\/pre>\n<h3 id=\"handling-pagination\">Handling pagination<\/h3>\n<p>Microsoft Graph returns paginated results for large collections. Check for <code>@odata.nextLink<\/code> in the response and loop until it is absent:<\/p>\n<pre><code class=\"language-python\">url = &quot;https:\/\/graph.microsoft.com\/v1.0\/me\/messages&quot;\nwhile url:\n    response = requests.get(url, headers=headers)\n    data = response.json()\n    for message in data.get(&quot;value&quot;, []):\n        process(message)\n    url = data.get(&quot;@odata.nextLink&quot;)\n<\/code><\/pre>\n<h3 id=\"error-handling-and-retry-strategy\">Error handling and retry strategy<\/h3>\n<pre><code class=\"language-python\">import time\n\ndef graph_get(url, headers, max_retries=3):\n    for attempt in range(max_retries):\n        response = requests.get(url, headers=headers)\n        if response.status_code == 429:\n            retry_after = int(response.headers.get(&quot;Retry-After&quot;, 10))\n            time.sleep(retry_after)\n        elif response.status_code &gt;= 500:\n            time.sleep(2 ** attempt)\n        else:\n            response.raise_for_status()\n            return response.json()\n    raise Exception(&quot;Max retries exceeded&quot;)\n<\/code><\/pre>\n<p><strong>Advanced scenarios that require direct REST calls:<\/strong><\/p>\n<ul>\n<li>Querying Microsoft Search API for cross-service content discovery<\/li>\n<li>Accessing beta-endpoint features not yet in the stable SDK<\/li>\n<li>Batch requests using the <code>$batch<\/code> endpoint to reduce API call volume<\/li>\n<li>Custom delta queries for incremental sync of large mailboxes or drives<\/li>\n<\/ul>\n<p><strong>Pro Tip:<\/strong> <em>Use <code>aiohttp<\/code> instead of <code>requests<\/code> when you need concurrent API calls. Fetching 50 mailboxes sequentially with <code>requests<\/code> takes seconds; fetching them concurrently with <code>asyncio<\/code> and <code>aiohttp<\/code> takes a fraction of that time.<\/em><\/p>\n<hr>\n<h2 id=\"production-ready-patterns-and-best-practices-for-microsoft-365-python-automation\">Production-ready patterns and best practices for Microsoft 365 Python automation<\/h2>\n<p>The teams that get Microsoft 365 Python automation into production fastest share one habit: they offload authentication complexity to managed SDKs rather than building their own OAuth2 flows. IT teams that avoid custom OAuth2 wrappers and rely on established SDKs report faster, more stable deployments with fewer API connection bugs.<\/p>\n<p>The Azure Connectors Python SDK takes this further with a connector-first, async-native design. It provides type-safe, async-first Python clients with built-in authentication, configurable retry policies, and exponential backoff out of the box. For teams building automation inside Azure Functions, it is the cleanest path available.<\/p>\n<p><strong>Core production patterns:<\/strong><\/p>\n<ul>\n<li><strong>Least-privilege permissions<\/strong>: request only the Graph scopes your script actually uses. Broad permissions like <code>Mail.ReadWrite.All<\/code> on a script that only sends mail are a security liability.<\/li>\n<li><strong>Centralized logging<\/strong>: write structured logs (JSON format) to Azure Monitor or Application Insights so failures are traceable without SSH access to a server.<\/li>\n<li><strong>Idempotent operations<\/strong>: design scripts so re-running them after a failure does not create duplicate emails, events, or files.<\/li>\n<li><strong>Secret rotation<\/strong>: rotate client secrets on a schedule and use Azure Key Vault references in runbooks to avoid hardcoded expiry surprises.<\/li>\n<li><strong>Hybrid architecture<\/strong>: use Power Automate for event triggers and Azure-hosted Python for the business logic. Power Automate handles the \u201cwhen\u201d and Python handles the \u201cwhat.\u201d<\/li>\n<\/ul>\n<p>For mid-market professional services firms, the <a href=\"https:\/\/gozera.ai\/blog\/copilot-workflows-for-professional-services-2026-guide\" target=\"_blank\" rel=\"noopener\">Copilot workflows guide<\/a> from Gozera covers how these Python automation patterns integrate with Microsoft 365 Copilot to recover billable time at scale.<\/p>\n<p><strong>Pro Tip:<\/strong> <em>Start with the Azure Connectors Python SDK\u2019s <code>Office365Client<\/code> for new projects. The managed identity token provider and built-in retry logic eliminate two of the three most common production failure modes before you write a single business logic line.<\/em><\/p>\n<hr>\n<h2 id=\"how-to-automate-sharepoint-online-with-python\">How to automate SharePoint Online with Python<\/h2>\n<p>The Office365-REST-Python-Client library gives you two distinct clients for SharePoint: <code>ClientContext<\/code> for the SharePoint REST API v1 (lists, files, site admin, permissions) and <code>GraphClient<\/code> for Microsoft Graph-based SharePoint access. Use <code>ClientContext<\/code> when you need full SharePoint fidelity.<\/p>\n<h3 id=\"uploading-a-file-to-sharepoint\">Uploading a file to SharePoint<\/h3>\n<pre><code class=\"language-python\">from office365.sharepoint.client_context import ClientContext\n\nctx = ClientContext(&quot;https:\/\/yourtenant.sharepoint.com\/sites\/YourSite&quot;).with_client_secret(\n    client_id=CLIENT_ID,\n    client_secret=CLIENT_SECRET,\n    tenant=TENANT_ID\n)\n\nwith open(&quot;report.pdf&quot;, &quot;rb&quot;) as f:\n    file_content = f.read()\n\ntarget_folder = ctx.web.get_folder_by_server_relative_url(&quot;\/sites\/YourSite\/Shared Documents&quot;)\ntarget_folder.upload_file(&quot;report.pdf&quot;, file_content).execute_query()\nprint(&quot;File uploaded.&quot;)\n<\/code><\/pre>\n<h3 id=\"reading-a-sharepoint-list\">Reading a SharePoint list<\/h3>\n<pre><code class=\"language-python\">list_obj = ctx.web.lists.get_by_title(&quot;Client Matters&quot;)\nitems = list_obj.items.get().execute_query()\nfor item in items:\n    print(item.properties.get(&quot;Title&quot;), item.properties.get(&quot;Status&quot;))\n<\/code><\/pre>\n<p>Common SharePoint automation scenarios for professional services include auto-archiving completed matter folders, syncing client data from an external CRM into a SharePoint list, and enforcing document naming conventions on upload. For law firms managing document-heavy workflows, <a href=\"https:\/\/gozera.ai\/blog\/workflow-automation-for-law-firms-a-2026-roi-guide\" target=\"_blank\" rel=\"noopener\">automating SharePoint document routing<\/a> can cut manual filing time significantly.<\/p>\n<hr>\n<h2 id=\"how-to-automate-onedrive-file-operations-with-python\">How to automate OneDrive file operations with Python<\/h2>\n<p>OneDrive automation through Microsoft Graph uses the <code>drives<\/code> endpoint. The <code>GraphClient<\/code> from Office365-REST-Python-Client or the <code>msgraph-sdk<\/code> both work well here.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/csuxjmfbwmkxiegfpljm.supabase.co\/storage\/v1\/object\/public\/blog-images\/organization-42891\/1784475030850_Programmer-working-on-OneDrive-file-automation-scripting.jpeg\" alt=\"Programmer working on OneDrive file automation scripting\"><\/p>\n<h3 id=\"listing-files-in-a-onedrive-folder\">Listing files in a OneDrive folder<\/h3>\n<pre><code class=\"language-python\">drive_items = await client.users.by_user_id(&quot;me&quot;).drive.root.children.get()\nfor item in drive_items.value:\n    print(item.name, item.size)\n<\/code><\/pre>\n<h3 id=\"uploading-a-file-to-onedrive\">Uploading a file to OneDrive<\/h3>\n<pre><code class=\"language-python\">file_path = &quot;\/Documents\/invoice.pdf&quot;\nwith open(&quot;invoice.pdf&quot;, &quot;rb&quot;) as f:\n    content = f.read()\n\nawait client.users.by_user_id(&quot;me&quot;).drive.root.item_with_path(&quot;Documents\/invoice.pdf&quot;).content.put(content)\n<\/code><\/pre>\n<p>For files larger than 4 MB, use the upload session API, which splits the file into chunks and handles resumable uploads. This is the correct approach for automating document delivery in accounting or legal workflows where PDF exports regularly exceed that threshold. Firms using <a href=\"https:\/\/ledgeronecfo.com\/services\" rel=\"nofollow noopener noreferrer\" target=\"_blank\">finance automation integrations<\/a> alongside Microsoft 365 often connect OneDrive file triggers to downstream processing pipelines using this pattern.<\/p>\n<hr>\n<h2 id=\"how-to-automate-microsoft-teams-with-python\">How to automate Microsoft Teams with Python<\/h2>\n<p>Teams automation via Microsoft Graph covers channel messaging, team creation, and membership management. The <code>GraphClient<\/code> handles all of it.<\/p>\n<h3 id=\"posting-a-message-to-a-teams-channel\">Posting a message to a Teams channel<\/h3>\n<pre><code class=\"language-python\">from office365.graph_client import GraphClient\nimport msal\n\ndef acquire_token():\n    authority = f&quot;https:\/\/login.microsoftonline.com\/{TENANT_ID}&quot;\n    app = msal.ConfidentialClientApplication(CLIENT_ID, CLIENT_SECRET, authority=authority)\n    return app.acquire_token_for_client([&quot;https:\/\/graph.microsoft.com\/.default&quot;])\n\nclient = GraphClient(acquire_token)\n\nteam_id = &quot;your-team-id&quot;\nchannel_id = &quot;your-channel-id&quot;\n\nclient.teams[team_id].channels[channel_id].messages.add(\n    subject=&quot;Automated Alert&quot;,\n    body=&quot;The nightly reconciliation completed with 0 errors.&quot;\n).execute_query()\n<\/code><\/pre>\n<h3 id=\"common-teams-automation-scenarios\">Common Teams automation scenarios<\/h3>\n<ul>\n<li>Posting daily status updates from a Python monitoring script to a DevOps channel<\/li>\n<li>Creating a new Team automatically when a client matter is opened in your practice management system<\/li>\n<li>Adding or removing members from a Team when staff join or leave a project<\/li>\n<li>Sending approval request messages with Adaptive Cards via the Graph API<\/li>\n<\/ul>\n<p>For law firms and accounting practices, Teams automation pairs naturally with <a href=\"https:\/\/taxbowl.com\/solutions\/law-firms\" rel=\"nofollow noopener noreferrer\" target=\"_blank\">bookkeeping workflow automation<\/a> to notify the right people the moment a document is ready for review, without anyone manually checking a queue.<\/p>\n<hr>\n<h2 id=\"key-takeaways\">Key Takeaways<\/h2>\n<p>Production Microsoft 365 automation with Python requires three things working together: proper app registration in Microsoft Entra, MSAL-managed OAuth2 authentication, and the right SDK for each service.<\/p>\n<table>\n<thead>\n<tr>\n<th>Point<\/th>\n<th>Details<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Use established SDKs<\/td>\n<td>Microsoft Graph SDK and Office365-REST-Python-Client eliminate custom OAuth2 complexity and reduce connection bugs.<\/td>\n<\/tr>\n<tr>\n<td>Refresh tokens expire<\/td>\n<td>MSAL refresh tokens expire after 90 days; persist the token cache to prevent silent automation failures.<\/td>\n<\/tr>\n<tr>\n<td>Azure hosts Python for Power Automate<\/td>\n<td>Power Automate Cloud requires Azure Automation or Azure Functions to execute Python scripts.<\/td>\n<\/tr>\n<tr>\n<td>Least-privilege permissions<\/td>\n<td>Request only the Graph API scopes each script needs; broad permissions increase security exposure.<\/td>\n<\/tr>\n<tr>\n<td>Hybrid architecture wins<\/td>\n<td>Combine Power Automate event triggers with Azure-hosted Python logic for production-grade, event-driven workflows.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<hr>\n<p><em>If your firm is running Microsoft 365 Copilot licenses alongside Python automation and not seeing measurable ROI, Gozera can help. Gozera\u2019s consulting practice measures actual Copilot usage via telemetry, identifies dormant licenses, and rebuilds workflows with Python and n8n to generate recoverable billable time. Visit <a href=\"https:\/\/gozera.ai\" target=\"_blank\" rel=\"noopener\">Gozera<\/a> to see how mid-market professional services firms turn idle licenses into documented productivity gains.<\/em><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/csuxjmfbwmkxiegfpljm.supabase.co\/storage\/v1\/object\/public\/blog-images\/organization-42891\/1783398003486_gozera.jpg\" alt=\"https:\/\/gozera.ai\"><\/p>\n<h2 id=\"recommended\">Recommended<\/h2>\n<ul>\n<li><a href=\"https:\/\/gozera.ai\/blog\" target=\"_blank\" rel=\"noopener\">Zera Consulting \u2013 Microsoft 365 Copilot ROI and adoption insights for mid-market professional services<\/a><\/li>\n<li><a href=\"https:\/\/gozera.ai\/blog\/ai-automation-consulting-for-mid-market-firms-in-2026\" target=\"_blank\" rel=\"noopener\">AI Automation Consulting for Mid-Market Firms in 2026<\/a><\/li>\n<li><a href=\"https:\/\/gozera.ai\/blog\/microsoft-365-copilot-user-license\" target=\"_blank\" rel=\"noopener\">Microsoft 365 Copilot User License: IT Manager\u2019s Guide \u2013 Zera Consulting<\/a><\/li>\n<li><a href=\"https:\/\/gozera.ai\/blog\/co-pilot-coaching-microsoft-365\" target=\"_blank\" rel=\"noopener\">Co Pilot Coaching for Microsoft 365: 2026 Guide \u2013 Zera Consulting<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Discover how to achieve effective Microsoft 365 automation with Python. Streamline Outlook, SharePoint, Teams, and more, effortlessly.<\/p>\n","protected":false},"author":1,"featured_media":111,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-107","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Microsoft 365 Automation with Python: 2026 Production Guide<\/title>\n<meta name=\"description\" content=\"Discover how to achieve effective Microsoft 365 automation with Python. Streamline Outlook, SharePoint, Teams, and more, effortlessly.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Microsoft 365 Automation with Python: 2026 Production Guide\" \/>\n<meta property=\"og:description\" content=\"Discover how to achieve effective Microsoft 365 automation with Python. Streamline Outlook, SharePoint, Teams, and more, effortlessly.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/\" \/>\n<meta property=\"og:site_name\" content=\"Zera Consulting\" \/>\n<meta property=\"article:published_time\" content=\"2026-07-23T02:27:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/gozera.ai\/blog\/wp-content\/uploads\/2026\/07\/1784475031387_Professional-woman-coding-Microsoft-365-automation.jpeg\" \/>\n\t<meta property=\"og:image:width\" content=\"1260\" \/>\n\t<meta property=\"og:image:height\" content=\"720\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"zeraconsulting\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"zeraconsulting\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/\"},\"author\":{\"name\":\"zeraconsulting\",\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/#\\\/schema\\\/person\\\/7777d5b5b3475c673677bf0a07ecb4b0\"},\"headline\":\"Microsoft 365 Automation with Python: 2026 Production Guide\",\"datePublished\":\"2026-07-23T02:27:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/\"},\"wordCount\":2173,\"image\":{\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/1784475031387_Professional-woman-coding-Microsoft-365-automation.jpeg\",\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/\",\"url\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/\",\"name\":\"Microsoft 365 Automation with Python: 2026 Production Guide\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/1784475031387_Professional-woman-coding-Microsoft-365-automation.jpeg\",\"datePublished\":\"2026-07-23T02:27:16+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/#\\\/schema\\\/person\\\/7777d5b5b3475c673677bf0a07ecb4b0\"},\"description\":\"Discover how to achieve effective Microsoft 365 automation with Python. Streamline Outlook, SharePoint, Teams, and more, effortlessly.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/#primaryimage\",\"url\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/1784475031387_Professional-woman-coding-Microsoft-365-automation.jpeg\",\"contentUrl\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/1784475031387_Professional-woman-coding-Microsoft-365-automation.jpeg\",\"width\":1260,\"height\":720,\"caption\":\"Professional woman coding Microsoft 365 automation\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/microsoft-365-automation-with-python\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Microsoft 365 Automation with Python: 2026 Production Guide\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/\",\"name\":\"Zera Consulting\",\"description\":\"Microsoft 365 Copilot ROI and adoption insights for mid-market professional services\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/#\\\/schema\\\/person\\\/7777d5b5b3475c673677bf0a07ecb4b0\",\"name\":\"zeraconsulting\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ba8b1ba6b449ed5c82c9b2b89716ea683b319e8ca3e9f626179384748b7b775?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ba8b1ba6b449ed5c82c9b2b89716ea683b319e8ca3e9f626179384748b7b775?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ba8b1ba6b449ed5c82c9b2b89716ea683b319e8ca3e9f626179384748b7b775?s=96&d=mm&r=g\",\"caption\":\"zeraconsulting\"},\"sameAs\":[\"https:\\\/\\\/gozera.ai\\\/blog\"],\"url\":\"https:\\\/\\\/gozera.ai\\\/blog\\\/author\\\/zeraconsulting\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Microsoft 365 Automation with Python: 2026 Production Guide","description":"Discover how to achieve effective Microsoft 365 automation with Python. Streamline Outlook, SharePoint, Teams, and more, effortlessly.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/","og_locale":"en_US","og_type":"article","og_title":"Microsoft 365 Automation with Python: 2026 Production Guide","og_description":"Discover how to achieve effective Microsoft 365 automation with Python. Streamline Outlook, SharePoint, Teams, and more, effortlessly.","og_url":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/","og_site_name":"Zera Consulting","article_published_time":"2026-07-23T02:27:16+00:00","og_image":[{"width":1260,"height":720,"url":"https:\/\/gozera.ai\/blog\/wp-content\/uploads\/2026\/07\/1784475031387_Professional-woman-coding-Microsoft-365-automation.jpeg","type":"image\/jpeg"}],"author":"zeraconsulting","twitter_card":"summary_large_image","twitter_misc":{"Written by":"zeraconsulting","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/#article","isPartOf":{"@id":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/"},"author":{"name":"zeraconsulting","@id":"https:\/\/gozera.ai\/blog\/#\/schema\/person\/7777d5b5b3475c673677bf0a07ecb4b0"},"headline":"Microsoft 365 Automation with Python: 2026 Production Guide","datePublished":"2026-07-23T02:27:16+00:00","mainEntityOfPage":{"@id":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/"},"wordCount":2173,"image":{"@id":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/#primaryimage"},"thumbnailUrl":"https:\/\/gozera.ai\/blog\/wp-content\/uploads\/2026\/07\/1784475031387_Professional-woman-coding-Microsoft-365-automation.jpeg","inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/","url":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/","name":"Microsoft 365 Automation with Python: 2026 Production Guide","isPartOf":{"@id":"https:\/\/gozera.ai\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/#primaryimage"},"image":{"@id":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/#primaryimage"},"thumbnailUrl":"https:\/\/gozera.ai\/blog\/wp-content\/uploads\/2026\/07\/1784475031387_Professional-woman-coding-Microsoft-365-automation.jpeg","datePublished":"2026-07-23T02:27:16+00:00","author":{"@id":"https:\/\/gozera.ai\/blog\/#\/schema\/person\/7777d5b5b3475c673677bf0a07ecb4b0"},"description":"Discover how to achieve effective Microsoft 365 automation with Python. Streamline Outlook, SharePoint, Teams, and more, effortlessly.","breadcrumb":{"@id":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/#primaryimage","url":"https:\/\/gozera.ai\/blog\/wp-content\/uploads\/2026\/07\/1784475031387_Professional-woman-coding-Microsoft-365-automation.jpeg","contentUrl":"https:\/\/gozera.ai\/blog\/wp-content\/uploads\/2026\/07\/1784475031387_Professional-woman-coding-Microsoft-365-automation.jpeg","width":1260,"height":720,"caption":"Professional woman coding Microsoft 365 automation"},{"@type":"BreadcrumbList","@id":"https:\/\/gozera.ai\/blog\/microsoft-365-automation-with-python\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/gozera.ai\/blog\/"},{"@type":"ListItem","position":2,"name":"Microsoft 365 Automation with Python: 2026 Production Guide"}]},{"@type":"WebSite","@id":"https:\/\/gozera.ai\/blog\/#website","url":"https:\/\/gozera.ai\/blog\/","name":"Zera Consulting","description":"Microsoft 365 Copilot ROI and adoption insights for mid-market professional services","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/gozera.ai\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/gozera.ai\/blog\/#\/schema\/person\/7777d5b5b3475c673677bf0a07ecb4b0","name":"zeraconsulting","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/4ba8b1ba6b449ed5c82c9b2b89716ea683b319e8ca3e9f626179384748b7b775?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/4ba8b1ba6b449ed5c82c9b2b89716ea683b319e8ca3e9f626179384748b7b775?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/4ba8b1ba6b449ed5c82c9b2b89716ea683b319e8ca3e9f626179384748b7b775?s=96&d=mm&r=g","caption":"zeraconsulting"},"sameAs":["https:\/\/gozera.ai\/blog"],"url":"https:\/\/gozera.ai\/blog\/author\/zeraconsulting\/"}]}},"_links":{"self":[{"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/posts\/107","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/comments?post=107"}],"version-history":[{"count":1,"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/posts\/107\/revisions"}],"predecessor-version":[{"id":109,"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/posts\/107\/revisions\/109"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/media\/111"}],"wp:attachment":[{"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/media?parent=107"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/categories?post=107"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gozera.ai\/blog\/wp-json\/wp\/v2\/tags?post=107"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}