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 summarydata: 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_runto 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_bodyand/orhtml_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:npxargs:-y mail-smtp-mcp
Option 2: Run from this repo (dev, no build)
command:pnpmargs:-C /Users/jonathan/Code/Projects/mail-smtp-mcp dev
Option 3: Run from this repo (built)
-
Build once:
pnpm -C /Users/jonathan/Code/Projects/mail-smtp-mcp build -
Spawn:
command:nodeargs:/Users/jonathan/Code/Projects/mail-smtp-mcp/dist/index.js
Option 4: Install globally (true executable)
-
Install:
pnpm -g add /Users/jonathan/Code/Projects/mail-smtp-mcp -
Spawn:
command:mail-smtp-mcp
Example MCP server config
Exact configuration keys vary by chat application, but the shape usually looks like:
{
"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_runto 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.