# mail-smtp-mcp
TypeScript MCP (stdio) server for sending email via SMTP with a compact, LLM-optimized tool surface.
## Overview
This server exposes outcome-oriented tools to validate SMTP accounts and send outbound email with
strict policy controls. Responses are JSON-encoded text and include:
- `summary`: concise human-readable summary
- `data`: structured payload aligned to the tool contract
- `_meta`: optional metadata (e.g., policy limits)
## Capabilities
### Read-only
- List configured SMTP accounts (non-secret metadata)
- Verify SMTP connectivity/authentication (no email sent)
### Send (gated)
- Send outbound email with text/HTML bodies
- Optional attachments (bounded)
- `dry_run` to validate inputs and policy without sending
## Tools
### `mail_smtp_list_accounts`
List configured SMTP accounts.
### `mail_smtp_verify_account`
Verify a configured SMTP account can connect/authenticate.
Inputs include:
- `account_id` (default: `default`)
### `mail_smtp_send_message`
Send or validate an outbound email via SMTP.
Inputs include:
- `account_id` (default: `default`)
- `from` (optional; falls back to account default)
- `to`, `cc`, `bcc` (string or string[])
- `reply_to` (optional)
- `subject` (required; header-injection safe)
- `text_body` and/or `html_body` (at least one required)
- `attachments` (optional; base64 content)
- `dry_run` (optional; default false)
## Configuration
Account configuration is provided via environment variables.
This server also loads a local `.env` file (if present) using `dotenv`. Do not commit secrets.
An example is provided in `.env.sample`.
If you only configure the `default` account, you can omit `account_id` in tool calls; it defaults
to `default`.
```
MAIL_SMTP_DEFAULT_HOST
MAIL_SMTP_DEFAULT_PORT=587
MAIL_SMTP_DEFAULT_SECURE=false
MAIL_SMTP_DEFAULT_USER
MAIL_SMTP_DEFAULT_PASS
MAIL_SMTP_DEFAULT_FROM
```
Multiple accounts are supported by replacing `DEFAULT` with an uppercase account ID:
```
MAIL_SMTP_WORK_HOST
MAIL_SMTP_WORK_USER
MAIL_SMTP_WORK_PASS
```
### Send gate
Sending is disabled by default. Enable with:
```
MAIL_SMTP_SEND_ENABLED=true
```
### Allowlist policy (optional)
If set, only allowlisted recipients/domains can be used:
```
MAIL_SMTP_ALLOWLIST_DOMAINS=example.com,example.org
MAIL_SMTP_ALLOWLIST_ADDRESSES=alice@example.com,bob@example.org
```
### Policy/limits defaults
These defaults apply unless overridden via environment variables:
```
MAIL_SMTP_MAX_RECIPIENTS=10
MAIL_SMTP_MAX_MESSAGE_BYTES=2500000
MAIL_SMTP_MAX_ATTACHMENTS=5
MAIL_SMTP_MAX_ATTACHMENT_BYTES=2000000
MAIL_SMTP_MAX_TEXT_CHARS=20000
MAIL_SMTP_MAX_HTML_CHARS=50000
MAIL_SMTP_CONNECT_TIMEOUT_MS=10000
MAIL_SMTP_SOCKET_TIMEOUT_MS=20000
```
## Response shape (JSON text)
Many MCP clients expect `content` items to be `type: "text"` (and do not accept a JSON content
type). This server returns a single `text` content item whose text is a JSON object:
```
{
"summary": "Sent message to 1 recipient(s).",
"data": {
"account_id": "default",
"dry_run": false,
"envelope": {
"from": "me@example.com",
"to": ["alice@example.com"]
},
"message_id": "<abc123@example.com>",
"accepted": ["alice@example.com"],
"rejected": []
}
}
```
## Usage
### Run locally
```
pnpm install
pnpm dev
```
### Build
```
pnpm build
```
## Chat Application Integration (stdio spawn command)
Many MCP-enabled chat applications run stdio servers by spawning a process from an executable
command. These are common ways to invoke this server:
### Option 1: Run via npx (published package)
- `command`: `npx`
- `args`: `-y mail-smtp-mcp`
### Option 2: Run from this repo (dev, no build)
- `command`: `pnpm`
- `args`: `-C /Users/jonathan/Code/Projects/mail-smtp-mcp dev`
### Option 3: Run from this repo (built)
1. Build once:
```
pnpm -C /Users/jonathan/Code/Projects/mail-smtp-mcp build
```
2. Spawn:
- `command`: `node`
- `args`: `/Users/jonathan/Code/Projects/mail-smtp-mcp/dist/index.js`
### Option 4: Install globally (true executable)
1. Install:
```
pnpm -g add /Users/jonathan/Code/Projects/mail-smtp-mcp
```
2. Spawn:
- `command`: `mail-smtp-mcp`
### Example MCP server config
Exact configuration keys vary by chat application, but the shape usually looks like:
```json
{
"command": "node",
"args": ["mail-smtp-mcp/dist/index.js"],
"env": {
"MAIL_SMTP_DEFAULT_HOST": "smtp.example.com",
"MAIL_SMTP_DEFAULT_USER": "me@example.com",
"MAIL_SMTP_DEFAULT_PASS": "app-password-or-token",
"MAIL_SMTP_SEND_ENABLED": "true"
}
}
```
### Quality gates
```
pnpm check
```
## Notes
- Sending is gated by `MAIL_SMTP_SEND_ENABLED=true`.
- Use `dry_run` to validate payloads without sending.
- Inputs reject header injection characters and enforce size limits.
- Do not log or return credentials; outputs contain non-secret metadata only.