email.notetoself
Allows sending email notes to yourself via Gmail SMTP, using an app password for authentication.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
notetoself
A tiny MCP server that emails a note to yourself.
I set this up for personal use with the index01 ring.
Server name:
notetoselfTool:
send_note(message: str) -> strSubject:
NTS:+ first 20 characters of the noteBody: the full message, exactly as received
Transport: legacy SSE. Clients
GET /mcpto open the event stream and POST to/mcp/posts/for messages back.Auth: every request must carry
Authorization: Bearer <token>matching an entry inTOKENS_JSON
1. Install
cd notetoself
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txtRelated MCP server: Gmail MCP Server
2. Create a Gmail App Password
The server uses Gmail SMTP with an App Password (not your normal Gmail password).
Enable 2-Step Verification on the Google account that will send the email (https://myaccount.google.com/security).
Open https://myaccount.google.com/apppasswords and create an App Password.
App name: anything, e.g.
notetoselfGoogle shows you a 16-character password; copy it.
That's your
SMTP_PASS.
3. Configure
Copy .env.example to .env and fill in:
cp .env.example .env
$EDITOR .envSet at minimum:
Variable | Value |
|
|
| The 16-char App Password from step 2 |
|
|
| JSON array of allowed bearer tokens (see below) |
| Comma-separated list of allowed |
Generate a token:
python -c "import secrets; print(secrets.token_urlsafe(32))"Example TOKENS_JSON with a single trusted token:
TOKENS_JSON=["PASTE_TOKEN_HERE"]Multiple clients (each gets its own token):
TOKENS_JSON=["token-aaa","token-bbb"]ALLOWED_HOSTS lists the Host header values the MCP transport security
layer will accept. Defaults to loopback only. If you reach the server via
a reverse proxy on a public domain (e.g. https://yatesframe.com/mcp),
that domain must appear here or every request gets HTTP 421
("Invalid Host header"). The corresponding Origin header is whitelisted
automatically: loopback hosts pair with http://, everything else with
https://.
ALLOWED_HOSTS=127.0.0.1,localhost,[::1],yatesframe.com4. Run
python server.pyYou should see:
notetoself ready on 0.0.0.0:3001 (tokens=1, transport=sse)Smoke test from another shell:
curl http://localhost:3001/health
# {"status":"ok","server":"notetoself"}
# Open the SSE stream. The first event the server sends is the message
# post URL it expects clients to use. Use -N so curl streams the output
# instead of buffering until disconnect.
curl -N http://localhost:3001/mcp \
-H "Authorization: Bearer PASTE_TOKEN_HERE" \
-H "Accept: text/event-stream"The first line you receive is the endpoint event telling you where to
POST messages (it'll be /mcp/posts/?session_id=<hex>). You won't get a
plain tools/list response from curl -- real MCP clients (Claude
Desktop, Cursor, etc.) handle the SSE protocol end-to-end.
The body "remember to buy milk" will arrive at beernutz@gmail.com with subject NTS:remember to buy milk.
5. Wire up an MCP client
Claude Desktop
~/.config/Claude/claude_desktop_config.json:
{
"mcpServers": {
"notetoself": {
"type": "sse",
"url": "http://localhost:3001/mcp",
"headers": {
"Authorization": "Bearer PASTE_TOKEN_HERE"
}
}
}
}Note the type: "sse": this server uses the legacy SSE transport, not
streamable HTTP. The URL is /mcp (the SSE stream endpoint); the message
post URL is discovered automatically from the server's endpoint SSE
event.
If Claude Desktop runs on a different machine on the LAN, replace localhost with the server's LAN IP. Restart Claude Desktop. The send_note tool will show up in the tools list.
Other clients
Any MCP client that supports streamable HTTP works. Point it at
http://localhost:3001/mcp with the single Authorization header above.
File layout
notetoself/
|-- server.py # MCP server entry + Starlette wiring
|-- auth.py # ASGI middleware: bearer-token allowlist
|-- mailer.py # SMTP send + subject/body rules
|-- config.py # .env loading + validation
|-- requirements.txt
|-- .env.example # copy to .env and edit
|-- tests/
| `-- test_mailer_logic.py
|-- deploy/ # systemd unit + env file template + nginx config
| |-- notetoself.service
| |-- notetoself.env.example
| `-- nginx.conf.example
`-- README.md6. Run as a systemd service (Linux)
The repo ships a unit file in deploy/notetoself.service that runs the
server under a dedicated unprivileged user, restarts on failure, and reads
its config from /opt/notetoself/.env (in the app folder).
# 1. Pick an install root and clone/copy the repo there.
sudo install -d -o notetoself -g notetoself -m 0750 /opt/notetoself
sudo cp -r . /opt/notetoself/
sudo -u notetoself python3 -m venv /opt/notetoself/.venv
sudo -u notetoself /opt/notetoself/.venv/bin/pip install -r /opt/notetoself/requirements.txt
# 2. Install the env file in the app folder (mode 0600, owned by the service user).
sudo install -o notetoself -g notetoself -m 0644 \
deploy/notetoself.env.example /opt/notetoself/.env
sudo chmod 0600 /opt/notetoself/.env
sudo -u notetoself $EDITOR /opt/notetoself/.env
# 3. Install + enable the unit.
sudo cp deploy/notetoself.service /etc/systemd/system/notetoself.service
sudo systemctl daemon-reload
sudo systemctl enable --now notetoself.service
sudo systemctl status notetoself.serviceThe unit binds to 0.0.0.0:3001 (configurable via the env file) and logs to
the journal (journalctl -u notetoself.service -f).
7. Reverse proxy with nginx
If you're exposing the server on a public domain (e.g.
https://yatesframe.com/mcp), put nginx in front of uvicorn. SSE is
notoriously easy to break with default nginx settings, so use the
config in deploy/nginx.conf.example rather than rolling your own.
The two non-obvious requirements:
proxy_buffering off;— without it, nginx buffers the SSE stream and your MCP client times out before the first event arrives.No URI in
proxy_pass. Useproxy_pass http://127.0.0.1:3001;andlocation /mcp, notproxy_pass http://127.0.0.1:3001/mcp;. The URI form rewrites/mcp/posts/to/mcpposts/at the backend and breaks the message path.
Also make sure ALLOWED_HOSTS in the env file includes the public
domain — otherwise transport security rejects every request with 421.
# /etc/nginx/sites-enabled/notetoself (or included from your server block)
location /mcp {
proxy_pass http://127.0.0.1:3001;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header Authorization $http_authorization;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 1h;
proxy_send_timeout 1h;
chunked_transfer_encoding off;
}Security notes
The server binds to
0.0.0.0by default, which exposes it to anything that can reach the host onPORT. Put the box behind a firewall (drop inbound traffic to3001from untrusted networks), a reverse proxy with TLS, or restrictHOSTto a loopback address in the env file if you only need local clients.Authorizationheaders carry the bearer token in cleartext without TLS.MCP DNS-rebinding protection is on by default. The
ALLOWED_HOSTSlist governs whichHostheader values are accepted;Originheaders are matched against the same list with a sensible scheme prefix. Add every public domain the server will be reached under, or clients will see HTTP 421 "Invalid Host header".Tokens are compared with
secrets.compare_digest(constant-time).The server never logs message bodies, only
subject=...+body_chars=N.TOKENS_JSONshould be treated as a secret. Anyone with one of the listed tokens can email as you. Don't commit.envor the systemd env file.SMTP errors (wrong password, blocked sign-in, etc.) are returned to the calling LLM as plain text. Don't expose this server on a public network without thinking about that.
This server cannot be deployed
Maintenance
Related MCP Connectors
Give AI agents their own email inboxes: list, read and send mail via scoped, revocable OAuth grants.
Manage Gmail messages, threads, labels, drafts, and settings from your workflows. Send and organiz…
Email for AI agents: its own address, not your Gmail. Invite-only; requires an agent token.
Related MCP Servers
- AlicenseBqualityCmaintenanceEnables sending emails through Gmail using your Gmail credentials. Provides a simple send_email tool that accepts recipient, subject, and plain text body parameters.1MIT
- FlicenseNot gradedqualityDmaintenanceEnables sending emails through Gmail using Google's Gmail API. Requires OAuth authentication setup through Google Cloud Console.-
- AlicenseAqualityDmaintenanceEnables sending emails and creating drafts through the Gmail API with OAuth 2.0 authentication.211 npmMIT
- FlicenseNot gradedqualityDmaintenanceEnables sending emails via Gmail API, checking thread replies, and listing sent emails, all logged locally in SQLite.-