# Claude Code to Outlook via pywin32 — no MCP, no permission, no problem.

> Source: <https://dev.to/joseph_solomon_20a1569494/claude-code-to-outlook-via-pywin32-no-mcp-no-permission-no-problem-113b>
> Published: 2026-06-29 15:08:22+00:00

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.

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:

``` 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.

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.

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.

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.

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.

`list`

— recent emails in any folder`search`

— by keyword, sender, subject`read`

— full body + attachment list`send`

/ `reply`

/ `reply-all`

/ `forward`

— with `--draft`

support`move`

/ `delete`

`cal-list`

— calendar events in a date range, including shared calendarsWorth stating plainly:

If any of those constraints rule you out, use Microsoft Graph.

[github.com/ChiefStarKid/claude-outlook-bridge](https://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.
