Skip to main content

Email yourself from any shell or AI agent — one tiny command over Resend.

Project description

selfmail

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.


Install

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 pipx

For the MCP server, pull the optional extra:

uvx --from 'selfmail[mcp]' selfmail mcp
uv tool install 'selfmail[mcp]'

Requires Python 3.11+.

Quick start

selfmail init      # paste a Resend API key once — it emails you a test message
selfmail "done"    # send yourself a note

init 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).


Commands

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.

selfmail [body] — send

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 success

selfmail init — configure

Interactive 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:

  1. If you're already configured and the key authenticates, it says so and exits (unless --force).
  2. 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.
  3. Reads the key with no echo (never shown, never stored in shell history).
  4. Asks for your email — where selfmail should send.
  5. 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.
  6. 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.
  7. Writes the config file with 0600 permissions.

selfmail doctor — check configuration

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

selfmail mcp — MCP server

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 mcp

Tool:

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.


Configuration

Values are resolved in this order (highest priority first):

command-line flag → environment variable → config file → built-in default

Config file

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"

Environment variables

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"

Sending to addresses other than yourself

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.

Exit codes

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).

For agents

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 serverselfmail mcp exposes the send_email tool 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.

Development

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

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

selfmail-0.1.0.tar.gz (70.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

selfmail-0.1.0-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file selfmail-0.1.0.tar.gz.

File metadata

  • Download URL: selfmail-0.1.0.tar.gz
  • Upload date:
  • Size: 70.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for selfmail-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2ea13c986ea1270f74a8769b6f54f31b476b6e73807533467e4181232eeb5dd6
MD5 67a42592b64cf85bb4815741d9bae8fa
BLAKE2b-256 95d743dc2000739ebf4cd7271115032c8e31072c3ea026f5c5d8388c8d0b635a

See more details on using hashes here.

Provenance

The following attestation bundles were made for selfmail-0.1.0.tar.gz:

Publisher: release.yml on alltuner/selfmail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file selfmail-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: selfmail-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for selfmail-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ddfcf143f6f9eab2885c41b5e64d62d9a6f87646b03816cca1f8d53f8f5fbc13
MD5 d206f5a542e288ef073a5fd338f901fb
BLAKE2b-256 e0b607e4376544424a29844a3778cb18694d5dab97d6a0ab8feac0706ca9712c

See more details on using hashes here.

Provenance

The following attestation bundles were made for selfmail-0.1.0-py3-none-any.whl:

Publisher: release.yml on alltuner/selfmail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page