agentsclimarketplace

Outlook cli skill

Skill ob-cheng/outlook-cli-skill

Use when checking email, inbox, mail, or messages — finding, searching, reading, sending, replying, or forwarding emails. Also use for scheduling meetings or appointments, checking calendar or availability, managing tasks, todos, or notes in Outlook. Covers exporting emails to markdown/JSON, listing folders, managing contacts, and multi-account routing. Trigger phrases: check my inbox, emails from X, send email to, schedule meeting, my calendar, create task, my todos, export emails, what's in my mail, do I have anything tomorrow, any new messages. Works on Windows/WSL via COM automation — no Azure, OAuth, or API keys needed.From its SKILL.md

Install
npx -y skills add ob-cheng/outlook-cli-skill

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

13.3 KB, ~2.7k tokens by cl100k_base, as published. Nobody here has run it

Outlook CLI Skill

AI-friendly CLI for Microsoft Outlook. Works via COM automation — no Azure setup, no OAuth, no API keys. Windows/WSL only.

Installation, setup, and updates: See docs/install.md. WSL setup: See docs/wsl.md for the OUTLOOK_CLI_PYTHON workaround. Feature deep-dive: See references/features.md for internal behavior, export lifecycle, content processing, and multi-account handling.

Strategy

Search -> Read -> Act. Find emails first, then read details, then reply/forward/export.

Always add --json for structured output when processing programmatically.

Quick Reference

Run all commands using ${OUTLOOK_CLI_PYTHON:-python} (set only in WSL; falls back to python on native Windows):

