feat: emit a signed Reply-To by default, --anonymous to omit

This commit is contained in:
randogoth 2026-09-26 16:45:41 +03:00
parent 5bfb415830
commit 56a6ed1186
2 changed files with 7 additions and 0 deletions

View file

@ -70,6 +70,8 @@ uv run smolmail.py list
uv run smolmail.py read <id>
```
Sent mail carries the sender's full `smol://` address in a signed `Reply-To` field (SPEC.md §5.7), so a first-time recipient can answer without an out-of-band channel; pass `--anonymous` to omit it.
`import` adds a contact from a `smol://` address without trusting any server, `contacts` lists known keys and how each was learned, and `rotate` replaces the identity with a signed certificate your contacts accept automatically.
Mail is stored sealed and opened on demand, so the local database holds no plaintext. Superseded keys are retained after a rotation, because mail already addressed to them is readable with nothing else.

View file

@ -680,6 +680,9 @@ def cmd_send(args: argparse.Namespace, store: Store) -> int:
if not sep or not FM_KEY.match(key.strip()):
raise SmolError(f"{raw!r} is not a valid `Key: value` header")
fields.append((key.strip(), value.strip()))
# §5.7: a signed reply address lets a first-time recipient answer us.
if (account := store.account()) is not None and not args.anonymous:
fields.append(("Reply-To", account.uri(me.pk)))
body = build_frontmatter(fields, text).encode()
envelope = seal(me, recipient, body, pad=not args.no_pad)
@ -828,6 +831,8 @@ COMMANDS = [
(("--body",), {"help": "message text; read from stdin when omitted"}),
(("--header",), {"action": "append", "metavar": "KEY:VALUE",
"help": "extra frontmatter field; repeatable"}),
(("--anonymous",), {"action": "store_true",
"help": "omit the Reply-To field carrying this address (SPEC.md §5.7)"}),
(("--no-pad",), {"action": "store_true", "help": "do not pad to 1 KiB"})]),
("fetch", cmd_fetch, "retrieve, verify and acknowledge mail",
[(("--keep",), {"action": "store_true", "help": "do not delete from the server"})]),