Skip to main content

sessionmail

Mail for coding agents: message moves messages, pager alerts, memory is the filesystem view - three commands over one maildir.

Quick start

claude plugin marketplace add sessionkit/sessionmail
claude plugin install sessionmail
uv tool install sessionmail          # the commands the plugin calls
pager listen                         # blocks until mail arrives, then says so

Both of the first two lines need the repo and the release to be public: see Status, under Installation, before you copy them.

The last line is the point: an agent that runs pager listen in the background can be reached while it is idle, instead of finding out on its next manual check. Under an interactive Claude Code seat the plugin does it for you: its pager monitor listens from launch, on by default (see the pager monitor). The hand pager listen is for headless (claude -p) seats, seats where the monitor is switched off, and clients outside Claude Code.

message send NAME -s SUBJECT -f BODY.md   # and list, tree, read, mark
pager listen                              # block until mail; page; exit
pager status                              # what would page you now
memory ls / | memory cat PATH             # the box as a filesystem

Each command's own --help is the reference; <command> <verb> --help is the page for a verb.

Installation

Two installs, and you need both. The plugin brings the skills, the two hooks and the MCP servers; the package brings message, pager and memory, which is what all of those call.

claude plugin install sessionmail    # skills, hooks, MCP entries
uv tool install sessionmail          # the three commands on PATH

On Claude Code 2.1.275 or later the plugin installs from its marketplace in one step, from inside a session:

/plugin install sessionmail --marketplace sessionkit/sessionmail

With only the plugin, the hooks exit quietly and the MCP servers do not start: you get skills describing commands the machine does not have. The hook says so once per session rather than leaving you to guess.

Same-host mail needs no mail server.

  • message send writes each copy straight into this host's maildirs: the file drop, the default. Mail to another host is refused by name.
  • Reading needs no server either: message list, tree, read and mark, pager and memory all read the maildir directly.
  • Mail across machines goes through postfix, which is opt-in: postfix configuration.

Then make the host ready with message setup: message setup.

message setup --dry-run          # print the plan; change nothing
message setup --box NAME         # the mail root, the boxes, the notmuch profile
notmuch --config="$HOME/.config/notmuch/sessionkit/config" new   # once, as setup says
message setup                    # again: it links the notmuch hook
  • It makes the mail root, the operator's box and each --box NAME (the file drop never makes a box), and sessionmail's own notmuch profile. It links notmuch's post-new hook into that profile's hook folder. It prints its whole plan before it applies any of it, and it is safe to re-run.
  • It never touches your own notmuch config, never edits postfix, and writes no settings key.
  • Nothing runs notmuch new for you. message mark and memory read an empty index until something does: launchd, cron, or by hand.

Status. sessionmail 0.0.1 on PyPI is a name reservation, not this code - a 1.3 KB placeholder with no dependencies. Until 0.2.0 ships, install from source instead of the uv tool install sessionmail line above:

uv tool install git+https://github.com/sessionkit/sessionmail   # from the repo
make install                                                    # from a clone

message, pager and memory all run; the specs, in the git repository (the release archive leaves them out), say what each verb is meant to do and make progress counts how much of it is built.

Uninstall

claude plugin uninstall sessionmail                  # skills, hooks, MCP entries
uv tool uninstall sessionmail                        # the three commands
rm ~/.mail/.notmuch/hooks/post-new ~/.mail/.notmuch/hooks/post-insert   # the linked hook (in notmuch's database.hook_dir)
notmuch --config="$HOME/.config/notmuch/sessionkit/config" config set sessionmail.post_new_command   # the optional command, off
rm ~/.config/notmuch/sessionkit/config               # sessionmail's notmuch profile (its index stays in ~/.mail/.notmuch)

Configuration

Which files, which environment variables, and where each one lives, one component at a time: configuration.

  • sessionmail: ~/.sessionkit/mail/settings/mail.json for the host, and one for a seat or a session if you want them. Its keys: settings.
  • postfix, only to send: /etc/postfix/main.cf, root's and set once, and the two maps the generator writes as you, in /usr/local/etc/postfix-agents/.
  • notmuch, the index: sessionmail's own profile, ~/.config/notmuch/sessionkit/config. Your own ~/.notmuch-config is never read.
  • Environment variables: each settings key has one (the sendmail key's is SESSIONMAIL_SENDMAIL). When it is set and not empty, it wins over the file.

Logs

sessionmail keeps four logs. Each is written only when it has something to record:

  • ~/.session/sessions/<session-id>/log/mail/pager.jsonl: one row for each thing the pager put into an agent's context, sizes and Message-IDs only (the pager log). Past 16 MB it becomes pager.1.jsonl.
  • ~/.session/sessions/<session-id>/log/settings.jsonl, and the same file under ~/.session/seats/<seat>/: each settings change for that session or seat, such as a subscription or its address, with the command that made it.
  • ~/.mail/.state/regen-failures.log: each time the map generator refused to rewrite the alias map, and why.
  • ~/.sessionmail/post-new/log: the post-new command's runs and output, only once you set one. Past 1 MiB it becomes log.1.

Follow one as it grows with tail -F, for example tail -F ~/.mail/.state/regen-failures.log. pager status ends its today: line with the path of this session's pager.jsonl.

  • Health: pager status, run by the agent. monitor: armed (pid N), or a hand pager listen named on that line, means something is listening for its mail; not armed or off alone means nothing is. Exit 2 means it could not look (no session, or no box yet). It does not test sending: message send exits 3 when the mail server did not take the message.

Docs

Everything else is in docs/, one subject per file:

Metadata

Release files for sessionmail 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sessionmail 0.2.0
File Size Uploaded Provenance
sessionmail-0.2.0.tar.gz 628.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for sessionmail 0.2.0
File Interpreter ABI Platform
sessionmail-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / sessionmail-0.2.0.tar.gz

Download URL sessionmail-0.2.0.tar.gz
Size 628.7 kB
Tags Source
SHA-256 checksum
How to use checksums
44589b77ff00bf2a79390a5df1eec299e9313552bffcbe24385a7b9f1fefa90a
BLAKE2b-256 checksum
How to use checksums
20a84fe8aae9bafb19b047fc9ddbdc785dd41bb5fdc12382bd9b8bf87deec8ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / sessionmail-0.2.0-py3-none-any.whl

Download URL sessionmail-0.2.0-py3-none-any.whl
Size 667.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9019aa16590f819e0d7107ea90cae9c8f2e8529a95f53140afc827c758233741
BLAKE2b-256 checksum
How to use checksums
5c1c4a555f51140d6c4d7c2c69d93b6405bfcd799a03b08c7656f9e25244b94d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for sessionmail 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page