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.1.tar.gz (72.2 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.1-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: selfmail-0.1.1.tar.gz
  • Upload date:
  • Size: 72.2 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.1.tar.gz
Algorithm Hash digest
SHA256 7f4677f6f9cc6aa8b536301dec088521fd92f359070d1d0d90f99b97bf6c31ee
MD5 6fb49400808e0a36b86a17544bae1184
BLAKE2b-256 49dc597ebbd79de719b98b97dce57d8ac612d0140601374b2315d876d6061ba9

See more details on using hashes here.

Provenance

The following attestation bundles were made for selfmail-0.1.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: selfmail-0.1.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 fccf0efe65e44e152ddb38ea64965912ec0cebf57f8e598408023efecde25827
MD5 512566a199d5662d0324efaa214debe6
BLAKE2b-256 46b81e37485abcc0af67ebb2f9443a9910017820a9486aa9f26fe07f6916b527

See more details on using hashes here.

Provenance

The following attestation bundles were made for selfmail-0.1.1-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