Skip to main content
Glama
ptbsare

MCP Email Server

by ptbsare
README.md
# MCP Email Server

A Model Context Protocol (MCP) server for email operations (POP3/SMTP with TLS). Allows an LLM like Claude to read, send, and manage emails.

## Quick Start

### Option 1: uvx (recommended)

No clone, no install — runs directly from GitHub:

```bash
uvx git+https://github.com/ptbsare/email-mcp-server \
  --email-user you@example.com \
  --email-pass yourpassword \
  --pop3-server pop.example.com \
  --smtp-server smtp.example.com
```

First run caches the package; subsequent launches are instant.

### Option 2: Clone + run locally

```bash
git clone https://github.com/ptbsare/email-mcp-server
cd email-mcp-server
uv pip install -e .
uv run main.py --email-user you@example.com --email-pass yourpassword \
  --pop3-server pop.example.com --smtp-server smtp.example.com
```

### Option 3: .env file

Create a `.env` file in the working directory:

```dotenv
EMAIL_USER=you@example.com
EMAIL_PASS=yourpassword
POP3_SERVER=pop.example.com
SMTP_SERVER=smtp.example.com
```

Then simply:

```bash
uvx git+https://github.com/ptbsare/email-mcp-server
# or
uv run main.py
```

## Configuration

### Config Priority (highest → lowest)

1. **CLI arguments** — override everything
2. **Environment variables** — override `.env` file
3. **`.env` file** — fallback defaults

### All Config Options

| CLI Argument | Env Variable | Required | Default | Description |
|---|---|---|---|---|
| `--email-user` | `EMAIL_USER` | ✅ | — | Email address |
| `--email-pass` | `EMAIL_PASS` | ✅ | — | Email password / app password |
| `--pop3-server` | `POP3_SERVER` | ✅ | — | POP3 server hostname |
| `--pop3-port` | `POP3_PORT` | | `995` | POP3 SSL port |
| `--smtp-server` | `SMTP_SERVER` | ✅ | — | SMTP server hostname |
| `--smtp-port` | `SMTP_PORT` | | `587` | SMTP port (auto `465` if `--smtp-use-ssl`) |
| `--smtp-use-ssl` | `SMTP_USE_SSL` | | `false` | Use SMTP_SSL (port 465) instead of STARTTLS |
| `--log-level` | `LOG_LEVEL` | | `INFO` | Logging: `DEBUG` / `INFO` / `WARNING` / `ERROR` |

### Examples: Mixing Config Sources

```bash
# CLI args only (no .env needed):
uv run main.py --email-user me@gmail.com --email-pass xxx \
  --pop3-server pop.gmail.com --smtp-server smtp.gmail.com

# .env file for credentials, CLI for servers:
# .env: EMAIL_USER=me@gmail.com / EMAIL_PASS=xxx
uv run main.py --pop3-server pop.gmail.com --smtp-server smtp.gmail.com

# Env vars override .env:
EMAIL_USER=other@gmail.com uv run main.py --pop3-server pop.gmail.com ...
```

## Using with Claude Desktop

Add to your Claude Desktop config file:

**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows:** `%APPDATA%/Claude/claude_desktop_config.json`

### With env vars (in config):

```json
{
  "mcpServers": {
    "email-mcp-server": {
      "command": "uvx",
      "args": ["git+https://github.com/ptbsare/email-mcp-server"],
      "env": {
        "EMAIL_USER": "your-email@example.com",
        "EMAIL_PASS": "your-app-password",
        "POP3_SERVER": "pop.example.com",
        "SMTP_SERVER": "smtp.example.com"
      }
    }
  }
}
```

### With CLI args (in config):

```json
{
  "mcpServers": {
    "email-mcp-server": {
      "command": "uvx",
      "args": [
        "git+https://github.com/ptbsare/email-mcp-server",
        "--email-user", "your-email@example.com",
        "--email-pass", "your-app-password",
        "--pop3-server", "pop.example.com",
        "--smtp-server", "smtp.example.com"
      ]
    }
  }
}
```

> **Tip:** The `env` section and CLI args can be used together. CLI args always take priority.

## Features

