Metadata-Version: 2.4
Name: selfmail
Version: 0.1.2
Summary: Email yourself from any shell or AI agent — one tiny command over Resend.
Project-URL: Homepage, https://github.com/alltuner/selfmail
Project-URL: Source, https://github.com/alltuner/selfmail
Author: alltuner
License-Expression: MIT
License-File: LICENSE
Keywords: agent,cli,email,mcp,notify,resend
Requires-Python: >=3.11
Requires-Dist: resend<3,>=2.0
Requires-Dist: tomli-w>=1.0
Requires-Dist: typer>=0.12
Provides-Extra: mcp
Requires-Dist: mcp>=1.2; extra == 'mcp'
Description-Content-Type: text/markdown

# selfmail

**Email yourself from any shell or AI agent — one tiny command, over [Resend](https://resend.com).**

```bash
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:

```bash
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:

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

Requires Python 3.11+.

## Quick start

```bash
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**

```bash
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](https://modelcontextprotocol.io) 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.

```bash
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`:

```toml
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 |

```bash
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 server** — `selfmail 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.

### Agent skill

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:

```bash
npx skills add alltuner/skills --skill selfmail
```

See [`alltuner/skills`](https://github.com/alltuner/skills) (the skill lives at
[`skills/selfmail/SKILL.md`](https://github.com/alltuner/skills/blob/main/skills/selfmail/SKILL.md)).

## Development

```bash
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:

```bash
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](LICENSE)
