From 2eb373726a0abe07741138616a9e2bc70a2f753b Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sun, 13 Sep 2026 18:06:28 +0200 Subject: docs(mail-overview): document the arrival notifier Why a revision counter rather than a count delta or a date watermark, why the state file carries a UUID, and why an unseeded run stays quiet. Also records the final notification presentation: the split heading, the absolute-path icon, and the show_indicators setting that keeps the action indicator off. --- mail-overview/README.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'mail-overview') diff --git a/mail-overview/README.md b/mail-overview/README.md index 68ad051..6e34140 100644 --- a/mail-overview/README.md +++ b/mail-overview/README.md @@ -120,6 +120,62 @@ Gmail API with stored credentials, covered three of the five accounts, and opened Thunderbird. Everything it fetched over the network was already in the local index. +## Notifications on arrival + +`mail-notify.sh` sends one notification per account when mail lands, with the +newest three senders and subjects and a `+N more` line when the batch is +bigger. Each message is a bullet on its own line with a blank line between, +under a bold `New Mail` heading with the account and count as the second line. +Started from `autostart.lua`, it runs for the whole session. + + /home/you/Programming/GIT/quickshell/mail-overview/mail-notify.sh + +It watches the same xapian directory the waybar module does, for the same +reason and with the same 0.3s debounce. It is a **separate process rather +than part of `waybar-mail.sh`**, which already has that edge: waybar owns +that script's process, so a bar restart would stop notifications with nothing +reporting it. + +**A commit is not the same as new mail.** Reading a message in qtmaildir drops +its `unread` tag and commits; so does tagging. Arrival is found with notmuch's +revision counter instead: + + notmuch count --lastmod 'tag:unread and tag:inbox' + +which prints count, database UUID and revision, tab separated. Each account is +then asked what it gained in `lastmod:..`. A count delta was +rejected because it cannot name senders, and a `date:` watermark because +`date:` is the message's own Date header: backdated mail would never notify +and future-dated mail would notify forever. + +Position is kept in `~/.local/state/mail-notify.lastmod`, written by atomic +replace, holding the **UUID as well as the revision**. Revisions only compare +within one database, so a rebuild restarts the counter and a stored revision +from the old one means nothing. + +**Missing, corrupt or mismatched state seeds silently**, recording the current +revision and notifying nothing. Without that floor, `lastmod:0..` matches every +unread message ever: 101 of them here, which is a wall of popups at every +login. The same applies to a restart, so mail that arrived while it was down is +never notified. The waybar count is still right and the drawer still shows it, +so nothing is lost but a stale popup. + +The notification is sent with dunstify. The icon is passed as an **absolute +path** to the active icon theme's `mail-unread-multiple`, because this dunst +resolves an icon *name* only through the `icon_path` in `dunstrc`, and that +path holds no mail icon, so a name renders no icon at all. The click action +(`-A default,open`) makes dunst prepend an `(A)` action indicator when +`show_indicators` is on, so `dunstrc` sets `show_indicators = no`. A middle +click (dunst's `do_action`) opens qtmaildir, but not the account it belongs +to: `qtmaildir` takes no arguments and `startup_account` is a static setting +rather than a flag, the same limitation the thread rows have. + +`test-mail-notify.sh` is the check. It sources the script as a library and +asserts on the functions that only move text around, so it needs no mail and no +notmuch: + + ./test-mail-notify.sh + ## Geometry, and the one property that differs from the other panels The window is a fullscreen overlay with a dimmed backdrop and the drawer itself -- cgit v1.2.3