- **Poll Emails:** List inbox email headers with configurable limit (`pollEmails`)
- **Fetch Full Emails:** Get complete email content by ID, with automatic attachment extraction (`getEmailsById`)
- **Delete Emails:** Remove emails by ID (`deleteEmailsById`)
- **Send Emails:** Send plain text (`sendTextEmail`) or HTML (`sendHtmlEmail`) emails with optional file attachments
- **Secure Connections:** POP3 over SSL (port 995), SMTP with STARTTLS (port 587) or direct SSL (port 465)
- **Attachment Support:** Send local files as attachments; received attachments are auto-saved to `/tmp/email_mcp_attachments/<email_id>/`

## Tools

### `pollEmails(limit=50)`

List recent email headers (no body). Returns newest first. Use this first to get IDs for `getEmailsById`/`deleteEmailsById`.

| Parameter | Type | Default | Description |
|---|---|---|---|
| `limit` | `int` | `50` | Max emails to return, newest first |

**Returns:** `[{"id": int, "Subject": str, "From": str, "Date": str, "Message-ID": str}]`

```python
pollEmails(limit=10)   # 10 most recent
pollEmails()           # default 50
```

---

### `getEmailsById(ids)`

Fetch full email content (headers + body) by IDs from `pollEmails`. Attachments auto-saved to `/tmp/email_mcp_attachments/<id>/`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `ids` | `list[int]` | ✅ | Email IDs from `pollEmails()`. Example: `[1, 3, 5]` |

**Returns:** `[{"id": int, "headers": dict, "body": str, "attachments": [{"filename": str, "local_path": str, "size": int, "content_type": str}]}]`

```python
getEmailsById(ids=[1, 3, 5])
```

---

### `deleteEmailsById(ids)`

Permanently delete emails by IDs. **Irreversible.** Call `pollEmails` first.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `ids` | `list[int]` | ✅ | Email IDs from `pollEmails()`. Example: `[1, 2, 3]` |

**Returns:** `{"deleted": [int], "failed": {"id": "error msg"}}`

```python
deleteEmailsById(ids=[1, 2, 3])
```

---

### `sendTextEmail(toAddresses, subject, body, attachments=None)`

Send a plain text email. Attachments: list of local file paths like `["/tmp/file.pdf"]`.

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `toAddresses` | `list[str]` | ✅ | — | Recipients. Example: `["alice@example.com"]` |
| `subject` | `str` | ✅ | — | Subject line |
| `body` | `str` | ✅ | — | Plain text body |
| `attachments` | `list[str]` | | `None` | Local file paths. Example: `["/tmp/report.pdf"]` |

**Returns:** `{"status": "success"}`

```python
sendTextEmail(
    toAddresses=["alice@example.com"],
    subject="Hello",
    body="Hi Alice!",
    attachments=["/tmp/report.pdf"]
)
```

---

### `sendHtmlEmail(toAddresses, subject, body, attachments=None)`

Send an HTML email. Attachments: list of local file paths like `["/tmp/file.png"]`.

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `toAddresses` | `list[str]` | ✅ | — | Recipients. Example: `["alice@example.com"]` |
| `subject` | `str` | ✅ | — | Subject line |
| `body` | `str` | ✅ | — | HTML content. Example: `"<h1>Hi</h1><p>Hello!</p>"` |
| `attachments` | `list[str]` | | `None` | Local file paths. Example: `["/tmp/chart.png"]` |

**Returns:** `{"status": "success"}`

```python
sendHtmlEmail(
    toAddresses=["alice@example.com"],
    subject="Report",
    body="<h1>Report</h1><p>Sales up <b>20%</b>.</p>",
    attachments=["/tmp/chart.png"]
)
```

---

## Development Setup

### Prerequisites
- Python 3.12+
- [uv](https://github.com/astral-sh/uv)

### Steps

```bash
git clone https://github.com/ptbsare/email-mcp-server
cd email-mcp-server
uv pip install -e .
uv run main.py --help
```

## Important Notes

- **App Passwords:** If your email provider uses 2FA, generate an App Password for `EMAIL_PASS`
- **Email IDs:** POP3 IDs are session-specific. Call `pollEmails()` before `getEmailsById()` or `deleteEmailsById()`
- **Attachment Storage:** Received attachments are saved to `/tmp/email_mcp_attachments/<email_id>/`
- **Security:** Never commit your `.env` file — it's already in `.gitignore`
- **Config Priority:** CLI args > environment variables > `.env` file

## Project Structure

```
email-mcp-server/
├── main.py              # MCP server entry point (all logic)
├── pyproject.toml       # Package config & dependencies
├── uv.lock              # Dependency lock file
├── .env                 # Credentials (create your own)
├── .gitignore
└── README.md
```

## License

MIT