Microsoft 365
Microsoft 365 Adapter Architecture
Exchange, Outlook Calendar, and OneDrive — unified through Microsoft Graph API via Azure AD OAuth 2.0
service/calendar.py
adapter/calendar.py
adapter/users.py
MSAL Bearer token
📧 Mail (Exchange / Outlook)
📅 Calendar (Outlook)
📁 OneDrive
👤 Users
📄 SharePoint
What & Why
Microsoft Graph is a single unified REST endpoint for the entire Microsoft 365 surface: Exchange mail, Outlook Calendar, OneDrive, Teams, and user directory data. One OAuth token gives Octopus access to all of them without juggling multiple APIs.
For organizations on the Microsoft stack, this mirrors the Google Workspace integrations (gmail, google-calendar, google-drive) — the adapter → service → auto-generated routes pattern is identical; only the auth layer and downstream API differ.
Key properties of the adapter:
- Azure AD OAuth 2.0 via MSAL (
msalPython library). Supports both delegated (user) and application (tenant-level) permission flows. - Microsoft Graph API v1.0 (
https://graph.microsoft.com/v1.0/) for all calls. - Delta queries for incremental email and calendar sync — only changed items are fetched on subsequent calls.
- Automatic token refresh — the adapter handles
401responses by refreshing the access token and retrying transparently.
Azure AD OAuth Flow
5-step authorization from App Registration to Graph API calls
MICROSOFT_TENANT_ID, MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET. Add redirect URI.POST /v1/oauth/microsoft-365/authorize → Constellation returns an authorization_url pointing to the MSAL authorize endpoint.Mail.Read Mail.Send Calendars.ReadWrite Files.ReadWrite User.Readoauth.py callback. MSAL exchanges the authorization code for an access token + refresh token. Tokens stored in Redis.Authorization: Bearer <access_token> to every httpx request. On 401, MSAL refreshes silently and retries.list_users, directory reads.Methods Reference
Email (Exchange / Outlook)
| Method | Description | Key params |
|---|---|---|
list_emails | List messages in a folder with optional filters | folder (inbox/sent/…), top, skip, search, filter |
get_email | Fetch a single message by ID | message_id |
send_email | Send a new message | to, subject, body, cc, bcc, html (bool) |
reply_to_email | Reply to an existing message | message_id, body, reply_all (bool) |
forward_email | Forward a message to new recipients | message_id, to, comment |
delete_email | Move a message to Deleted Items | message_id |
move_email | Move a message to a different folder | message_id, destination_id |
list_folders | List all mail folders in the mailbox | — |
Calendar (Outlook)
| Method | Description | Key params |
|---|---|---|
list_events | List events in a calendar within a time window | calendar_id, start_time, end_time |
create_event | Create a new calendar event | subject, start, end, attendees, body, calendar_id |
update_event | Update an existing event | event_id, calendar_id, fields to update |
delete_event | Delete an event | event_id, calendar_id |
get_free_busy | Get free/busy schedule for one or more users | schedules (list of emails), start_time, end_time, interval_minutes |
OneDrive
| Method | Description | Key params |
|---|---|---|
list_files | List items in a folder (root by default) | folder_path, top |
get_file | Get metadata for a specific file or folder | item_id or item_path |
upload_file | Upload a file to OneDrive | file_path (local), destination_path, conflict_behavior |
download_file | Download a file from OneDrive | item_id, local_path |
create_folder | Create a new folder | folder_name, parent_path |
Users
| Method | Description | Key params |
|---|---|---|
get_user | Get a specific user's profile from the directory | user_id or user_principal_name |
list_users | List users in the tenant directory | top, filter |
get_user_photo | Get the profile photo of a user | user_id |
Setup
1. Azure AD App Registration
- Go to Azure Portal → Azure Active Directory → App registrations → New registration.
- Set a name (e.g.
octopus-constellation). Choose Accounts in this organizational directory only (single-tenant) or Any Azure AD directory (multi-tenant). - Add a redirect URI:
http://localhost:3007/oauth/microsoft365/callback(web platform). Use your deployed URL in production. - Under Certificates & secrets → create a Client secret. Copy it immediately.
- Under API permissions → Add a permission → Microsoft Graph → Delegated permissions. Add:
Mail.Read,Mail.Send,Mail.ReadWriteCalendars.ReadWriteFiles.ReadWriteUser.Read,User.ReadBasic.All
- Click Grant admin consent for your tenant.
- Note your Tenant ID, Application (client) ID, and the client secret value.
2. Environment variables
# Required
MICROSOFT_TENANT_ID=your-tenant-id
MICROSOFT_CLIENT_ID=your-client-id
MICROSOFT_CLIENT_SECRET=your-client-secret
# Optional (defaults shown)
MICROSOFT_REDIRECT_URI=http://localhost:3007/oauth/microsoft365/callback
Add the same vars to docker-compose.yml under the api service environment block.
3. Verify connection
# Check OAuth status for a user
GET /v1/oauth/microsoft-365/status
# → { "status": "needs_oauth", "authorization_url": "https://login.microsoftonline.com/..." }
# → { "status": "authorized", "user_email": "user@company.com" }
CLI Examples
# List the 20 most recent inbox messages
constellation microsoft-365 list-emails --folder inbox --top 20
# Get a specific email by ID
constellation microsoft-365 get-email --message-id AAMkAGI2...
# Send a new email
constellation microsoft-365 send-email \
--to user@company.com \
--subject "Hello from Octopus" \
--body "Sent via Constellation CLI"
# Reply to a message
constellation microsoft-365 reply-to-email \
--message-id AAMkAGI2... \
--body "Thanks!" \
--reply-all
# List calendar events for May 2026
constellation microsoft-365 list-events \
--start 2026-05-01 \
--end 2026-05-31
# Create a calendar event
constellation microsoft-365 create-event \
--subject "Team Sync" \
--start "2026-05-15T10:00:00" \
--end "2026-05-15T11:00:00" \
--attendees "alice@company.com,bob@company.com"
# Check free/busy for two users
constellation microsoft-365 get-free-busy \
--schedules "alice@company.com,bob@company.com" \
--start 2026-05-15 \
--end 2026-05-15
# List OneDrive root folder
constellation microsoft-365 list-files
# Upload a file to OneDrive
constellation microsoft-365 upload-file \
--file-path ./report.pdf \
--destination-path "Documents/report.pdf"
# List tenant users
constellation microsoft-365 list-users --top 50
HTTP API
# List emails via HTTP
curl -X POST https://api.yourdomain.com/v1/microsoft-365/list-emails \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"folder": "inbox", "top": 10}'
# Response
# {
# "messages": [
# {"id": "AAMkAGI2...", "subject": "Hello", "from": "sender@company.com", "receivedDateTime": "2026-05-12T10:00:00Z", "isRead": false}
# ]
# }
# Send email via HTTP
curl -X POST https://api.yourdomain.com/v1/microsoft-365/send-email \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"to": "user@company.com", "subject": "Hello", "body": "From Octopus"}'
# Create calendar event via HTTP
curl -X POST https://api.yourdomain.com/v1/microsoft-365/create-event \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"subject": "Team Sync", "start": "2026-05-15T10:00:00", "end": "2026-05-15T11:00:00"}'
Auth Reference
# Initiate OAuth flow (returns authorization_url)
POST /v1/oauth/microsoft-365/authorize
# Check authorization status
GET /v1/oauth/microsoft-365/status
# Revoke tokens
DELETE /v1/oauth/microsoft-365/revoke
When a token is missing or expired, any integration call returns:
{
"detail": {
"action": "oauth_required",
"message": "User needs to authorize Microsoft 365 access",
"auth_url": "http://localhost:3007/oauth/microsoft365/authorize?..."
}
}
Direct the user to auth_url to complete the consent flow.
See also: SharePoint