Email yourself from any shell or AI agent — one tiny command, over Resend.
uvx selfmail "the build is green"selfmail sends an email to a pre-configured "me" address with no ceremony. It runs
anywhere — your laptop, a cron job, a cloud runner, or an AI agent — with no GUI and no
local mail server. After a one-time selfmail init, sending is a single command.
selfmail is a single pure-Python package on PyPI. The zero-install path is best:
uvx selfmail "hello" # run without installing (recommended)
uv tool install selfmail # install the `selfmail` command on PATH
pipx install selfmail # same, via pipxFor the MCP server, pull the optional extra:
uvx --from 'selfmail[mcp]' selfmail mcp
uv tool install 'selfmail[mcp]'Requires Python 3.11+.
selfmail init # paste a Resend API key once — it emails you a test message
selfmail "done" # send yourself a noteinit deep-links you to the Resend create-key page, captures the key without echoing
it, and proves the whole pipeline by emailing you on the spot — no DNS setup needed
(Resend's shared sender delivers to your own account address).
selfmail [body] send an email (this is the default command)
selfmail init configure: paste a Resend key, get a test email
selfmail doctor check configuration without sending
selfmail mcp run an MCP server exposing a send_email tool
selfmail --version print the version
Run selfmail <command> --help for a command's options.
The default command. With no subcommand, selfmail sends an email.
selfmail [-s SUBJECT] [-a FILE]... [--html] [--to TO] [--from SENDER] [-q] [body]
| Argument / flag | Description |
|---|---|
body |
The message body. Optional — if omitted and stdin is not a TTY, the body is read from stdin. If neither is given, the body is (no body). |
-s, --subject TEXT |
Subject line. Default: a timestamp like selfmail 2026-06-16 14:05. |
-a, --attach FILE |
Attach a file. Repeatable: -a a.pdf -a b.png. |
--html |
Treat the body as HTML (sets the HTML part instead of plain text). |
--to ADDR |
Override the configured recipient for this send. |
--from ADDR |
Override the configured sender for this send. |
-q, --quiet |
Suppress the sent → … success line. |
On success it prints sent → you@example.com (id <message-id>) and exits 0.
Examples
selfmail -s "build finished" "all green on main" # subject + inline body
echo "$(tail -50 build.log)" | selfmail -s "log tail" # body from stdin (pipe)
some-command 2>&1 | selfmail -s "cron output" # capture a command's output
selfmail -s "the report" -a report.html "see attached" # with an attachment
selfmail --html "<h1>Shipped</h1><p>v1.2 is live.</p>" # HTML body
selfmail --to ops@example.com "heads up" # one-off different recipient
selfmail -q "silent ping" # no stdout on successInteractive first-run setup. Resend has no OAuth or programmatic key provisioning, so
the key is minted in your dashboard and pasted in — init makes that one step painless.
selfmail init [--force] [--domain]
| Flag | Description |
|---|---|
--force |
Reconfigure even if a working config already exists. |
--domain |
Also print the steps to verify your own sending domain. |
What it does:
- If you're already configured and the key authenticates, it says so and exits
(unless
--force). - Deep-links you to
https://resend.com/api-keys?new=true(opens the create-key dialog directly), and tells you to create a key with Sending access. - Reads the key with no echo (never shown, never stored in shell history).
- Asks for your email — where
selfmailshould send. - Sends a real test email from the shared sender to that address (works with no domain), which both validates the key and proves delivery. A bad key re-prompts; nothing is saved until a send succeeds.
- Asks which address to send from. There is no silent default: you either accept
the shared
onboarding@resend.dev(self-only) or enter your own verified-domain sender. - Writes the config file with
0600permissions.
Validates the resolved configuration without sending. Prints a summary and exits
0 if usable, 2 otherwise. Never prints the secret.
$ selfmail doctor
backend: resend
from: onboarding@resend.dev
to: you@example.com
api key: present
auth: ok
config: /Users/you/.config/selfmail/config.toml
Runs a Model Context Protocol server over stdio,
exposing a single tool so AI agents can email you directly. Requires the mcp extra
(selfmail[mcp]); without it, the command exits 2 with an install hint.
uvx --from 'selfmail[mcp]' selfmail mcpTool:
send_email(subject: str, body: str, to?: str, html?: bool) -> {"id": str, "to": str}
It uses the same configuration as the CLI — no separate setup.
Values are resolved in this order (highest priority first):
command-line flag → environment variable → config file → built-in default
Written by selfmail init to ~/.config/selfmail/config.toml (or
$XDG_CONFIG_HOME/selfmail/config.toml), with mode 600:
to = "you@example.com"
from = "onboarding@resend.dev"
[resend]
api_key = "re_xxx"For CI, cron, or cloud boxes, skip the file entirely and set:
| Variable | Maps to |
|---|---|
RESEND_API_KEY |
the Resend API key |
SELFMAIL_TO |
the recipient ("me") |
SELFMAIL_FROM |
the sender — required (there is no built-in default; init sets it) |
SELFMAIL_CONFIG |
full path to an alternate config file |
export RESEND_API_KEY=re_...
export SELFMAIL_TO=you@example.com
selfmail "from CI"Resend's shared sender, onboarding@resend.dev, only delivers to your own Resend
account address — which is all "email myself" needs, and what init offers by default.
To send from your own domain (and to anyone), verify a domain in Resend and set from
accordingly. If your DNS is on
Cloudflare, selfmail init --domain points you at Resend's one-click Cloudflare
integration, which auto-creates the MX/SPF/DKIM records.
| Code | Meaning |
|---|---|
0 |
Success. |
1 |
The send failed (network error, or Resend rejected the message). |
2 |
Configuration or usage error (no key, bad flag, missing recipient, unreadable attachment). |
selfmail is built to be driven by AI agents two ways:
- As a shell command — any agent that can run a shell can
selfmail -s "…" "…". - As an MCP server —
selfmail mcpexposes thesend_emailtool over stdio.
Because it reads config from the environment, an agent in a headless sandbox just needs
RESEND_API_KEY and SELFMAIL_TO set to start emailing you.
There's a ready-made agent skill so coding agents (Claude Code, etc.) discover and use
selfmail automatically — it bundles the invocation, usage patterns, exit codes, and
gotchas:
npx skills add alltuner/skills --skill selfmailSee alltuner/skills (the skill lives at
skills/selfmail/SKILL.md).
uv sync # install deps (incl. dev group)
uv run ruff check . # lint
uv run ruff format . # format
uv run ty check # type-check
uv run pytest # tests (unit tests mock the Resend SDK boundary)There's an opt-in end-to-end test that sends a real email — skipped unless you provide real credentials:
SELFMAIL_LIVE_TEST=1 RESEND_API_KEY=re_... SELFMAIL_LIVE_TO=you@example.com \
SELFMAIL_FROM=you@yourdomain.com uv run pytest -k live