IntentCommand
Find emails${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" search [options]
Read email${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" read <id> --json
Send email${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" send --to X --subject Y --body Z
Reply${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" reply <id> --body "text" [--all] [--cc X]
Forward${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" forward <id> --to X
Calendar${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" cal list/read/create/delete
Tasks${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" tasks list/read/create/complete/delete
Notes${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" notes list/read/create/delete
Export${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" export --output DIR [--format json] [--batch] [--stdout]
Folders${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" folders [--json] [--refresh]
People${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" people list/lookup/add
Config${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" config show/set/clear
Batch${OUTLOOK_CLI_PYTHON:-python} "${SKILL_DIR}/outlook.py" batch --commands '[...]'

Draft Workflow

Before every send/reply/forward:

  1. Run outlook.py config show to read all settings (see references/config.md)
  2. Compose the email body
  3. If draft_instructions is set → follow them while drafting
  4. If humanizer_enabled is true → load humanizer skill and run the pattern checklist
  5. Pass the final body to the CLI

The CLI prints status tags so skipped steps are visible in the output.

People Directory

The CLI auto-tracks every person encountered in email interactions — sender, recipients, CC — via python outlook.py read. Unknown people are automatically added to ~/.outlook-cli/people.json.

After every email interaction (any time you have an email in context — search results, read output, a composed send/reply/forward), scan the participants and run:

# Check if this person is already known
python outlook.py people lookup "Name"
python outlook.py people lookup [email protected]

# If not found, add them (but only for people you haven't already handled via cmd_read)
python outlook.py people add "Full Name" [email protected]

The read command handles this automatically — unknown participants are added and reported. For send/reply/forward, manually check since those involve the recipients you're sending to.

Whenever the user refers to someone by name (e.g. "email Alice about the report"), look them up:

python outlook.py people lookup "Alice"

If found, you have their email. If not found, ask the user for the email and save it. To view all known people:

python outlook.py people list [--json]

Common Patterns

These cover 80% of agent tasks without needing extra reference files.

Quick inbox scan

# First N unread, last day only (fast on large inboxes)
python outlook.py search --unread --days 1 --limit 10 --json

Find emails from someone

python outlook.py search --filter-email "[email protected]" --days 7 --json

Find emails by name (unknown email)

# --filter-email matches SMTP addresses only. When you only know the name:
# Step 1: discover accounts
python outlook.py folders --json
# Step 2: search broadly in the right account's inbox, then inspect sender_clean
python outlook.py search --folder "[email protected]/Inbox" --days 7 --json
# Step 3: or narrow by domain when you know the organization
python outlook.py search --folder "[email protected]/Inbox" --days 7 --filter-domain "alcon.com" --json

Reply with extra CC

python outlook.py reply <id> --body "My reply" --cc "[email protected],[email protected]"

Reply all vs. reply

Use --all judiciously — the default reply goes only to the sender, which can silently drop stakeholders from group threads.

  • Use --all for group discussions to keep all participants in the loop
  • Use regular reply when the response is only relevant to the sender
  • When asking a specific person a question in a group thread, still use --all to maintain transparency
  • Exception: sensitive or private matters should use regular reply
# Reply to sender only (default)
python outlook.py reply <id> --body "Thanks, got it"

# Reply to all participants
python outlook.py reply <id> --body "Here's the update for everyone" --all

# Reply to all + extra recipients
python outlook.py reply <id> --body "Adding legal to the loop" --all --cc "[email protected]"

Export to markdown or JSON

# Markdown files
python outlook.py export --output ./inbox-export --filter-email "[email protected]" --days 7

# Single JSON file, token-efficient
python outlook.py export --output ./data --format json --batch --days 30

# Direct JSON to stdout (no files, best for AI pipelines)
python outlook.py export --output . --stdout --days 7

Task management

python outlook.py tasks list --json
python outlook.py tasks create --subject "Review PR" --due 2026-05-15 --priority high
python outlook.py tasks complete <task-id>

Calendar today

python outlook.py cal list --json

Multi-account: always discover folders first

# See what accounts are connected (cached after first run — instant thereafter)
python outlook.py folders
# Force a full refresh if you've added/removed accounts
python outlook.py folders --refresh
# Then target a specific account
python outlook.py search --folder "[email protected]/Inbox" --filter-email "[email protected]"

Batch mode (multi-command single process)

# Run multiple commands in one Python process — avoids 0.34s cold-start per extra command.
# Each inner array is [command, ...args]. Output is a JSON envelope with per-command results.
python outlook.py batch --commands '[
  ["search", "--unread", "--days", "1", "--limit", "5", "--json"],
  ["tasks", "list", "--json"],
  ["cal", "list", "--json"]
]'

Prefer batch when you know the full command pipeline upfront (e.g., search → read → reply). Saves ~40% on 3-command workflows vs. separate invocations.

Date filtering options

  • --days N — last N days (default 7)
  • --from-date YYYY-MM-DD --to-date YYYY-MM-DD — exact range (overrides --days)
  • --limit N — stop after N matches (for huge inboxes)

Known Pitfalls

Large inbox search can be slow

COM iterates every item in the folder. On 1000+ emails, narrow with --days 1 or --limit 20.

Per-command cold-start (~0.5s) and what's fast/slow

Every CLI invocation pays ~0.5s overhead (Python import: 0.34s + COM Dispatch: 0.22s). Three optimizations are baked in:

  • Folder cache (~/.outlook-cli/folder-cache.json): First folders call walks all stores (16-35s). Subsequent calls return from cache instantly (0.45s). Invalidates automatically when store topology changes. --refresh forces a full re-walk.
  • Calendar/tasks summary mode: cal list and tasks list skip expensive COM properties (body, attendees, recurrence details) automatically. cal list: 6s → 0.73s. cal read still returns full detail.
  • Batch mode: Run multiple commands in one Python process. Cuts the 0.5s per-extra-command cold start. 3-command workflows run ~40% faster. Prefer batch when you know the full pipeline upfront (e.g., search → read → reply).

cal create always uses the default delivery store in multi-account profiles

cal create calls outlook.CreateItem(1) which saves to Outlook's default delivery store — not necessarily the account the user considers primary. See references/features.md for the create-event-in-store.py workaround script.

Multi-account: search defaults to primary account

Search/send/export target the default account. Run folders first to see what's connected, then use --folder "AccountName/Inbox" to reach another account.

EntryIDs can change when emails move

If a stored message ID fails to load, re-search to get the current ID — Outlook regenerates EntryIDs on move/archive operations.

Draft-only is the default

All compose commands create drafts. Direct sending requires both send_mode: send in config AND the --send flag.

Safety Rules

Draft-Only Mode: The CLI defaults to draft mode. All send/reply/forward commands create drafts by default.

  • Tell the user: "I've saved this as a draft. You can review and send it from Outlook."
  • To enable direct sending, set config send_mode: send — see references/config.md for the behavior matrix
  • --send is the only way to direct-send. Without it, even with send_mode: send, the email saves as a draft

Always confirm before: deleting events/tasks/notes Never: delete without confirmation, forward sensitive emails without verification

Verification Checklist

  • Ran folders (or used cache) to know which accounts are connected
  • Used --json for structured output when parsing programmatically
  • People directory checked/updated for any new contacts encountered
  • Draft-only: confirmed email saved as draft (unless --send + send_mode: send)
  • Batch mode used for multi-command workflows (search → read → reply)
  • Narrowed search with --days or --limit on large inboxes

Workflows & patterns: See references/workflows.md. Command details: See references/commands.md when you need all flags/options beyond the Quick Reference table. Config reference: See references/config.md for draft instructions, humanizer, and send mode settings. JSON schemas: See references/json-schemas.md when parsing output programmatically. Troubleshooting: See references/troubleshooting.md when commands fail. Agent ergonomics: See references/agent-ergonomics.md for known agent-side friction points and workarounds.

What ships with it: 65 files

453.0 KB alongside SKILL.md, 50 of them executable

assets/

docs/

25 more files not listed here. See all 65 in the repository.

Keep looking

Skills are one crate of 326,286. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.