# simple-email-mcp

A provider-agnostic MCP server for email (IMAP/SMTP). Works with any email provider — Purelymail, Gmail, Outlook, DomainFactory, or any standard IMAP/SMTP server.

Built for [Claude Desktop](https://claude.ai), [Claude Code](https://claude.com/claude-code), and any MCP-compatible client.

## Features

- **Multi-account** — manage multiple email accounts from different providers
- **Read, search, list** — full IMAP support with folder browsing
- **Send emails** — plain text, HTML, or both (multipart/alternative)
- **Attachments** — send via file path or base64-encoded inline data
- **Download attachments** — extract attachments from received emails as base64
- **Calendar invites** — send proper ICS invitations with Accept/Decline buttons
- **Save to Sent** — automatically saves sent emails to the Sent folder via IMAP
- **Optional send gate** — configurable confirmation code to prevent accidental sends
- **International folders** — handles UTF-7 encoded folder names (German, etc.)

## Quick Start

### 1. Install

```bash
pip install simple-email-mcp
```

Or from source:

```bash
git clone https://github.com/mexican75/simple-email-mcp.git
cd simple-email-mcp
pip install .
```

### 2. Create `accounts.json`

```json
{
  "accounts": [
    {
      "name": "personal",
      "address": "me@example.com",
      "password": "your-app-password",
      "provider": "gmail"
    }
  ]
}
```

### 3. Add to your client

**Claude Code** (global, all projects):

```bash
claude mcp add email -s user -e ACCOUNTS_FILE=/path/to/accounts.json -- simple-email-mcp
```

**Claude Desktop** — add to config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows):

```json
{
  "mcpServers": {
    "email": {
      "command": "simple-email-mcp"
    }
  }
}
```

Or if running from source:

```json
{
  "mcpServers": {
    "email": {
      "command": "python",
      "args": ["/path/to/simple_email_mcp.py"]
    }
  }
}
```

### 4. Restart your client

## Configuration

### accounts.json

```json
{
  "send_code": "MYSECRETCODE",
  "accounts": [
    {
      "name": "work",
      "address": "me@company.com",
      "password": "app-password",
      "provider": "outlook"
    },
    {
      "name": "personal",
      "address": "me@gmail.com",
      "password": "app-password",
      "provider": "gmail"
    },
    {
      "name": "custom",
      "address": "me@mydomain.com",
      "password": "password",
      "imap_host": "mail.mydomain.com",
      "imap_port": 993,
      "smtp_host": "mail.mydomain.com",
      "smtp_port": 587,
      "smtp_security": "starttls"
    }
  ]
}
```

Config is reloaded on each tool call, so changes to `accounts.json` such as rotating `send_code` take effect without restarting the MCP server.

### Fields

| Field | Required | Description |
|-------|----------|-------------|
| `send_code` | No | If set, users must provide this code to send emails. Omit or set to `""` to disable. |
| `name` | Yes | Short identifier for the account (used in tool calls) |
| `address` | Yes | Email address |
| `password` | Yes | Password or app-specific password |
| `provider` | No | Preset: `gmail`, `outlook`, `purelymail`, `domainfactory` |
| `imap_host` | No | Custom IMAP server (overrides provider default) |
| `imap_port` | No | Custom IMAP port (default: 993) |
| `smtp_host` | No | Custom SMTP server (overrides provider default) |
| `smtp_port` | No | Custom SMTP port (default: 465) |
| `smtp_security` | No | `ssl` (port 465) or `starttls` (port 587). Auto-detected from port if omitted. |

### Environment variables (single account)

Instead of `accounts.json`, you can configure a single account via environment variables:

```
EMAIL_ADDRESS=me@example.com
EMAIL_PASSWORD=password
IMAP_HOST=imap.example.com
SMTP_HOST=smtp.example.com
SMTP_SECURITY=ssl
SEND_CODE=optional
```

## Tools

| Tool | Description |
|------|-------------|
| `email_list_accounts` | List configured accounts |
| `email_list_folders` | List IMAP folders for an account |
| `email_list_emails` | List recent emails in a folder |
| `email_search_emails` | Search emails using IMAP criteria |
| `email_read_email` | Read full email content by UID |
| `email_get_attachment` | Download an attachment as base64 |
| `email_prepare_attachments` | Inspect local attachment paths before sending |
| `email_save_attachment` | Save an attachment directly to disk (preferred for large files) |
| `email_send_email` | Send an email (text, HTML, attachments, calendar invites) |
| `email_reply` | Reply to an email (auto-sets recipient, subject, threading, quotes body) |
| `email_reply_all` | Reply all (sender → To, other recipients → CC, quotes body) |
| `email_forward` | Forward an email with original attachments |
| `email_move_email` | Move an email between folders |
| `email_mark_email` | Mark as read/unread/flagged/unflagged |

### Sending with attachments

**Preflight metadata only** (recommended before send):
```json
attachments: "/path/to/file.pdf, /path/to/doc.xlsx"
```
Call `email_prepare_attachments` first to verify resolved paths, file names, sizes, MIME types, and missing files without loading contents into context.

**File path** (when the MCP server has filesystem access):
```
attachments: "/path/to/file.pdf, /path/to/doc.xlsx"
```

**Base64 inline** (when the caller is in a sandbox):
```json
attachments_inline: [{"filename": "report.pdf", "content_base64": "JVBERi0...", "content_type": "application/pdf"}]
```

### Sending calendar invites

Pass raw ICS content via `calendar_ics`. The email is structured as `multipart/alternative` so clients display Accept/Decline buttons:

```
calendar_ics: "BEGIN:VCALENDAR\r\nVERSION:2.0\r\n..."
```

### Send confirmation gate

If `send_code` is set in `accounts.json`, the AI must show the email draft to the user and wait for them to provide the code before sending. This is useful as a workflow checkpoint to reduce accidental sends.

Important: this is not a hard security boundary if the MCP process and the AI runtime can both read the same config source. In that setup, the AI may be able to read the code from `accounts.json` or environment variables. Remove or clear `send_code` to disable the checkpoint.

## Testing

Run the regression suite from the repo root:

```bash
.venv/bin/python -m unittest discover -s tests -v
```

## Security

- Passwords are stored in `accounts.json` — **add it to `.gitignore`**
- The `send_code` gate is a user-intent checkpoint, not a hard secret, unless the AI cannot read the config source that contains it
- No passwords are exposed via the `email_list_accounts` tool
- **File attachments**: The `attachments` parameter reads files from paths the AI provides. If the MCP server runs with broad filesystem access, the AI could theoretically attach and send any readable file. Use `attachments_inline` (base64) in sandboxed environments, or restrict filesystem access at the OS/container level.
- **Saving attachments**: `email_save_attachment` now fails if the target file already exists unless `overwrite=true` is set explicitly.

## Provider Notes

### Gmail
Use an [App Password](https://support.google.com/accounts/answer/185833) (not your Google password). Enable IMAP in Gmail settings.

### Outlook / Microsoft 365
Use an [App Password](https://support.microsoft.com/en-us/account-billing/using-app-passwords-with-apps-that-don-t-support-two-step-verification-5896ed9b-4263-e681-128a-a6f2979a7944) or enable basic auth for IMAP/SMTP.

### Purelymail
Use your Purelymail account password directly.

## License

MIT — see [LICENSE](LICENSE)

## Authors

- Ramon Ramirez ([@mexican75](https://github.com/mexican75))
