Cross-platform CLI for Microsoft Outlook via the Microsoft Graph API, with dual implementations in Node.js and .NET NativeAOT.
- π§ Email β inbox, read, search, draft, reply, forward, send, move, flag, mark-read
- π Calendar β today, week, date range, view, create events, list calendars
- π₯ Contacts β search contacts and GAL, manage aliases (
fredβfreddie@outlook.com) - π€ Multi-account β personal + work accounts, parent chains, per-account permissions
- π₯ Delegate access β read and send on behalf of other users (
--as fred) - π Watch mode β real-time change tracking via delta queries, rules engine for channel delivery
- π Security β AES-256-GCM encrypted token cache, configurable permissions, forbidden scopes, send_to whitelist, defense-in-depth token validation
- π₯οΈ Cross-platform β Mac, Linux, Windows; device code flow for headless VMs
- π Multiple output formats β text, json, markdown, html
- π€ AI agent integration β OpenClaw / NanoClaw dual-mode (Skill + Channel Factory)
- π COM Bridge β For enterprise environments where Graph API is blocked, connect via Outlook Desktop COM automation on Windows
git clone https://github.com/jeffstall/outlook-cli.git
cd outlook-cli
.\build.ps1 all
build.ps1runsnpm installautomatically and builds both Node.js and .NET NativeAOT for your current OS/architecture. Both implementations share the same config directory (~/.outlook-cli/) and can be used interchangeably. See docs/architecture.md for details.
You need an Azure App Registration (free). See docs/AZURE-SETUP.md for step-by-step instructions. Both accounts below can share the same client ID β each user authenticates independently.
# Add a read/write account
node bin/outlook-cli.js account add work --client-id YOUR_CLIENT_ID
node bin/outlook-cli.js auth login --account work
# Add a read-only account (can read mail but cannot send, draft, move, or delete)
node bin/outlook-cli.js account add monitor --client-id YOUR_CLIENT_ID --read-only
node bin/outlook-cli.js auth login --account monitorEach auth login opens a browser to sign in with a different Microsoft account. Read-only is enforced at two layers: the token only contains read scopes, and the CLI blocks write commands before they reach the API. See docs/usage/account.md for details.
# List recent messages for the read/write account
node bin/outlook-cli.js mail inbox --account work
# Read message #1 (short IDs are assigned by inbox/search commands)
node bin/outlook-cli.js mail read 1 --account work# Compose and send a message from "work" to "monitor"
node bin/outlook-cli.js mail draft --to "monitor@example.com" --subject "Hello from CLI" --body "Testing outlook-cli!" --send --yes --account workReplace
monitor@example.comwith the actual email address of the monitor account. Use--sendto compose and send in one step, or omit it to create a draft you can review first.
# Check the read-only account's inbox
node bin/outlook-cli.js mail inbox --account monitor# List all accounts
node bin/outlook-cli.js account list
# Remove a single account (deletes config and cached tokens)
node bin/outlook-cli.js account remove monitor
# Reset to clean state β remove the entire config directory
# (Windows)
rmdir /s /q "%USERPROFILE%\.outlook-cli"
# (Mac/Linux)
rm -rf ~/.outlook-cliSee docs/usage/account.md for the full account command reference.
| Document | Description |
|---|---|
| docs/usage.md | Complete command-line reference with examples |
| docs/architecture.md | Architecture, config formats, security model, integration |
| docs/src-node.md | Building and testing the Node.js implementation |
| docs/src-dotnet.md | Building and testing the .NET implementation |
| docs/src-tests.md | Test architecture and conventions |
| docs/AZURE-SETUP.md | Azure App Registration setup guide |
| docs/SECURITY.md | Security model and threat analysis |
| docs/MULTI-ACCOUNT.md | Multi-account configuration guide |
| docs/DELEGATE-ACCESS.md | Delegate access setup and usage |
| docs/WATCH-MODE.md | Watch mode and rules engine |
| docs/JSON-INPUT.md | JSON input file schemas for all commands |
| docs/DIRECTORY-STRUCTURE.md | Project directory layout |
| docs/self-hosting.md | Self-hosting guide including COM Bridge deployment |
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β outlook-cli β
ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ€
β Node.js (ESM) β .NET 8 (NativeAOT) β
β Commander.js CLI β System.CommandLine CLI β
β @azure/msal-node β MSAL.NET β
β Direct HTTP Graph β Direct HTTP Graph β
ββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββ€
β Shared Configuration β
β ~/.outlook-cli/accounts.json β
β ~/.outlook-cli/aliases.json β
β ~/.outlook-cli/cache-*.enc (AES-256-GCM) β
β ~/.outlook-cli/delta-*.json β
ββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β (provider = "bridge" in accounts.json)
ββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ
β COM Bridge (optional) β
β src/bridge/ β Windows-only ASP.NET Core server β
β COM automation β Outlook Desktop β Exchange β
β HMAC-SHA256 authenticated HTTP API β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Both implementations produce identical CLI behavior and share all configuration files. You can switch between them freely.
You need a free App Registration in Microsoft Entra ID. See docs/AZURE-SETUP.md for step-by-step instructions.
Required permissions:
| Permission | Purpose |
|---|---|
User.Read |
Read user profile |
Mail.Read |
Read email messages |
Mail.ReadWrite |
Create drafts, move, flag, mark-read |
Calendars.Read |
Read calendar events |
Calendars.ReadWrite |
Create calendar events |
offline_access |
Refresh tokens for persistent sessions |
Optional permissions:
| Permission | Purpose |
|---|---|
Mail.Send |
Send email from own account |
Mail.Send.Shared |
Send on behalf of delegate mailbox owner |
Mail.Read.Shared |
Read delegate mailbox |
Mail.ReadWrite.Shared |
Write to delegate mailbox |
Calendars.Read.Shared |
Read delegate calendar |
Security note: Permissions are configurable per account via
accounts.json. The security model supports forbidden scopes and send_to recipient whitelists. See docs/SECURITY.md.
- Read-only accounts β Restrict accounts to read-only operations with
--read-only(setup guide) - Configurable permissions β Each account defines allowed/forbidden scopes in
accounts.json - Forbidden scopes β Block specific permissions (e.g.,
Mail.Send) at the config level - send_to whitelist β Restrict which recipients can receive mail from a given account
- Defense-in-depth token validation β Tokens are inspected at runtime to enforce permission policy
- Encrypted token cache β AES-256-GCM encryption, PBKDF2 SHA-512 with 310,000 iterations
- Confirmation prompts β Write operations require confirmation (bypass with
--yesfor scripting)
See docs/SECURITY.md for the full threat model.
outlook-cli operates in two modes for AI agent integration:
- Skill mode β Agents invoke CLI commands and parse JSON output
- Channel Factory mode β Watch rules engine normalizes incoming emails to channel messages, delivered via stdout / webhook / exec / file
# OpenClaw β symlink as a skill
ln -s /path/to/outlook-cli/skill ~/.openclaw/skills/outlook
# NanoClaw β install in container
git clone https://github.com/jeffstall/outlook-cli.git /opt/outlook-cli
cd /opt/outlook-cli && npm install && npm linkSee skill/SKILL.md and skill/NANOCLAW.md.
| Variable | Description | Default |
|---|---|---|
OUTLOOK_CLI_CLIENT_ID |
Azure app client ID | (none) |
OUTLOOK_CLI_TENANT_ID |
Azure AD tenant ID | common |
OUTLOOK_CLI_PASSPHRASE |
Token cache encryption passphrase | Machine-derived |
OUTLOOK_CLI_LOG_LEVEL |
Logging level | warn |
All configuration is stored in ~/.outlook-cli/:
| File | Purpose |
|---|---|
accounts.json |
Account definitions, permissions, defaults |
aliases.json |
Contact aliases |
cache-*.enc |
Encrypted MSAL token cache |
delta-*.json |
Watch mode delta tokens |
config.json |
Optional global configuration |
# Node.js
npm install
npm test # 160+ tests via vitest
node bin/outlook-cli.js --help
# .NET
dotnet build src/dotnet/OutlookCli.csproj
dotnet run --project src/dotnet -- --help
# Both (unified build script)
.\build.ps1 allSee docs/src-node.md, docs/src-dotnet.md, and docs/src-tests.md.
MIT β see LICENSE