Skip to main content
ClaudeWave
psyb0t avatar
psyb0t

docker-mailbox

View on GitHub

Multi-mailbox IMAP/SMTP control plane. One YAML, N accounts, one bearer-auth gate. Unified inbox across Gmail/Outlook/iCloud/mailo/inbox.lv/whatever — search, read, mark, send. Reader mode strips HTML chrome for LLMs. Streamable-HTTP MCP server + REST API on one port. Ships as a Docker image.

MCP ServersOfficial Registry0 stars0 forksPythonWTFPLUpdated today
Install in Claude Code / Claude Desktop
Method: UVX (Python) · docker-mailbox
Claude Code CLI
claude mcp add docker-mailbox -- uvx docker-mailbox
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "docker-mailbox": {
      "command": "uvx",
      "args": ["docker-mailbox"]
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Package name inferred from the repository name. Verify it exists on PyPI, or clone https://github.com/psyb0t/docker-mailbox and follow its README.
Use cases

MCP Servers overview

# mailbox

[![Docker Pulls](https://img.shields.io/docker/pulls/psyb0t/mailbox)](https://hub.docker.com/r/psyb0t/mailbox)
[![License: WTFPL](https://img.shields.io/badge/License-WTFPL-brightgreen.svg)](LICENSE)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![FastAPI](https://img.shields.io/badge/FastAPI-0.136-009688.svg)](https://fastapi.tiangolo.com/)

Your inboxes, on tap. Point this thing at as many email accounts as you want over IMAP + SMTP, and out the other end you get **one HTTP API and one MCP server, both on the same port** (MCP rides a streamable-HTTP channel at `/mcp`) so you can read mail, send mail, and nuke mail across every account from one place. No webmail. No database. No three-thousand-toggle desktop app. Just: "here's some email creds" → "now my agent / shell script / chaotic 3am curl pipeline can drive the inbox."

Every other "unified inbox" thing on the planet wants to *own* your mail — slurp it all into their cloud, charge you forever, lose it in a breach next quarter. This one stores **zero bytes**. Restart the container, nothing's lost, because there was never anything to lose. Connections come up per request, do their job, and die in a `finally`.

Stdlib `imaplib` + `smtplib` under the hood, FastAPI on top, official MCP Python SDK riding shotgun (streamable HTTP, no stdio nonsense), a supply-chain `exclude-newer` gate so a malicious pip release published at 3am can't sneak in, and a real-SMTP-server integration test that actually puts bytes on a socket.

## Table of Contents

- [What's Inside](#whats-inside)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
- [HTTP API](#http-api)
  - [Authentication](#authentication)
- [MCP server](#mcp-server)
- [Architecture](#architecture)
- [Development](#development)
- [License](#license)

## What's Inside

| Surface         | The goods                                                                                                                                       |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| **HTTP API**    | `GET /inbox` fans out across every account at once (filter by mailbox, sender, subject, date, flags…). Per-mailbox reads + deletes. SMTP send.   |
| **MCP server**  | Streamable-HTTP MCP at `/mcp` — same port, same bearer, same boss. A flat set of tools (`mailboxes`, `inbox`, `list_messages`, `send`, …) that take `mailbox` as a parameter. 100 accounts? Still one tool catalog. |
| **Bearer auth** | One token list in YAML guards both the API and `/mcp`. Empty list = wide open (your problem). Multiple tokens = zero-downtime rotation.          |
| **Protocols**   | IMAP (SSL / STARTTLS / plain), SMTP (SSL / STARTTLS / plain). Standards-boring on purpose.                                                       |
| **Config**      | One YAML file. Add a mailbox, restart, done. Each one declares whichever subset of `{imap, smtp}` you actually care about.                       |
| **State**       | None. Truly none. No DB, no queue, no cache, no "oh just this little Redis." A connection opens, does the work, closes. Next.                    |

## Quick Start

1. Drop a `config.yaml` next to you (steal `config.example.yaml` if you're feeling lazy — that's what it's there for).
2. Light it up:

```bash
docker run --rm \
  -p 8000:8000 \
  -v "$PWD/config.yaml:/etc/mailboxd/config.yaml:ro" \
  psyb0t/mailbox:latest
```

3. Poke it:

```bash
# no auth? this works as-is. with auth.tokens set, add: -H "Authorization: Bearer YOUR_TOKEN"
TOKEN="paste-a-token-from-config-here"

curl -s http://localhost:8000/health | jq                                               # health is always open
curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8000/mailboxes | jq
curl -s -H "Authorization: Bearer $TOKEN" 'http://localhost:8000/inbox?limit=5' | jq
```

### docker compose

```yaml
services:
  mailbox:
    image: psyb0t/mailbox:latest
    ports: ["8000:8000"]
    volumes:
      # config.yaml holds your IMAP/SMTP passwords AND your auth.tokens —
      # gitignore it, lock down its filesystem perms, treat it like an SSH key.
      - ./config.yaml:/etc/mailboxd/config.yaml:ro
```

## Configuration

One YAML file. Lives at `MAILBOXD_CONFIG`, or `--config`, or `/etc/mailboxd/config.yaml` if you can't be bothered.

```yaml
log_level: INFO

# Bearer-token gate. Guards the HTTP API AND /mcp. Empty / missing = no auth
# (good luck out there). Multi-token list = rotate without downtime: add a
# new one, swap clients over, retire the old one.
auth:
  tokens:
    - "long-random-token-1"
    - "long-random-token-2"

mailboxes:
  - name: personal              # URL-safe handle; shows up in /mailboxes/<name>/... and as the MCP tool prefix
    description: "Gmail"

    imap:
      host: imap.gmail.com
      port: 993                 # default 993
      tls: ssl                  # ssl | starttls | none   (default ssl)
      username: me@gmail.com
      password: "app-password"  # Gmail/Yahoo/etc. need an app password, not your real one
      default_folder: INBOX     # default folder when callers don't specify one

    smtp:
      host: smtp.gmail.com
      port: 465                 # default 587
      tls: ssl                  # default starttls
      username: me@gmail.com
      password: "app-password"
      from_address: "Me <me@gmail.com>"

  - name: work
    imap:  { host: mail.work.com, port: 143, tls: starttls, username: me, password: "...", default_folder: INBOX }
    smtp:  { host: mail.work.com, port: 587, tls: starttls, username: me, password: "...", from_address: me@work.com }
```

The fine print:

- **At least one mailbox.** Each one needs at least one of `imap` / `smtp`. Both is fine. Neither is a config error.
- **`name`** matches `[a-zA-Z0-9_-]+` and is unique — it's the URL path segment and the MCP tool prefix, so don't put spaces or emojis in it.
- **Defaults**: IMAP `993/ssl`, SMTP `587/starttls`. Override if your provider is weird.
- **The config file holds plaintext passwords and your bearer tokens.** Treat it like a credential vault: gitignore it, `chmod 600`, mount read-only, don't paste it in Slack.

## HTTP API

### Authentication

If `auth.tokens` is set, **every request except `GET /health`** has to carry a bearer:

```
Authorization: Bearer <one of auth.tokens>
```

No header, wrong shape, wrong value → `401` with `WWW-Authenticate: Bearer`. Tokens get a constant-time compare so you don't leak them through timing. The same gate covers `/mcp` — there's no second auth system to learn.

Leave `auth.tokens` empty (or skip the block) and everything's open. Fine for "this is bound to 127.0.0.1 and there's a reverse proxy in front." Catastrophic otherwise. Your call.

### Errors

Everything's JSON. Errors look like `{"detail": "..."}`:

| Status | When                                                                                       |
| ------ | ------------------------------------------------------------------------------------------ |
| `401`  | Missing or invalid bearer (when auth is on).                                                |
| `404`  | Unknown mailbox name in the URL.                                                            |
| `409`  | You're asking a mailbox for a protocol it doesn't have (IMAP endpoint on an SMTP-only one). |
| `502`  | The IMAP / SMTP server upstream said no.                                                    |

### `GET /health`

```json
{ "ok": true, "version": "0.1.0" }
```

Always open, no bearer required. Point your liveness probe at this and forget about it.

### `GET /mailboxes`

```json
{
  "mailboxes": [
    { "name": "personal", "description": "Gmail",
      "imap": true, "smtp": true }
  ]
}
```

### Unified inbox (the main event)

`GET /inbox` is the read endpoint you actually want 90% of the time. It hits **every IMAP-configured mailbox in parallel**, runs the same structured search on each one, merges newest-first, and tags every result with which account it came from. "Show me everything from `boss@corp.com`," "what's unread right now," "what came in this morning" — all the same call, no fanout dance on the client side.

| Query param                                      | What it does                                                                                                                              |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `mailbox`                                        | CSV filter by mailbox name (`personal`) **or** email address (`me@gmail.com`). Omit to search all of them.                                 |
| `from`, `to`, `subject`, `body`, `text`          | IMAP SEARCH predicates. `text` is full-text across headers + body.                                                                         |
| `since`, `before`                                | IMAP dates, e.g. `1-Jan-2026`.                                                                                                             |
| `unseen`, `seen`, `flagged`, `answered`          | Flag filters. Set the ones you want to true.                                                                                               |
| `larger_than`, `smaller_than`                    | Bytes.                                                                                                                                     |
| `folder`                                         | IMAP folder (default `INBOX`).                                                                                                             |
| `limit`                                          | Hard-capped at 500. Default 50.                                                          
dockeremailfastapiimapllm-toolsmailboxmcpmodel-context-protocolpythonself-hostedsmtpstreamable-httpunified-inbox

What people ask about docker-mailbox

What is psyb0t/docker-mailbox?

+

psyb0t/docker-mailbox is mcp servers for the Claude AI ecosystem. Multi-mailbox IMAP/SMTP control plane. One YAML, N accounts, one bearer-auth gate. Unified inbox across Gmail/Outlook/iCloud/mailo/inbox.lv/whatever — search, read, mark, send. Reader mode strips HTML chrome for LLMs. Streamable-HTTP MCP server + REST API on one port. Ships as a Docker image. It has 0 GitHub stars and was last updated today.

How do I install docker-mailbox?

+

You can install docker-mailbox by cloning the repository (https://github.com/psyb0t/docker-mailbox) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.

Is psyb0t/docker-mailbox safe to use?

+

psyb0t/docker-mailbox has not been audited yet by our security agent. Review the original repository on GitHub before using it in production.

Who maintains psyb0t/docker-mailbox?

+

psyb0t/docker-mailbox is maintained by psyb0t. The last recorded GitHub activity is from today, with 0 open issues.

Are there alternatives to docker-mailbox?

+

Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.

Deploy docker-mailbox to your cloud

Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.

Maintain this repo? Add a badge to your README

Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.

Featured on ClaudeWave: psyb0t/docker-mailbox
[![Featured on ClaudeWave](https://claudewave.com/api/badge/psyb0t-docker-mailbox)](https://claudewave.com/repo/psyb0t-docker-mailbox)
<a href="https://claudewave.com/repo/psyb0t-docker-mailbox"><img src="https://claudewave.com/api/badge/psyb0t-docker-mailbox" alt="Featured on ClaudeWave: psyb0t/docker-mailbox" width="320" height="64" /></a>

More MCP Servers

docker-mailbox alternatives