smtp-mcp-wrapper
Sends real HTML email through Gmail's SMTP relay, allowing MCP clients to send emails using a Gmail account.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@smtp-mcp-wrappersend an email to user@example.com with subject 'Update' and body 'All good'"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
smtp-mcp-wrapper
A minimal, self-hosted MCP server that exposes a
single send_email tool. It sends real HTML email through an SMTP relay (e.g. Gmail).
The tool is served over the streamable-HTTP MCP transport at /mcp, with an
unauthenticated /healthz liveness route. The implementation is intentionally tiny
(stdlib smtplib) to keep the audit/attack surface small.
⚠️ Security requirement: this server MUST be gated by an authorization service
This server implements no authentication of its own, by design. Anyone who can reach
/mcp can send email. Do not expose it directly to the internet or bind it to a public
port.
It must sit behind an identity-aware authorization proxy — such as
Pomerium in MCP mode, or an
equivalent like Cloudflare Access
or oauth2-proxy — that authenticates and
authorizes every request before it reaches /mcp.
Reference topology:
edge tunnel → reverse proxy (TLS) → Pomerium (SSO + allowlist to a single identity) → smtp-mcp-wrapper
(internal network only)The provided docker-compose.yml deliberately publishes no host ports and attaches
the container only to the proxy's internal Docker network, so the server is unreachable
except through the authorization proxy.
Defense in depth already built in (these complement, they do not replace, the proxy):
ALLOWED_TOhard-limits recipients, so even a misused tool cannot mail outside the allowlist.Setting
REQUIRE_POMERIUM_IDENTITY=truemakes the app itself reject/mcprequests that arrive without a Pomerium identity header (x-pomerium-assertionby default) — a backstop in case the proxy is ever misconfigured or bypassed.
Related MCP server: Mail MCP Server
Configuration
All configuration is via environment variables. Copy .env.example to .env and fill in
real values. .env is git-ignored and must stay that way — it holds the SMTP password.
Nothing secret is baked into the image (credentials are injected at runtime), which is why
the published container image can safely be public.
Variable | Default | Description |
|
| SMTP relay host. |
|
| SMTP relay port (STARTTLS). |
| — | SMTP username. |
| — | SMTP password. For Gmail, use an App Password. |
|
| From address. |
| — | Optional display name for the From header. |
| — | Recipient used when the tool's |
| — | Comma-separated recipient allowlist. Empty = any recipient allowed. |
|
| Also enforce a Pomerium identity header at the app layer. |
|
| Header checked when the above is |
|
| Server bind address/port. |
The send_email tool
send_email(subject: str, html: str, to?: str, text?: str) -> strSends an HTML email. to falls back to DEFAULT_TO and must be within ALLOWED_TO when
that allowlist is set. text is an optional plain-text alternative for non-HTML clients.
Run
cp .env.example .env # then edit .env with real values
docker compose up -dHealth check:
docker compose exec email-mcp \
python -c "import urllib.request; print(urllib.request.urlopen('http://localhost:8080/healthz').read())"
# -> b'ok'Then add the email-mcp route to your authorization proxy (pathless upstream, e.g.
to: http://email-mcp:8080, so the /mcp path passes through) and connect your MCP
client to https://<your-host>/mcp.
Maintenance
Patches flow with near-zero manual effort:
Dependabot (
.github/dependabot.yml) watchesrequirements.txt, the Dockerfile base image, and the workflow's actions, opening upgrade PRs weekly. Also enable Dependabot security updates in the repo's Settings → Code security.CI (
.github/workflows/build.yml) builds and pushes the image to GHCR on push tomain, on Dependabot PRs, via manual dispatch, and weekly (Mon 06:00 UTC) withno-cacheso the OS and Python patches are genuinely refreshed even without code changes.On the host, pull the rebuilt image with Watchtower (the compose file already sets the opt-in label) or a cron running
docker compose pull && docker compose up -d.
Links
Pomerium — MCP support
Pomerium — Protect an MCP server
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/JB09/smtp-mcp-wrapper'
If you have feedback or need assistance with the MCP directory API, please join our Discord server