Metadata-Version: 2.4
Name: owlpost
Version: 0.1.4
Summary: High-fidelity IMAP/SMTP MCP server for iCloud, Gmail, and other mail providers
Project-URL: Homepage, https://github.com/smankoo/owlpost
Project-URL: Repository, https://github.com/smankoo/owlpost
Project-URL: Issues, https://github.com/smankoo/owlpost/issues
Author-email: Sumeet Singh Mankoo <sumeet@mankoo.ca>
License: MIT License
        
        Copyright (c) 2026 Sumeet Singh Mankoo
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: claude,email,gmail,icloud,imap,mcp,model-context-protocol,smtp
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Email
Classifier: Topic :: Communications :: Email :: Post-Office :: IMAP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Requires-Dist: mcp>=1.2.0
Description-Content-Type: text/markdown

# owlpost

A high-fidelity IMAP/SMTP MCP server for iCloud, Gmail, and other mail
providers. Built because every other email MCP server I tried got tripped up
by real-world IMAP quirks (CRLF line endings, `RFC822` vs `BODY.PEEK[]`,
provider-specific Sent folders, multi-word search values).

owlpost is the one I actually use day-to-day from Claude Code to read,
search, follow conversations, and send mail.

## Features

- **Multi-account** — configure as many mailboxes as you want, switch by name
- **iCloud and Gmail tested end-to-end**, with provider-specific quirks handled:
  - iCloud's `RFC822` fetch returns empty bodies → uses `BODY.PEEK[]`
  - iCloud's IMAP `APPEND` requires CRLF line endings → all outbound mail uses `policy.SMTP`
  - iCloud's SMTP doesn't auto-save sent mail → owlpost APPENDs to Sent for you
  - Gmail's SMTP *does* auto-save → owlpost skips the duplicate APPEND
  - Folder names auto-discovered via RFC 6154 SPECIAL-USE (no hardcoding `Sent Messages` vs `[Gmail]/Sent Mail`)
- **Conversation following** — Gmail's `X-GM-THRID` extension where available, otherwise a generic Message-ID/References BFS across folders
- **Reliable connections** — short-lived per-operation IMAP sessions instead of long-lived ones that drop randomly
- **MIME-aware** — parses multipart messages, decodes headers, lists attachments, downloads them to disk
- **Threaded reply/forward** — preserves `In-Reply-To`/`References`, quotes the original

## Tools

| Tool | What it does |
| --- | --- |
| `list_accounts` | List configured mail accounts |
| `list_folders` | List folders for an account, with detected special-use roles |
| `resolve_folder` | Resolve a role (`sent`, `trash`, `drafts`, `inbox`, `all`, `archive`) to a folder name |
| `search_messages` | Structured IMAP search (from/to/cc/subject/body/since/before/unseen/flagged/has_attachment), newest first |
| `read_email` | Read one message: headers, plaintext/HTML body, attachment list. Truncates by default to fit MCP result limits |
| `save_attachment` | Download an attachment to disk by part index |
| `get_conversation` | Return all messages in the same thread (Gmail X-GM-THRID or generic reference walking) |
| `send_email` | Send mail. Auto-saves to Sent on providers that don't (e.g. iCloud). Supports attachments, threading headers |
| `save_draft_email` | Build a message and APPEND it to Drafts without sending — same parameters as `send_email` |
| `reply_email` | Reply (with optional reply-all), preserving threading and quoting |
| `forward_email` | Forward, re-attaching original attachments by default |
| `mark_read` | Set/unset `\Seen` |
| `flag_message` | Set/unset `\Flagged` (star) |
| `move_email` | Move to another folder |
| `delete_email` | Move to Trash |

## Install

