A cross-browser extension that helps you clean up your Gmail and Outlook inbox by surfacing the senders of newsletters and promotional emails, then letting you unsubscribe or trash them with a swipe.
Built with React 19, TypeScript, Vite, Tailwind v4, and Manifest V3. Runs on Chrome, Edge, Brave, Vivaldi, Firefox, and Zen.
Everything runs locally on your device. No backend, no analytics, no tracking.
|
|
| Sign-in screen | Swiping through senders |
|
|
| Privacy announcement | Results summary |
Important
SortItOut is currently going through Google's OAuth verification process. The first time you sign in with Google you may see a "this app is not verified by Google" warning. Click Advanced → Go to SortItOut (unsafe) to proceed. This is expected while verification is pending and will go away once the process completes.
| Feature | What it does |
|---|---|
| Two-provider support | Sign in with Gmail or Outlook (or both, with separate auth state per provider). |
| One-click unsubscribe | Detects senders that support the standard List-Unsubscribe and List-Unsubscribe-Post headers (RFC 2369 / RFC 8058) and unsubscribes you with a single HTTPS POST. No redirect needed. |
| Swipe-to-trash | Swipe a sender card to move every email from that sender into Trash in one action. |
| Three swipe modes | Unsubscribe-only, trash-only, or both at the same time. |
| Card and list views | Choose a Tinder-style card stack or a checklist for batch actions. |
| Open-rate hint | Each sender card shows a rough open rate (read vs. unread) so you know which senders you actually engage with. |
| Dismissed list | Senders you've reviewed don't reappear next time you scan, with optional cooldowns. |
| Local-only | All scan results, dismissed senders, and Outlook tokens live in chrome.storage.local and are deleted when the extension is uninstalled. |
- Framework: React 19 + TypeScript
- Build: Vite 7
- Styling: Tailwind CSS v4
- Animations:
motion(formerly Framer Motion) - Extension platform: Manifest V3, cross-browser (Chromium service worker + Gecko background script fallback)
- APIs: Gmail API (
gmail.modify), Microsoft Graph (Mail.ReadWrite) - Auth:
- Gmail on Chromium:
chrome.identity.getAuthToken(Chrome Extension OAuth client) - Gmail on Firefox/Zen:
chrome.identity.launchWebAuthFlow+ PKCE (Web Application OAuth client) - Outlook on both:
chrome.identity.launchWebAuthFlow+ PKCE (Entra public client)
- Gmail on Chromium:
- Node.js 20+ and npm
- A Chromium-based browser (Chrome, Edge, Brave, Vivaldi) and/or a Gecko-based browser (Firefox 121+, Zen)
git clone https://github.com/NinyaDev/SortItOut-Extension.git
cd SortItOut-Extension
npm installnpm run buildThis outputs the production bundle to dist/.
- Go to
chrome://extensions(or the equivalent in your browser) - Toggle Developer mode on (top right)
- Click Load unpacked and select the
dist/folder - The SortItOut icon will appear in your toolbar
The key field in public/manifest.json makes the unpacked build compute the same extension ID as the production CWS install, so the bundled OAuth client works out of the box. (Chrome Web Store strips the key field on submission and re-signs with its own key, so this is safe for both local dev and store distribution.)
- Go to
about:debugging - Click This Firefox (Zen shows it as "This Zen", same thing)
- Click Load Temporary Add-on and pick
dist/manifest.json - The SortItOut icon will appear in your toolbar
Note: temporary add-ons are removed when you close the browser. For a persistent install, use the recent published AMO listing or sign the extension with your own AMO developer account.
The published manifest.json and source code ship with the OAuth client IDs used by the live store builds. If you want to develop against your own Google or Microsoft tenants:
- Gmail (Chromium): create an OAuth Client of type Chrome Extension in the Google Cloud Console, set its Application ID to your unpacked extension ID, and replace
client_idinpublic/manifest.json(oauth2.client_id). - Gmail (Firefox/Zen): create a separate OAuth Client of type Web Application, add
chrome.identity.getRedirectURL()(anhttps://<hash>.extensions.allizom.org/URL — get it from the extension's background console) as an Authorized Redirect URI, and replaceCLIENT_IDinsrc/logic/gmail-auth.ts. Google's Web Application client type requires a client secret even with PKCE; put it in a gitignored.env.localfile asVITE_FIREFOX_GOOGLE_CLIENT_SECRET=...and Vite will inject it at build time. - Outlook (both): register a public client in the Azure Portal, add both
https://<chrome-extension-id>.chromiumapp.org/(for Chromium) and the Firefoxextensions.allizom.orgURI as redirect URIs, and replaceCLIENT_IDinsrc/logic/outlook-auth.ts.
.
├── public/
│ └── manifest.json # MV3 manifest (permissions, OAuth, icons, gecko id)
├── src/
│ ├── App.tsx # Popup root, branches on browser for Gmail auth
│ ├── background/ # Service worker: unsubscribe POST + Outlook/Gmail PKCE
│ ├── logic/ # Gmail / Outlook API calls, auth modules, scanners,
│ │ # parser, dismissed list
│ └── ui/ # Swipeable card, list view, info / dismissed panels
├── popup.html
├── vite.config.ts
└── .env.local # gitignored. Holds VITE_FIREFOX_GOOGLE_CLIENT_SECRET
# for the Firefox Gmail OAuth flow.
SortItOut reads only email headers (sender, List-Unsubscribe) and basic metadata. Bodies, attachments, and contacts are never accessed. All data stays on your device. Read the full Privacy Policy.
Google OAuth verification for the gmail.modify scope is in progress:
- ✅ Branding verified
- ⏳ Data Access (restricted scope) verification, in beta under Google's 100-user cap
Released under the MIT License.
Adrian Ninanya
- GitHub: NinyaDev
- LinkedIn: Adrian Ninanya
- Project Link: https://github.com/NinyaDev/SortItOut-Extension



