A native macOS app for finding and bulk-unsubscribing from newsletters.
Nevermore syncs the headers of every message carrying a List-Unsubscribe
header into a local database, groups them by sender, and lets you unsubscribe
from or trash whole senders in a few keystrokes. It never downloads message
bodies, and it never sends your data anywhere except directly to the
unsubscribe endpoint the sender published.
The name is the point: senders that keep mailing after you unsubscribe get flagged and shut down for good.
nevermore website · download 1.0.0 · FAQ · privacy
Status: 1.0.0 released for direct download; Mac App Store submission in review. Built and used daily against a real ~132,000-message mailbox. Docs last reviewed: 9 August 2026.
All screenshots and recordings use Nevermore's built-in demo mailbox — the senders are invented, which is why the app is showing its demo banner.
Watch the 30-second walkthrough — sync, unsubscribe, keep what you want, and catch the senders who carry on.
Pick a sender, press u. Nevermore sends the request the sender published, then
tells you what it actually did — "requested", not "unsubscribed", because an
endpoint returning success proves nothing.
i ignores a sender for good; ⌘⌫ moves everything they've sent to your
provider's Trash, where you can still get it back.
This is the part a web service can't do. Senders who keep mailing after you unsubscribed show up here with a count of what's arrived since — including the ones that "confirmed" your request.
Most unsubscribe tools are web services that ask for OAuth access to your mailbox and then read it on their servers. Unroll.me famously sold the results. Nevermore is the opposite shape:
- Local-first. Everything runs on your Mac. There is no server, no account to create, and no telemetry. Your header cache is a SQLite file in Application Support; your password lives in the macOS Keychain.
- Headers only. It reads
From,Subject,Date,List-Unsubscribe, and a few others. It never fetches a message body. - Honest about outcomes. Unsubscribing is not verifiable in the general case. Nevermore distinguishes requested from confirmed rather than claiming success it can't prove — and it tells you when a sender ignores you.
- No OAuth. It signs in over plain IMAP with an app-specific password, so there's no Google Cloud project to create and no consent screen to click through.
- Any IMAP provider. Gmail, iCloud, Yahoo, Fastmail, and AOL are detected from your address; custom domains pick their provider. Folders are discovered at connect via the IMAP SPECIAL-USE extension rather than hard-coded.
- Fast sync. Header-only fetch runs at roughly 1,000 messages/second.
- Smart grouping. Senders are grouped by registrable domain (eTLD+1), with shared platforms split per newsletter so every Substack doesn't collapse into one row. You can override with Split by Address / Keep as One Group.
- Full RFC 2369 / 8058 chain. One-click
POSTwhere offered, thenGET, thenmailto:, then a built-in browser for senders that publish nothing usable. - Reappearance detection. If a sender mails you again after a recorded unsubscribe, it surfaces in a dedicated collection with a notification.
- Keyboard triage.
j/kto move,uunsubscribe,⇧Uunsubscribe and delete without a confirmation,vopen the newest message in your browser,iignore,dtrash,?for the full list. Every action advances to the next sender, so a mailbox can be cleared without touching the mouse. - Trash with undo. Messages move to your provider's Trash and
⌘Zputs them back. - Alias-aware. Send-as addresses are inferred from your Sent folder, so
mailto:unsubscribes go out from the address the mail was delivered to. - Multi-account, with per-account databases.
- Demo mode. A built-in sample mailbox you can explore before handing over a password, and switch back to any time from Settings. It runs on a backend with no network code in it, so nothing in demo mode can reach a server.
The first sync reads your whole mail history, so it explains itself while you wait — and says which of the two steps it's on rather than leaving you guessing.
Nevermore tells you what pressing the button will actually do — which senders get a one-click request, which open a page, which get an email — before it does it.
Available any time from Help ▸ How Nevermore Works, including an honest list of what the app won't find.
Download the latest DMG from Releases, open it, and drag Nevermore to Applications. Signed and notarized by Apple.
- macOS 14 or later, Apple Silicon or Intel (universal binary)
- Xcode 26 (or matching Swift 6 toolchain) to build
- An app-specific password for your mail account
cd Packages/NevermoreKit
swift build # build everything
swift run nevermore-tests # run the test suite (117 tests)
./make-app.sh release # produce a signed Nevermore.app
./make-dmg.sh --notarize # produce a notarized, stapled DMGmake-app.sh wraps the SwiftPM executable into a proper .app bundle. It
signs with the first Developer ID Application certificate it finds; set
NEVERMORE_SIGN_IDENTITY to choose one explicitly. Signing with a stable
identity matters — an ad-hoc signature changes every build, which invalidates
the Keychain ACL on the saved password.
To build with the App Sandbox enabled (as the Mac App Store requires):
NEVERMORE_SANDBOX=1 ./make-app.sh releaseNote the sandbox relocates Application Support into the app container, so a sandboxed build starts with no accounts. It also still embeds Sparkle — the SwiftPM target links it unconditionally, so the framework has to be there for the app to launch at all. Only the Tuist store target genuinely omits the updater. See MAS-RELEASE.md.
Not ready to hand over a password? The first screen offers Try the Demo — a sample mailbox with no account required. Settings ▸ Advanced switches back and forth later.
- Turn on two-factor authentication for your mail account.
- Create an app-specific password (Nevermore links you to the right page for your provider).
- Enter your address and that password. It goes straight to the Keychain.
macOS will ask permission the first time Nevermore reads its own Keychain item. Choose Always Allow so it stops asking.
Packages/NevermoreKit/
├── Sources/
│ ├── NevermoreKit/ # no SwiftUI — domain logic, testable headless
│ │ ├── Domain/ # value types + pure logic, zero I/O
│ │ ├── Backend/ # MailBackend protocol, IMAP implementation
│ │ ├── Unsubscribe/ # RFC 2369/8058 engine, SSRF destination guard
│ │ ├── Store/ # GRDB/SQLite header cache
│ │ ├── Demo/ # fabricated mailbox + a backend with no network
│ │ └── Credentials/ # Keychain, account registry
│ ├── NevermoreApp/ # SwiftUI app: views, sheets, AppModel
│ └── Probe/ # CLI harness for live-mailbox testing
└── Tests/NevermoreTests/
NevermoreKit must not import SwiftUI — the domain logic stays testable
without launching a UI.
Release process and versioning: RELEASE.md. Mac App Store specifics: MAS-RELEASE.md.
Design documents: PLAN.md for architecture decisions and UI_SPEC.md for the interface brief. Both are design-time snapshots and have drifted from the code in places; this README and the source are authoritative.
The app acts on data written by strangers — a List-Unsubscribe header is
attacker-authored input that drives outbound network requests and email. It's
built accordingly:
- SSRF guard. Unsubscribe URLs are resolved and rejected unless they point
at a public, global-unicast address, so a sender can't aim a request at
localhost, your LAN, or a cloud metadata endpoint. Redirects are re-validated at every hop. - Header-injection defense.
mailto:values are percent-decoded, so control characters are stripped and the subject is RFC 2047-encoded unconditionally; recipients must be a single well-formed address. - STARTTLS required when sending, so a stripped capability can't downgrade the session and leak your password in cleartext.
- Device-bound credential. The app password is stored
WhenUnlockedThisDeviceOnly, so it can't ride a backup to another machine. - Every sender-supplied URL is guarded — the silent request, the redirect chain, the in-app browser, and the "Manage" link in your unsubscribe history.
Nevermore never permanently deletes anything. "Trash" moves messages to your
provider's Trash folder, where they sit under that provider's own retention
(30 days on Gmail) and can be restored by you at any time. The app never issues
an IMAP EXPUNGE. Small batches also offer an in-app undo with ⌘Z.
The local database is a cache of headers. Deleting it loses your unsubscribe history and ignore list, not mail.
Found something? Open an issue — or email if it's sensitive.
Personal use, source-available. You may read, audit, build, and run Nevermore for your own personal use, and modify it privately. You may not redistribute it, publish a fork, or use it commercially. See LICENSE.
The source is published because an app that reads your mail and holds a credential to it should be inspectable. That's a different thing from open source, and this licence says so plainly.
No servers, no accounts, no telemetry. See PRIVACY.md.