The recommended way is to **not install at all** — let
[`uvx`](https://docs.astral.sh/uv/guides/tools/) fetch and cache it on first
use. This keeps the package always up-to-date and avoids polluting your
global Python environment:

```bash
# Run directly — uvx fetches from PyPI and caches.
uvx --from owlpost owlpost
```

If you'd rather have a stable binary on your `PATH`:

```bash
# Persistent install with uv (recommended)
uv tool install owlpost

# Or plain pip
pip install owlpost
```

Either way you'll end up with an `owlpost` command that speaks MCP over stdio.

## Configure

Copy [`accounts.example.toml`](accounts.example.toml) to
`~/.config/owlpost/accounts.toml` and fill in your credentials. **Use
app-specific passwords**, not your real password:

- **iCloud**: [account.apple.com → Sign-In and Security → App-Specific Passwords](https://account.apple.com)
- **Gmail**: [myaccount.google.com/apppasswords](https://myaccount.google.com/apppasswords) (2FA must be enabled)

```toml
[accounts.icloud]
email = "you@icloud.com"
password = "xxxx-xxxx-xxxx-xxxx"
provider = "icloud"
imap_host = "imap.mail.me.com"
imap_port = 993
smtp_host = "smtp.mail.me.com"
smtp_port = 587
auto_save_sent = true   # iCloud SMTP doesn't auto-save sent

[accounts.gmail]
email = "you@gmail.com"
password = "xxxx xxxx xxxx xxxx"
provider = "gmail"
imap_host = "imap.gmail.com"
imap_port = 993
smtp_host = "smtp.gmail.com"
smtp_port = 587
auto_save_sent = false  # Gmail SMTP auto-saves
```

You can override the config path with the `OWLPOST_CONFIG` environment
variable.

## Use with Claude Code

Add to `~/.claude.json` under `mcpServers`. The `uvx` form is recommended —
it fetches owlpost from PyPI on first launch, caches it, and keeps you on
the latest version with no manual install step:

```json
{
  "mcpServers": {
    "owlpost": {
      "type": "stdio",
      "command": "uvx",
      "args": ["--from", "owlpost", "owlpost"],
      "env": {}
    }
  }
}
```

If `uvx` isn't on Claude Code's `PATH` you may need to use the absolute
path (typically `~/.local/bin/uvx`).

Alternatively, if you installed with `uv tool install owlpost` or
`pip install owlpost`, point `command` directly at the resulting binary:

```json
{
  "mcpServers": {
    "owlpost": {
      "type": "stdio",
      "command": "owlpost",
      "args": [],
      "env": {}
    }
  }
}
```

Restart Claude Code and the tools will appear under the `owlpost` namespace.

## Use with Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "owlpost": {
      "command": "uvx",
      "args": ["--from", "owlpost", "owlpost"]
    }
  }
}
```

## Use with other MCP clients

owlpost speaks the standard MCP stdio transport — any MCP-compatible client
can talk to it by spawning either `uvx --from owlpost owlpost` or, if
installed, the bare `owlpost` binary.

## Examples

Once registered, you can ask Claude things like:

- *"Find emails from priya about the kids' school in the last month"*
- *"Show me the full thread for the latest mortgage email"*
- *"Reply to the most recent message from the landlord saying I'll be in touch tomorrow"*
- *"Forward the Manulife policy PDFs to Mom and Dad with Priyanka in CC"*
- *"Save the attachment from the Toronto Hydro bill to ~/Downloads"*

## Provider notes

### iCloud

- Use an [app-specific password](https://account.apple.com), not your Apple ID password.
- iCloud throttles aggressive reconnection. owlpost uses short-lived per-op sessions but doesn't pool — if you get `SSLEOFError: EOF`, back off for ~30 seconds.
- Sent folder is `Sent Messages`, Trash is `Deleted Messages`. Both are auto-detected.

### Gmail

- Requires [2FA](https://myaccount.google.com/security) and an [app password](https://myaccount.google.com/apppasswords).
- IMAP must be enabled in [Gmail settings → Forwarding and POP/IMAP](https://mail.google.com/mail/u/0/#settings/fwdandpop).
- owlpost uses Gmail's `X-GM-THRID` extension for reliable thread detection.

### Proton Mail (via Proton Bridge)

Proton only exposes IMAP/SMTP through the [Proton Bridge](https://proton.me/mail/bridge)
app, which runs on localhost with a self-signed certificate and speaks
STARTTLS on non-standard ports. Configure with:

- `provider = "generic"`
- `imap_host = "127.0.0.1"`, `imap_port = 1143`, `imap_security = "starttls"`
- `smtp_host = "127.0.0.1"`, `smtp_port = 1025`, `smtp_security = "starttls"`
- `tls_verify = false` — required because Bridge's cert is self-signed
- Use the Bridge-generated mailbox password (not your Proton account password)

### Other providers

Set `provider = "generic"` and configure `imap_host`, `smtp_host`, ports,
`imap_security` / `smtp_security` (`starttls` or `ssl`), and `tls_verify`
(set `false` for self-signed certs). Folder roles will still be
auto-detected if your provider supports SPECIAL-USE (most modern ones do).

## Development

```bash
git clone https://github.com/smankoo/owlpost
cd owlpost
uv venv
uv pip install -e .
```

Run the server directly to verify it starts:

```bash
.venv/bin/owlpost
# (waits for MCP stdio input)
```

## Publishing

Releases go to [PyPI](https://pypi.org/project/owlpost/). From a clean tree
on `main`:

```bash
# 1. Bump version in pyproject.toml
# 2. Commit the bump
# 3. Build the sdist + wheel
uv build

# 4. Upload to PyPI (requires ~/.pypirc with an API token)
uv publish

# 5. Tag and push
git tag v0.1.x
git push && git push --tags
```

`uv build` writes to `dist/`. `uv publish` reads credentials from
`~/.pypirc` (expects `[pypi]` with `username = __token__` and
`password = pypi-...`). `uvx` users pick up the new version automatically
on next launch.

## License

MIT — see [LICENSE](LICENSE).
