Outlook 365 CLI — read, send, and manage emails from the terminal
Project description
outlook-cli
Read, send, and manage Outlook 365 emails, calendar events, and contacts from the terminal.
Uses OWA bearer token authentication via Playwright — no admin consent or API keys required.
Disclaimer: This is an unofficial, community-driven project. It is not affiliated with, endorsed by, or supported by Microsoft Corporation. "Outlook" and "Microsoft 365" are trademarks of Microsoft Corporation.
This tool accesses Microsoft Outlook services using intercepted browser tokens and, in some cases, undocumented internal APIs (OWA
service.svc). Use of this tool may violate Microsoft's Terms of Service or your organization's acceptable use policies. The authors accept no responsibility for account suspensions, data loss, or other consequences arising from the use of this tool.Use at your own risk. This software is provided "as is", without warranty of any kind. See LICENSE for details.
Install
pip install -e .
playwright install chromium
Auth
outlook login # opens browser, captures token automatically
outlook login --force # force re-login, ignore saved session
outlook whoami # verify current user
Token is cached at ~/.cache/outlook-cli/token.json. Auto re-login on 401.
You can also set OUTLOOK_TOKEN env var directly.
Usage
Inbox
outlook inbox # list inbox (shows unread/total count)
outlook inbox --unread # unread only
outlook inbox -n 10 # last 10 messages
outlook inbox --from "john" # filter by sender
outlook inbox --subject "report" # filter by subject
outlook inbox --after 2026-03-01 # after date
outlook inbox --before 2026-03-08 # before date
outlook inbox --has-attachments # only with attachments
outlook inbox --category "Urgent" # filter by category
outlook inbox --no-category # only uncategorized messages
outlook inbox -n 50 --no-category # find 50 uncategorized messages
Read / Search / Thread
outlook read 3 # read message #3
outlook read 3 --raw # raw HTML body
outlook thread 3 # full conversation thread for message #3
outlook search "keyword" # search messages
outlook search "from:john" --max 10
Send / Reply / Forward
All send commands show a confirmation prompt before sending. Use -y to skip.
outlook send "to@email.com" "Subject" "Body"
outlook send "a@b.com,c@d.com" "Subject" "Body" --cc e@f.com -y
outlook send "to@email.com" "Subject" "Body" --signature MySignature
outlook send "to@email.com" "Subject" "<h1>HTML</h1>" --html -s MySignature
outlook reply 3 "Thanks!"
outlook reply 3 "Thanks!" --all
outlook reply-draft 3 # create reply draft without sending
outlook reply-draft 3 "Will check" --all # reply-all draft with body
outlook reply-draft 3 "<p>HTML</p>" --html # HTML body (preserves quoted original)
outlook reply-draft 3 "Body" -s MySignature # reply draft with signature
outlook forward 3 "to@email.com" --comment "FYI"
Drafts
outlook draft "to@email.com" "Subject" "Body" # create draft
outlook draft "to@email.com" "Subject" "Body" --cc e@f.com # draft with CC
outlook draft "to@email.com" "Subject" "Body" -s MySignature # draft with signature
outlook draft-send 3 # send a draft (with confirmation)
outlook draft-send 3 -y # send without confirmation
Scheduled Send
outlook schedule "to@email.com" "Subject" "Body" "+1h" # send in 1 hour
outlook schedule "to@email.com" "Subject" "Body" "+30m" -y # 30 min, skip confirm
outlook schedule "to@email.com" "Subject" "Body" "tomorrow 09:00"
outlook schedule "to@email.com" "Subject" "Body" "2026-03-15T10:00"
outlook schedule "to@email.com" "Subject" "Body" "+2h30m" --html -s MySignature
outlook schedule-draft 3 "+1h" # schedule an existing draft
outlook schedule-draft 3 "tomorrow 09:00" # schedule reply draft for morning
outlook schedule-list # list scheduled emails
outlook schedule-list --json
outlook schedule-cancel 1 # cancel by list number
outlook schedule-cancel 1 -y # skip confirmation
Time formats: +30m, +1h, +2h30m, today 17:00, tomorrow 09:00, 2026-03-15T10:00.
Folders
outlook folders # list folders with counts
outlook folder Archive -n 20 # messages in a folder
outlook folder Archive --category "Urgent" # filter by category
outlook move 3 Archive # move message to folder
outlook move 3 4 5 Archive # move multiple messages
Categories
outlook categories # list categories with counts
outlook categorize 3 "FYI" # add category to message
outlook categorize 3 4 5 "FYI" # add to multiple messages
outlook uncategorize 3 "FYI" # remove category from message
outlook uncategorize 3 4 5 "FYI" # remove from multiple messages
outlook category-create "New Category" # create master category
outlook category-create "Urgent" --color 0 # create with color (0-24)
outlook category-rename "FYI" "Info" # rename + update all messages
outlook category-rename "FYI" "Info" --no-propagate # master list only
outlook category-clear "FYI" # remove category from all messages
outlook category-clear "FYI" -n 20 # remove from max 20 messages
outlook category-clear "FYI" --folder Inbox # remove only in Inbox
outlook category-delete "Old" -y # delete master + clear all messages
outlook category-delete "Old" --no-propagate -y # delete master only
Signatures
outlook signature-pull -n MySignature # extract signature from sent emails
outlook signature-list # list saved signatures
outlook signature-show MySignature # preview a signature
outlook signature-delete MySignature # delete a saved signature
Signatures are saved as HTML in ~/.config/outlook-cli/signatures/. Set a default in config:
default_signature: MySignature
Management
outlook mark-read 3 # mark as read
outlook mark-read 3 4 5 # mark multiple as read
outlook mark-read 3 --unread # mark as unread
outlook delete 3 # delete (with confirmation)
outlook delete 3 4 5 -y # delete multiple without confirmation
Calendar
outlook calendar # next 7 days
outlook calendar --days 14 # next 14 days
outlook calendar --calendar "John Smith" # view a shared calendar
Events
outlook event 42 # view event details (attendees, recurrence, etc.)
# Create
outlook event-create "Meeting" "2026-03-16 10:00" "2026-03-16 11:00"
outlook event-create "Meeting" "tomorrow 14:00" "+1h" \
-a john@example.com -a jane@example.com \
-l "Room A" -b "Agenda: Q1 review" -y
outlook event-create "Standup" "2026-03-16 09:00" "2026-03-16 09:30" \
--teams -a team@example.com # Teams online meeting
# Recurring events
outlook event-create "Weekly Sync" "2026-03-16 10:00" "2026-03-16 11:00" \
--repeat weekly --repeat-count 8 -a team@example.com
outlook event-create "Daily Standup" "2026-03-16 09:00" "2026-03-16 09:15" \
--repeat daily --repeat-until 2026-04-30
outlook event-create "Sprint Review" "2026-03-16 14:00" "2026-03-16 15:00" \
--repeat weekly --repeat-days Monday,Wednesday --repeat-count 12
outlook event-create "Monthly Report" "2026-03-16 10:00" "2026-03-16 11:00" \
--repeat monthly --repeat-count 6
# Update
outlook event-update 42 --subject "New Title"
outlook event-update 42 --start "2026-03-16 14:00" --end "2026-03-16 15:00"
outlook event-update 42 --location "Room B"
outlook event-update 42 --add-attendee new@example.com
outlook event-update 42 --remove-attendee old@example.com
# Delete
outlook event-delete 42 # delete single event/occurrence
outlook event-delete 42 --series # delete entire recurring series
outlook event-delete 42 43 44 -y # delete multiple
# Respond to invitations
outlook event-respond 42 accept
outlook event-respond 42 decline --comment "Can't make it"
outlook event-respond 42 tentative --silent # don't notify organizer
# Recurring event instances
outlook event-instances 42 # list all occurrences (90 days)
outlook event-instances 42 --days 180 # look further ahead
Calendars / Free-Busy / People
outlook calendars # list all calendars (own + shared)
outlook free-busy "john@example.com" tomorrow
outlook free-busy "a@b.com,c@d.com" 2026-03-16 -d 30 # 30-min slots
outlook people-search "john" # find people for attendee autocomplete
outlook people-search "john" --max 5
Attachments / Contacts
outlook attachments 3 # list attachments
outlook attachments 3 -d # download all
outlook contacts
JSON Output
Auto-JSON on pipe: When stdout is piped, JSON output is automatic — no --json flag needed.
outlook inbox | jq '.data[0].subject' # auto-JSON when piped
outlook inbox --json # explicit JSON in terminal
outlook inbox --json -o emails.json # save to file
All JSON output uses a structured envelope:
{"ok": true, "schema_version": "1", "data": [...]}
How It Works
outlook loginopens Chromium via Playwright- Intercepts the OWA bearer token from network requests
- Uses the token against Outlook REST API v2 (
outlook.office.com/api/v2.0/) - Category management uses OWA
service.svc(reverse-engineeredUpdateMasterCategoryList) - Messages get short display numbers (#1, #2...) mapped to real Outlook IDs
- Auto re-login on token expiry via cached browser SSO state
Security Notice
This tool caches sensitive authentication data on your local machine:
- Bearer token (
~/.cache/outlook-cli/token.json) — grants full access to your mailbox, calendar, and contacts until it expires. Protect this file as you would a password. - Browser session state (
~/.cache/outlook-cli/browser-state.json) — contains cookies and SSO state that can be used to obtain new tokens without re-authentication.
Both files are created with 600 permissions (owner-only read/write) on Unix systems. Never share these files or commit them to version control.
To revoke access, delete the cache directory:
rm -rf ~/.cache/outlook-cli/
Undocumented API Notice
Category management commands (categories, category-create, category-delete, category-rename) use a reverse-engineered OWA internal endpoint (service.svc) that is not a public or documented Microsoft API. These endpoints may change or stop working at any time without notice. All other commands use the Outlook REST API v2.0, which is a documented (though deprecated in favor of Microsoft Graph) API.
Config
~/.config/outlook-cli/config.yaml:
max_messages: 25
default_folder: Inbox
default_signature: null # set to signature name for auto-append
timezone: UTC # Microsoft timezone ID for calendar operations
browser:
headless: false
timeout: 120
output_format: table
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file outlook365_cli-0.1.1.tar.gz.
File metadata
- Download URL: outlook365_cli-0.1.1.tar.gz
- Upload date:
- Size: 76.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21b2c312357f642a46a8b7ce930ccdb11841aca759ffdb99d01d6e2f69a33409
|
|
| MD5 |
677fd9cd2ad03cfeb1c5726de1d23931
|
|
| BLAKE2b-256 |
78f5ce875e3712c417df4b741ea53a6245270dd1f509bdb41ee90e1253bd3967
|
File details
Details for the file outlook365_cli-0.1.1-py3-none-any.whl.
File metadata
- Download URL: outlook365_cli-0.1.1-py3-none-any.whl
- Upload date:
- Size: 50.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f83cf4da6af3aa918d03b5ccca09011b5f01d1c782d30bddf2db576299dfdee
|
|
| MD5 |
7e15a4ca231a14260feb8dab3276bf8c
|
|
| BLAKE2b-256 |
4c7e66fc3e7e351b35d52fa42012f38dda144e0824ba5f58675e3ea8d03bae6c
|