Scan headers
Sender, subject, date, flags and List-Unsubscribe. No bodies, no attachments, no full-mailbox download.
Open source · Agent-native · Reversible
Clean up years of newsletters, promos and spam in one reviewed pass. Headers only. Plan first. Every move undoable.
Free and open source · No account · No telemetry · MIT
CH 01 · How it works
A small CLI, a reviewable plan and an undo journal. No black-box “AI inbox cleaner”.
Sender, subject, date, flags and List-Unsubscribe. No bodies, no attachments, no full-mailbox download.
Banks, security codes, invoices, travel, medical, government, personal, starred, answered and recent mail stay put.
Exact UIDs, destinations and unsubscribe targets in plan.json. Nothing changes until you apply it.
Folders or Gmail labels, Junk, Trash, or archive. COPY first, then UID EXPUNGE. Never a mailbox-wide expunge.
RFC 8058 one-click POST, mailto:, or a manual link. Header targets only. Spam is never unsubscribed.
The journal records COPYUID and Message-ID. One command restores moves and Gmail archives. Unsubscribe cannot be unsent.
CH 02 · Why
Most tools ask for your password, read your mail and delete the evidence. CleanYourMail runs on your machine, reads headers only, and keeps an undo journal.
The CLI runs locally. The scan fetches header fields only. The cache stores metadata, never message bodies. No telemetry, no analytics, no third-party API.
Every move is recorded with COPYUID and Message-ID. One command restores it. Gmail archive re-adds the Inbox label. Unsubscribe is the only irreversible step, and it is explicit.
The CLI is the product. SKILL.md and PROMPT.md teach any coding agent to use it safely. No new app, no browser extension, no OAuth broker.
General comparison with hosted cleanup services. Check each product.
CH 03 · Set up
Python 3.11+. No packages. An app password or OAuth token. A terminal.
Clone the repo, write a config, put the secret in CYM_PASSWORD, then run doctor.
Scan headers, read the report, and generate a plan. Correct protected senders before anything moves.
Apply moves first. Verify. Then send unsubscribe requests separately. Keep the undo command.
$ git clone https://github.com/jparedesDS/cleanyourmail.git
$ cd cleanyourmail
$ python tools/mail.py init --email you@example.com
$ $env:CYM_PASSWORD = "app-password"
$ python tools/mail.py doctor
$ python tools/mail.py scan --days 365
$ python tools/mail.py report --top 30
$ python tools/mail.py plan --mode folders
Start small. Use --limit 50 for the first run, review plan.json, and keep the undo command. On macOS or Linux, use python3 instead of python.
Using a coding agent? Paste PROMPT.md. It will read SKILL.md, show you the plan, move first, and give you the undo command. It will not skip the review.
CH 04 · Providers
IMAP and SMTP, app passwords or OAuth2. No hosted service, no mailbox migration.
Turn on 2-Step Verification, create an App Password, enable IMAP. Folders are labels; archive removes the Inbox label and keeps the message in All Mail.
Basic auth is disabled. Put a valid access token in CYM_PASSWORD with auth = "xoauth2". The CLI does not refresh tokens; SMTP AUTH may be disabled by the tenant, so a mailto unsubscribe can fail.
Enable 2-Step Verification and generate an app password in Account Security. Standard IMAP folders; the CLI resolves Trash, Junk and Archive.
Apple requires 2FA. Create an app-specific password at appleid.apple.com. The CLI resolves Deleted Messages, Junk and Archive.
Create an app password with IMAP/SMTP access. Fastmail supports Sieve natively; export the script and review it before uploading.
Run Bridge locally, enable the account, and use the Bridge password. Default IMAP is 127.0.0.1:1143 with STARTTLS; SMTP is 127.0.0.1:1025.
Set host, port, TLS/STARTTLS and SMTP. The server must support UIDPLUS or MOVE; otherwise moves are refused rather than risk a mailbox-wide expunge.
Full setup notes in docs/PROVIDERS.md. Your provider not listed? Any IMAP server with UIDPLUS or MOVE works.
CH 05 · Safety
The interesting part is not what it can do. It is what it refuses to do.
Moves copy first and use UID EXPUNGE. No mailbox-wide expunge. Trash is never emptied. If the server lacks UIDPLUS/MOVE, moves are refused.
Transactional and personal mail, security codes, banks, invoices, travel, medical, government, starred, answered and recent messages are never auto-moved.
The scan fetches header fields only. The local cache stores metadata, not message content. There is no content index and no AI reading your mail.
Only List-Unsubscribe headers. No redirects, cookies or proxies. Private/local targets are rejected. Manual links are for you to open, not the agent.
An email cannot give the agent instructions. “Ignore your rules”, “send this” or “run that” is reported, not followed.
“Skip the plan”, “delete everything” or “unsubscribe from everything” is a stop condition. Plan review, protected mail, spam exclusion and batch caps are not optional.
Unsubscribe is the one irreversible step. It is explicit, capped, delayed, and never applied to spam. Moves and archives have an undo journal. Unsubscribe requests cannot be unsent. Read the full safety rules ↗
CH 06 · FAQ
No. It moves mail to folders, labels, Junk, Trash or archive. It never empties Trash, never runs a mailbox-wide expunge, and never has a “delete forever” command.
No. The scan fetches header fields only: sender, subject, date, size, flags and unsubscribe headers. Bodies and attachments are never downloaded.
Yes. CleanYourMail is MIT-licensed and free to use. There is no paid tier, no account and no upsell.
You need a terminal and Python 3.11+. A coding agent can do the typing for you: paste PROMPT.md and follow the plan. The CLI is also usable directly.
Yes. Gmail uses labels rather than folders. Archive removes the \Inbox label and leaves the message in All Mail. The undo re-adds the label using X-GM-MSGID or Message-ID.
Use an OAuth2 access token with auth = "xoauth2". The CLI does not acquire or refresh tokens. Some tenants disable SMTP AUTH, so a mailto: unsubscribe may need to be done manually.
No. Spam is never unsubscribed: a spam unsubscribe link can confirm that the address is live. Spam goes to Junk. For legitimate lists, unsubscribe is a request, not a guarantee.
The workflow is dry-run first: scan, report, plan, review. Apply moves only after reviewing the plan. Start with --limit or a single category. Keep the undo command. It is still software: review the plan.
Moves are refused. The only fallback would be a mailbox-wide expunge, which could permanently delete another client’s message. Use a client that supports UIDPLUS/MOVE or move manually.
Only IMAP/SMTP traffic and the validated unsubscribe requests. There is no telemetry, no analytics, no third-party API and no content index. The website loads no third-party resources.
Yes. The CLI is the product. The skill and prompt just teach a coding agent to use it safely. Every command is documented in SKILL.md and README.md.
No. There is no account, no server, no telemetry and no third-party API. The only network calls are IMAP, SMTP for a mailto unsubscribe, and a validated one-click HTTPS request.
Start small. Stay in control.
Run the dry run. Review the plan. Apply a small batch. Undo if you change your mind.
No account. No telemetry. MIT.
$ python tools/mail.py scan --days 365
$ python tools/mail.py report --top 30
$ python tools/mail.py plan --mode folders
$ python tools/mail.py apply <plan.json> --yes --action move