mailbox-mcp
by SDK-E
README.md
# mailbox
[](https://github.com/SDK-E/mailbox/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/@sdk-e/mailbox)
[](./LICENSE)
A local development **mail sink**: run one SMTP server plus an HTTP API for your whole machine and point every project at it. Emails never leave your device — instead they land in an inspectable inbox with a web UI, a CLI, and an MCP server for AI agents.
One shared instance eliminates per-project port collisions: start it once, connect many.
## Install
```sh
pnpm add -D @sdk-e/mailbox # or npm i -D / yarn add -D
```
Or run ad hoc:
```sh
npx @sdk-e/mailbox
```
## Quick start
```sh
mailbox # SMTP on :11025, inbox UI on http://localhost:11090
```
Send mail to `smtp://127.0.0.1:11025` from any app (nodemailer, Resend dev mode, etc.), then:
```sh
open http://localhost:11090 # or: mailbox-cli open
```
## Bins
| Bin | Purpose |
| ------------- | ---------------------------------------------------------------------------- |
| `mailbox` | Run the sink (SMTP + HTTP + inbox UI) |
| `mailbox-cli` | `list`, `read <id>`, `wait [match] [--timeout s]`, `clear`, `health`, `open` |
| `mailbox-mcp` | MCP server (`list_emails`, `read_email`, `clear_emails`, `wait_for_email`) |
### CLI examples
```sh
mailbox-cli list
mailbox-cli read 3
mailbox-cli wait "verification code" --timeout 10 # blocks until a new matching message arrives
mailbox-cli clear
```
`wait` only matches messages that arrive **after** it starts — start it before triggering the send.
## Library use
```ts
import { startMailbox } from "@sdk-e/mailbox";
const mailbox = await startMailbox({ smtpPort: 0, httpPort: 0 }); // 0 = ephemeral
console.log(mailbox.smtpPort, mailbox.url);
await mailbox.close();
```
Ideal for integration tests that need an isolated throwaway inbox.
## HTTP API (stable wire protocol)
| Route | Method | Response |
| ---------------- | ------ | -------------------------------------------------------------- |
| `/api/health` | GET | `{ ok, smtpPort, httpUrl, messageCount }` |
| `/api/email` | GET | array of `{ id, receivedAt, from, to, subject, text, html }` |
| `/api/email/:id` | GET | message above plus `raw` source; `404 {"error": …}` if missing |
| `/api/email/all` | DELETE | `{ ok: true, messageCount: 0 }` |
| `/` | GET | inbox UI |
## Configuration
Environment variables (a `.env.local`, then `.env`, in the working directory are loaded if present):
| Variable | Default | Purpose |
| ---------------- | ----------------- | ------------------------------------------ |
| `MAIL_SMTP_PORT` | `11025` | SMTP listen port |
| `MAIL_HTTP_PORT` | `11090` | HTTP API/UI port |
| `MAIL_HTTP_URL` | derived from port | Base URL used by CLI/MCP to reach the sink |
| `MAILBOX_HOST` | `127.0.0.1` | Bind interface (loopback by default) |
Point your app's mailer at `smtp://127.0.0.1:$MAIL_SMTP_PORT` locally; in production keep using your real provider. The server refuses to start when `NODE_ENV=production`.
## Why high ports?
1025/1080 (classic MailHog-style defaults) collide frequently. mailbox defaults to 11025/11090 so several SDK-E projects can share a single instance without stepping on each other or on other local tooling.
## Development
Requires Node >= 20 and pnpm >= 11.
```sh
pnpm install
pnpm verify # format, lint, typecheck, test, build
```
See [CONTRIBUTING.md](./CONTRIBUTING.md).
## License
[MIT](./LICENSE)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues