Skip to main content

mail-notify

E-mail notifications for Claude Code, with a local settings web app. A small daemon on your own computer mails you when Claude finishes a long task, needs a permission, hits an error or a usage limit, or when your background processes finish. You can answer from your phone by replying to the mail.

Naming: the package and the command are mail-notify; the daemon and the Python module inside are called ccmail (ccmail also works as a command).

CI Python Dependencies License

  • Few mails, on purpose. Every mail passes several gates (turn length, cooldown, hourly cap, event types). Turning it on or off sends nothing.
  • Private by design. Standard library only, no telemetry. The only thing that leaves your machine is the mail itself, sent through your own mail account. The password lives in your system's credential store.
  • Reply to act. Reply OFF, ON or PAUSE 60 to a notification or, if you enable it, write a sentence that is delivered to the Claude chat that sent the mail.
  • Understands your chats. Mails name the project, the chat and your Claude account, and carry a short summary of what Claude said (about 300 characters, at most 10 lines; the complete answer follows in a scrollable box).
  • Works while you are away. While background tasks run, Claude is woken at a period you choose, only when tasks exist, to report their status.

Tested today: Windows with Gmail. macOS, Linux and mail providers other than Gmail (the Outlook, iCloud and Yahoo presets) are implemented and covered by the automated tests in CI, but are not yet tested on a real system: that is planned for a later release. Please report what you find.

Install step by step

You need your mail account's app password and about fifteen minutes. Run every command in your own terminal. ccmail never asks Claude for your password.

Requirements

  • Python 3.10 or newer.
  • Claude Code, as the CLI or the desktop app.
  • A mail account that allows SMTP with an app password. Presets exist for Gmail, Outlook, iCloud and Yahoo, and you can enter any SMTP server.
  • Optional, for replies by mail: IMAP access to the same mailbox.

Step 1: install the package

Pick one way. All three put the program in its own environment or in your user folder, nothing system-wide.

With pipx (recommended). pipx keeps the program isolated:

pipx install mail-notify

If the terminal says pipx is not recognised, install pipx first (once), then close and reopen the terminal:

python -m pip install --user pipx
python -m pipx ensurepath

With uv, if you already use uv:

uv tool install mail-notify

With plain pip, no extra tool needed:

python -m pip install --user mail-notify

(On Windows you may have py instead of python: py -m pip install --user mail-notify.)

To install the development version from the repository instead of PyPI, replace mail-notify with git+https://github.com/lobascioemanuele-droid/mail-notify in any of the commands above.

If, afterwards, the terminal says mail-notify is not recognised (typical with Microsoft Store Python, whose Scripts folder is not on PATH), type python -m ccmail in place of mail-notify for steps 2 and 3. setup (step 3) creates the short mail-notify command in a folder that is already on PATH, and when the command is not available in the terminal you are using it prints the next steps with python -m ccmail already filled in.

Step 2: set up the sender account

mail-notify init

The prompts ask for the sender address, the provider (the right app-password link is shown for it), the app password, the recipient (it defaults to the sender) and an optional device name. The app password is typed in a hidden prompt and stored only in the system credential store (Windows Credential Manager, macOS Keychain or Linux Secret Service). Never paste it into a chat, a file or an issue. This step sends no mail.

Where to create an app password:

Gmail, step by step: create the app password

An app password is a 16-letter password that Google generates for one program only. It is not your Google password, it can be revoked at any time, and it works only if 2-step verification is on.

  1. Open https://myaccount.google.com/security and sign in with the Gmail account that will send the mails.
  2. Under "How you sign in to Google", make sure 2-Step Verification is On. If it is not, open it and follow the steps (a phone number or an authenticator app); the app-password page does not appear without it.
  3. Open https://myaccount.google.com/apppasswords. If the page says the setting is not available, go back to point 2 (or see the notes below).
  4. In "App name" type something recognisable, for example mail-notify, and press Create.
  5. Google shows a 16-letter password in a yellow box, in four groups of four. Copy it now: it is shown only once. If you lose it, delete it from the same page and create another.
  6. In your own terminal run mail-notify init. Answer the prompts:
    • sender address: the Gmail address from point 1;
    • provider: gmail;
    • app password: paste the 16 letters (the prompt is hidden, so nothing appears; spaces are ignored; right-click pastes in most Windows terminals);
    • recipient: press Enter to send the notifications to the same address, or type another one.
  7. Check it: mail-notify on, then mail-notify test. A mail should arrive within a minute (look in Spam the first time). If it does not, mail-notify doctor --network says which step fails.

Notes:

  • Work or school Google accounts (Google Workspace) may have app passwords disabled by the administrator. In that case use a personal Gmail address as sender, and the work address as recipient if you wish.
  • The same app password is used to read your replies (IMAP) when reply-by-mail is on; no second password is needed.
  • To revoke it: open https://myaccount.google.com/apppasswords again and delete the mail-notify entry. Then run mail-notify init with a new one.
  • Never paste the app password into a chat, a file or an issue, and do not send it to anyone.

Step 3: install the hooks, the skill and the short command

mail-notify setup --autostart

One command does all of this, and sends nothing:

  • adds ccmail's hooks to Claude Code's settings, ~/.claude/settings.json (when the file already exists, a copy named settings.json.bak-<date> is made first);
  • copies the /mail-notify skill to ~/.claude/skills/mail-notify/;
  • creates the short mail-notify command if it is missing (on Windows it is a small mail-notify.cmd file in %LOCALAPPDATA%\Microsoft\WindowsApps; on macOS and Linux a script in ~/.local/bin);
  • creates the data folder with the local database (Windows: %APPDATA%\ccmail);
  • with --autostart, starts the background daemon at logon. This changes your system: on Windows it adds a Task Scheduler task, on macOS a launchd agent, on Linux a systemd user unit (or an autostart entry). Leave the option out if you prefer to start the daemon yourself with mail-notify open. To undo it later: mail-notify uninstall-hooks --autostart, uninstall-skill and uninstall-cli.

It never asks for the password (that is init, step 2) and can be run again at any time. The three parts are also available one by one: install-hooks, install-skill and install-cli. Steps 2 and 3 can be done in either order.

Good to know on the first run:

  • Right after setup, and before init, mail-notify doctor and status report the missing credentials ([FAIL] Credentials not configured). That is expected: run init and the message goes away.
  • The daemon starts by itself at the first Claude Code event, or immediately with mail-notify open, which opens the settings page in your browser. If no browser can be opened (SSH, WSL), it prints a one-time link instead: open it in a browser on the same computer within 60 seconds.
  • Language. The program's messages follow the language setting of Claude Code, then the system language, so on an Italian system you see Italian even though this guide is in English. To force a language for one terminal, set CCMAIL_LANG=en (or it); for the web app and the e-mails use the Language setting in the web app (Auto, Italiano, English).

Alternative for step 3: install the skill from Claude Code (plugin)

Instead of copying the skill with setup, you can add this repository as a Claude Code plugin marketplace and install the skill from inside Claude Code:

mail-notify setup --autostart --no-skill

Then, in Claude Code:

/plugin marketplace add lobascioemanuele-droid/mail-notify
/plugin install mail-notify@mail-notify

