v0.6.0 — installable: pipx install gmail-inbox-cleanup
The "installable" release. First release on PyPI, as gmail-inbox-cleanup
(pipx install gmail-inbox-cleanup); the command is still gmail-cleanup. The
gmail-cleanup name on PyPI belongs to an unrelated project.
⚠️ Upgrading from 0.5.x
- Your lists moved. Lists now ship inside the package as seeds
(gmail_cleanup/lists/), merged with your own copies in~/.gmail_cli/lists/.
Onlykeep.yamlships populated;humans,killandunsubbedship empty.
If you edited the repo'slists/*.yaml, copyhumans.yaml,kill.yamland
unsubbed.yamlinto~/.gmail_cli/lists/before upgrading. - Successful unsubscribes are now appended to
~/.gmail_cli/lists/unsubbed.yaml
(previously the repo/package copy).
Fixed
verifyno longer flags senders for mail sent before you unsubscribed.
It counted every message in the last 14 days, including mail that arrived
before the unsubscribe, soautopilot --escalaterun daily would block-filter
senders unsubscribed the day before. Entries with anunsubscribed_at
timestamp now count only mail after that time plus a grace period
(--grace-days, default 2 — Google's bulk-sender deadline). Senders still
inside the grace period are reported as PENDING and are never escalated.- List and state writers: a sender could be silently dropped after an
unterminated header comment; concurrent runs (scheduled + manual) lost records
and crashed on rename; a failed write could strand the newer data; event
deltas could overwrite a record's timestamp; malformed state files raised. - Wheel no longer installs a top-level
lists/directory into site-packages,
and the sdist no longer sweeps in stray checkouts. humans.yamlsenders are never unsubscribed or archived. The docs promised
this, butunsubscribenever checked the list. Humans now win over the kill
list too.- Removed the
has:listcatch-all filter.has:listis not a Gmail search
operator — the filter matched nothing. Delete it from your Gmail filters if a
previous version created it. filters applyreplaces a grown list's filter instead of stacking another.
Each run that added unsubscribed senders used to leave the older filter behind.
Older filters are removed only when the new one covers every sender in them.filters applyskips filters whose list is empty (Gmail rejects an emptyfrom:).statusmatches Gmail's UI: inbox conversations and inbox-only unread, from
one API call. It used to page through up to 10,000 message IDs twice and count
messages and all-mail unread.- Rate-limited or failed API calls are retried and reported instead of silently
returning nothing.
Added
autopilot --days Nand--min-count Kto tune the unsubscribe phase
(defaults unchanged: 30 days, 2 messages).autopilot --email-summaryemails the run's report to the account itself —
e.g. a scheduled--dry-runpreview.verify --grace-days N.- Much faster scans that respect Gmail's quota.
unsubscribefetches headers
in HTTP batches (25 per request) paced to the documented per-user limit
(100 quota units/s), and no longer fetches each sender a second time. - Rate-limit handling: honors
Retry-After, backs off 5→80 s with jitter,
re-sends throttled items in smaller batches, and remembers a throttle in
~/.gmail_cli/soautopilotskips its run until it expires. - Progress lines for non-terminal runs (logs, launchd).
- Autopilot webhook notification (
notify.webhook_urlin config). unsubbed.yamlmapping format{sender, unsubscribed_at}; bare-string
entries are still read.- User override lists in
~/.gmail_cli/lists/merged with the packaged seeds. - Tests for the scheduler, setup wizard, progress UI, list layout, verify
windows and autopilot (200+ tests). Tests run with a sandboxedHOME. - CI gates on
ruff checkbefore pytest; PyPI trusted-publishing workflow.