Skip to main content
Glama
Yahoo Mail MCP

Yahoo Mail MCP

by Colciferr
README.md
# Yahoo Mail connector for Claude (and Claude Duet)

A small remote MCP server that gives Claude access to one Yahoo Mail account through IMAP and SMTP with a Yahoo **app password**. Yahoo has no connector in the Claude directory. Claude Duet uses the connectors on your Claude account, so once you add this one in Claude, Duet can use it too.

This is for Yahoo Mail (`@yahoo.com` and similar). It does not cover Yahoo! JAPAN mail (`@yahoo.co.jp`), which is a separate service.

## Tools

| Tool | What it does | Changes mail? |
|---|---|---|
| `list_folders` | Folders with role (sent/trash/spam/...), counts, unread | no |
| `search_emails` | Filter by sender, recipient, subject, text, date range, unread, flagged. Newest first, with snippets | no |
| `get_email` | Full message as plain text (HTML converted), attachment names and sizes | only if `mark_read` |
| `create_draft` | Saves a draft to Drafts. Can be a threaded reply | adds a draft |
| `update_flags` | Mark read/unread, flag/unflag | yes |
| `move_emails` | Move to any folder or role (`archive`, `spam`, ...) | yes |
| `trash_emails` | Move to Trash (never permanently deletes) | yes |
| `send_email` | Sends immediately | **sends** |
| `reply_to_email` | Threaded reply / reply-all with quoted original | **sends** |

The tools are annotated (read-only vs. destructive) so clients can decide what needs your approval. `READ_ONLY=1` exposes only the first three tools. `DISABLE_SEND=1` removes the two send tools but keeps drafts, so Claude can prepare replies and you send them yourself from Yahoo.

## Setup

### 1. Yahoo app password

Yahoo account → **Account Info → Account Security → Generate app password**. Name it something like "Claude". Copy the 16-character password. You can revoke it there anytime without touching your real password.

### 2. Secret token

```bash
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
```

Copy `.env.example` to `.env` and fill in `YAHOO_EMAIL`, `YAHOO_APP_PASSWORD`, and `MCP_AUTH_TOKEN`.

### 3. Run it

```bash
docker build -t yahoo-mail-mcp .
docker run -d --name yahoo-mail-mcp --restart unless-stopped --env-file .env -p 8000:8000 yahoo-mail-mcp
curl localhost:8000/healthz   # -> ok
```

Without Docker: `pip install -r requirements.txt && python -m yahoo_mcp.server` (Python 3.10+, tested on 3.13).

### 4. Put it on the public internet over HTTPS

Claude connects to custom connectors from Anthropic's cloud, not from your device, so the server has to be reachable from the internet. Some options:

- **Cloudflare Tunnel from a machine at home** (no open ports): `cloudflared tunnel --url http://localhost:8000` gives a temporary `https://*.trycloudflare.com` address, which is fine for a first test. For something permanent, use a named tunnel on your own domain.
- **Any small VPS or container host** (Fly.io, Render, a $5 VPS with Caddy in front): deploy the Dockerfile and set the variables from `.env` as secrets.

### 5. Add it to Claude

In Claude: **Customize → Connectors → Add custom connector**.

- **URL:** `https://YOUR-HOST/mcp`
- **Authentication:** No sign-in
- **Request headers:** `Authorization` = `Bearer YOUR_MCP_AUTH_TOKEN`

If your dialog has no request-header option, use the URL `https://YOUR-HOST/mcp/YOUR_MCP_AUTH_TOKEN` instead. That works too, but the secret is then part of the URL, so keep that URL private.

After that, the connector is on your Claude account, and Duet picks up connected apps from there.

## Security model

- **One account, one secret.** Anyone with the token can read and send your mail. Every other path returns a bare 404. The token is compared in constant time and never logged (access logging is off).
- **Credentials never leave the server.** Error messages never include the app password. TLS certificates are verified. `IMAP_SECURITY`/`SMTP_SECURITY=none` (plaintext) is refused for anything except localhost.
- **Email is untrusted input.** The server tells Claude not to follow instructions found inside emails. It also rebuilds every reply header from validated parts, so a crafted message can't smuggle in a `Bcc:` or a newline through encoded display names, subjects, or `References`.
- **No permanent deletion.** Trash is as far as it goes.
- **Duplicate-send safety.** If the server accepted a message and the connection dropped afterward, or only some recipients were refused, the tool still reports it as sent (with a `refused` list). That way Claude won't send it a second time.
- **Sent folder.** By default (`SAVE_TO_SENT=auto`), after sending, the server waits a few seconds to see whether Yahoo filed its own copy in Sent. It only saves a copy if Yahoo didn't, so you don't get duplicates either way.

## Tests

```bash
pip install -r requirements-dev.txt
python tests/test_e2e.py    # 111 checks: real MCP client → this server → local IMAP + SMTP servers
python tests/test_fuzz.py   # 20,000 mangled messages through the MIME/header handling
```

The end-to-end suite runs a real MCP client over HTTP against the server, with a local IMAP server (pymap) and SMTP server (aiosmtpd), including a TLS run with certificate verification. It covers auth bypass attempts, header injection, hostile inbound mail, HTML-only and ISO-2022-JP mail, attachments, Unicode folders and subjects, reply-all address handling, partial recipient refusal, wrong passwords, server outages, parallel requests, and config guards.

## Limits

- Plain-text sending only. No outgoing attachments, and attachments can't be downloaded (they're listed with name and size).
- One Yahoo account per server instance.
- Recipients must be ASCII addresses.
- Tested against local IMAP/SMTP servers, not yet against Yahoo's live servers. The first real run is the final check.