The skill then runs as /mail-notify:mail-notify status (Claude Code prefixes a plugin's skills with the plugin name). The plugin carries only the skill: the program, the hooks and the daemon still come from steps 1 to 3. Use one of the two ways, not both.

Step 4: restart Claude Code

Close and reopen Claude Code: hooks and skills are read at startup. After that /mail-notify appears in the list of skills.

Step 5: turn it on and test it

mail-notify on

Notifications are off after installation, so nothing is sent until you run this. on sends no mail.

mail-notify test

This sends one test mail. It also works while notifications are off.

mail-notify open

This opens the settings web app in your browser. It listens on 127.0.0.1 only and uses a one-time sign-in link. Optionally, in its Rules tab, turn on:

  • Control by replying to the e-mail (reply OFF / ON / PAUSE; needs IMAP, see above).
  • Replies reach Claude (free-text replies are delivered to the chat that sent the mail).
  • E-mail with buttons (an HTML version with tappable quick-reply cards).

Step 6: use it

In Claude Code, the /mail-notify skill accepts on, off, status, test and open:

/mail-notify on
/mail-notify status

Each project also has its own switch in the web app's Activity tab.

When reply control is on, each mail tells you how to reply. Write one of these on the first line of your reply:

  • OFF: turns notifications off for that project.
  • ON: turns them back on for that project.
  • PAUSE 60 (or SLEEP, or PAUSE alone for 60 minutes): silence on all projects for that many minutes.

Updating

Update the package (use the command that matches how you installed it):

pipx upgrade mail-notify
pipx install --force git+https://github.com/lobascioemanuele-droid/mail-notify

Then refresh the hooks and the skill, and restart Claude Code:

mail-notify setup

Uninstalling

Stop the daemon, then remove the pieces in this order:

mail-notify stop
mail-notify uninstall-hooks --autostart
mail-notify uninstall-skill
mail-notify uninstall-cli
pipx uninstall mail-notify

Uninstalling does not delete the data folder or the stored password. Delete the data folder yourself (on Windows %APPDATA%\ccmail), remove the ccmail entry from your credential store (on Windows it is ccmail:smtp in Credential Manager), and revoke the app password at your mail provider.

What a mail looks like

  • Header: Project:, Account: and Chat: (the chat's name in the desktop app, or Session: with a short id when the name is unknown). Device: appears when you set a device name. Turn duration and type follow for a finished turn.
  • OUTCOME (ESITO in Italian): a short summary of the whole answer, about 300 characters (the summary_chars setting) and at most 10 lines: a lead, one line per section, and the closing question when the answer ends with one. With HTML mail on, the complete answer is in a scrollable box below it.
  • Background processes: how many are still running, and their ids, when there are any.
  • Suggested commands: a numbered list tailored to the message, to paste into the chat. They are tappable boxes when "Replies reach Claude" is on.
  • Quick-reply cards (HTML mail with reply control on): OFF, ON and SLEEP (a 1-hour pause on all projects), other pauses (15 minutes, 3 hours, 8 hours) and, if "Replies reach Claude" is on, "Write to Claude". Each card opens a pre-filled reply; you still press Send.
  • Reply instructions in plain text, when reply control is on.

What you get

Mail When
Task finished A turn longer than 2 minutes (setting) ended
Needs your input A permission prompt or a question is waiting
Error / usage limit An API error, or the account limit was reached (with the reset time)
Background processes Periodic status while they run; one mail when the last one ends
Chat stalled Optional watchdog: no events for N minutes with tasks declared

HTML mail (optional)

Turn on E-mail with buttons in the web app's Rules tab and every mail also carries an HTML version next to the unchanged plain text: a coloured header by event type, the data in a grid, quick-reply cards, the suggested commands as tappable boxes (when "Replies reach Claude" is on), and the whole message in a box with its own scroll bar (at most 340 px tall). The same layout is used for the confirmation, "command executed" and "reply discarded" mails.

  • The cards are pre-filled replies (mailto:): you still press Send. One-click actions inside Gmail need registration with Google and a public HTTPS endpoint, which a daemon listening on loopback cannot offer.
  • A mail app that does not show HTML shows the plain text, without cards or the scroll box.
  • Nothing extra leaves your machine: the box follows the content mode (title and minimal add nothing), and text goes through the same secret redaction.
  • A verified reply that cannot be delivered (no chat tied to the mail, unknown or expired reference, delivery to Claude switched off) is answered with a mail whose outcome says "reply discarded" and why. At most 5 an hour.

Settings web app

mail-notify open shows: an Overview with health checks and the main on/off switch; Rules (what to report, how often, how much text, reply control); Activity with per-project switches and the latest chats; and Connection with provider presets, the device name and a test button. It listens on 127.0.0.1 only, with a one-time sign-in link, CSRF protection and a strict content security policy.

The page, the mails and the command line follow the language setting: auto (the default), it or en. auto uses the language set in Claude Code's own language setting when it names Italian or English, and otherwise the system language. The page is translated from static catalogs in the package. Nothing is sent to a translation service, and data from the daemon (project names, chat titles, mail subjects) is never translated.

Reply by mail

Off by default (web app → Rules → Control by replying to the e-mail). When on, ccmail reads your mailbox over IMAP and accepts only replies that come from you, are verified by the provider, quote a valid reference from a recent ccmail mail, and start with OFF, ON or PAUSE [minutes] (the Italian words SPEGNI, ACCENDI, PAUSA, and a few others are accepted too). With Replies reach Claude on, any other reply text is delivered to the chat the mail came from. The answer to it is mailed back to you when that turn ends, even if it was short, with the subject "answer to your e-mail" (Italian: "risposta alla tua email").

See SECURITY.md for the exact rules and docs/HOW-IT-WORKS.md for the delivery paths.

The /mail-notify skill

mail-notify install-skill copies a small skill to ~/.claude/skills/mail-notify/. It lets you type /mail-notify on, off, status, test or open in Claude Code, and tells Claude how to behave during long processes (a concise status while they run, a short final summary). The skill is instructed never to read credential files or edit Claude's settings.

Several computers

Every computer has its own daemon, data folder and credentials, and its own copy of the settings. Give each one a name (mail-notify init, or web app → Connection → Name of this device) and it appears as Device: in the mails. A reply is applied by the daemon that sent the mail it refers to; daemons ignore references they did not issue.

Platforms

Windows macOS Linux
Data folder %APPDATA%\ccmail ~/Library/Application Support/ccmail ~/.config/ccmail
Password store Credential Manager (fallback: DPAPI file) Keychain (fallback: 0600 file) Secret Service via secret-tool (fallback: 0600 file)
Start at logon Task Scheduler LaunchAgent systemd --user (fallback: XDG autostart)
Status tested to be tested (later release) to be tested (later release)

The fallback files are announced loudly by init, status, doctor and the web app. On Linux install libsecret-tools to use the Secret Service. Claude Code's folder honours CLAUDE_CONFIG_DIR.

Privacy and security

  • ccmail reads only what it needs: what Claude Code passes to its hooks; the desktop app's chat titles and folders; the latest chat title recorded at the end of a session transcript, when the app's metadata is missing; the account's display name from ~/.claude.json (nothing else in that file is used); and the language key of Claude Code's settings.json. Installing the hooks edits that file, after making a backup.
  • Message text is redacted for common secrets before it is put in a mail. title and minimal content modes send no model-written text at all.
  • The password is never written to logs, the database, the repository or the web app; the API never returns it.
  • The daemon binds to 127.0.0.1, authenticates hooks with a file-based token and checks Host and Origin.

Details and the threat model: SECURITY.md. Report vulnerabilities privately (see that file).

Troubleshooting

Symptom Try
No mail at all mail-notify status: notifications start OFF, so run mail-notify on. Then mail-notify doctor --network and mail-notify test; check spam and the app password
Hooks do nothing mail-notify install-hooks, then restart Claude Code; mail-notify doctor flags a moved Python
No buttons or cards in a mail Cards need HTML mail and reply control on; plain-text mail apps show no buttons
Chat names missing mail-notify diagnose shows where the desktop app's metadata is looked for
Port busy The daemon picks a free port by itself; hooks and CLI read it from daemon.json
Reply by mail is slow Most of the delay is the provider delivering mail to yourself (seconds to about 25 s)
Linux: password in a file Install libsecret-tools and run mail-notify init again

Commands

init · setup [--autostart] · on · off · status [--cwd DIR] · test · open · stop · doctor [--network] · install-hooks [--autostart] · uninstall-hooks [--autostart] · install-skill · uninstall-skill · diagnose · trace on|off|show · migrate · daemon [--foreground] · install-cli · uninstall-cli.

The command is installed as both mail-notify and ccmail. install-hooks and install-skill also create the short mail-notify command. If neither name is found, run python -m ccmail install-cli once (see Step 1).

Resource use

No model calls at all in normal operation. The daemon uses about 35 MB and about 0.05–0.25 % of one core, and each hook call adds about 0.12 s. Tokens are spent only on the skill text, on periodic wake-ups while background tasks run and on delivered replies. The HTML mail costs no tokens (about 0.1–0.6 ms of CPU and 6–9 KB more per mail). Measurements, formulas and limits: docs/RESOURCES.md.

How it works

Hooks run a tiny client (python -m ccmail hook) that forwards the event to the local daemon and always exits 0. The daemon applies the rules, writes to SQLite, and an outbox worker sends mail with retries. More in docs/HOW-IT-WORKS.md.

Development

git clone https://github.com/lobascioemanuele-droid/mail-notify && cd mail-notify
python -m venv .venv
. .venv/bin/activate

On Windows, activate with .venv\Scripts\activate instead.

pip install -e .
python -W ignore -m unittest discover -s tests

Set PYTHONPATH=src:tests first if the package is not installed.

See CONTRIBUTING.md. Changes are listed in CHANGELOG.md; what 1.x promises to keep stable is in docs/STABILITY.md.

License

MIT.

Metadata

Release files for mail-notify 1.0.3

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

Source distribution (sdist)

Source distribution for mail-notify 1.0.3
File Size Uploaded Provenance
mail_notify-1.0.3.tar.gz 242.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for mail-notify 1.0.3
File Interpreter ABI Platform
mail_notify-1.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 425.0 kB

Release files / mail_notify-1.0.3.tar.gz

Download URL mail_notify-1.0.3.tar.gz
Size 242.7 kB
Tags Source
SHA-256 checksum
How to use checksums
268869198e3f1bd2e77d69c366d3e0e29222644c68245b680cdcdae86ef34cb2
BLAKE2b-256 checksum
How to use checksums
8c4193128c8070fce4e67b8b3f9811958cf3595eb93c931aacabcde3488634ae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release files / mail_notify-1.0.3-py3-none-any.whl

Download URL mail_notify-1.0.3-py3-none-any.whl
Size 182.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7c56fc29876230c9a3d33a8adabce70699f01a81f2dd54a72094ee6672a09bc3
BLAKE2b-256 checksum
How to use checksums
88f4e737bb6175876353a6acf9a06b6c44f7c2aedb93afafc2327adf01701f49
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Security for mail-notify 1.0.3

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for mail_notify-1.0.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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