I work on a locked-down enterprise Windows machine. Can't register an Azure app. Can't install browser extensions. Managed device — IT controls what's approved.
I still needed Claude Code to read and draft my emails.
The fix turned out to be simpler than I expected.
What COM automation actually is
Outlook Desktop on Windows exposes a COM interface. It's been there since the 90s. Any program running on the same machine can connect to it, provided Outlook is open and signed in.
That's the whole authentication model: if Outlook is running, you're in.
pywin32 wraps this interface in Python:
import win32com.client
outlook = win32com.client.Dispatch("Outlook.Application")
inbox = outlook.GetNamespace("MAPI").GetDefaultFolder(6)
One import. One dispatch call. You're talking to Outlook and you have access to almost anything you can do with a mouse and keyboard.
The bridge pattern
Claude wrote a single Python file — outlook_bridge.py — that exposes Outlook commands as CLI subcommands and returns JSON.
Claude Code calls it via Bash:
python outlook_bridge.py list --count 10 --pretty
python outlook_bridge.py search "renewal" --folder inbox
python outlook_bridge.py reply <entry_id> --body "Noted, will revert." --draft
Output:
[
{
"Subject": "Q2 renewal — action required",
"SenderName": "Alice Tan",
"ReceivedTime": "2026-06-12T09:14:00",
"Unread": true,
"BodyPreview": "Following up on the renewal terms we discussed..."
}
]
Claude processes the JSON, reasons over it, and calls the next command in the chain. Read a thread for context → draft a reply → hand it back for review. All without leaving the Claude Code conversation.
Why not MCP?
I considered it. MCP is worth it when you need a long-running server process and cross-client compatibility.
For this use case, it wasn't worth it — for three reasons.
COM object lifetime. A long-running MCP server has to maintain the COM connection across calls, handle Outlook restarts, and manage session state. A direct Bash call has none of that: Claude shells out, Python grabs the running Outlook process, JSON comes back, process exits cleanly.
Rate limits. MCP servers that wrap an API (like Microsoft Graph) inherit that API's throttling. Broad-spectrum queries — pulling a large folder, searching across multiple mailboxes — hit those limits fast. The bridge talks directly to the local COM interface. No API in the middle, no rate limit.
Token efficiency. The bridge returns exactly what I define: a JSON object with the fields I want. MCP tool responses carry protocol overhead on top of the payload. For high-frequency operations inside a single conversation, that adds up.
One Python file. No daemon. No protocol overhead.
If the constraints above don't apply to your setup, an MCP server is a reasonable alternative. For a local single-user workflow on Windows, this is the shorter path.
Why not Microsoft Graph?
Graph works cross-platform and headless. The trade-off: Azure app registration, OAuth consent flow, ongoing token refresh. On a managed enterprise device, that registration process may not be available to you.
COM requires none of it. You're riding the session that's already open on your machine.
The permission setup
One entry in .claude/settings.json:
{
"permissions": {
"allow": ["Bash(python *outlook_bridge.py*:*)"]
}
}
Claude can call the bridge and nothing else. No open-ended Bash access required.
send, reply, and forward all work. My default is --draft — Claude saves to Drafts and I review before sending. Accidental sends are still a real risk when you're chaining operations inside a conversation. The CLAUDE_INTEGRATION.md in the repo has a CLAUDE.md snippet that sets draft-by-default as a standing instruction.
What it covers
-
list— recent emails in any folder -
search— by keyword, sender, subject -
read— full body + attachment list -
send/reply/reply-all/forward— with--draftsupport -
move/delete -
cal-list— calendar events in a date range, including shared calendars
Limits
Worth stating plainly:
- Windows only. COM is a Windows interface.
- Classic Outlook Desktop App only — not the new Outlook web wrapper, not OWA, not Mac.
- Outlook must be open and signed in when the script runs.
- Single machine, single Outlook profile. Not for headless or multi-mailbox server scenarios.
If any of those constraints rule you out, use Microsoft Graph.
The repo
github.com/ChiefStarKid/claude-outlook-bridge
AGENTS.md and llms.txt are in there for anyone who wants to wire this into a coding agent automatically.
Top comments (0)