Privacy-first, self-hosted Gmail cleanup. Runs locally on your machine — no cloud backend, no analytics.
Scan Spam, Trash, and Inbox, group messages by sender, and bulk delete, block, keep (whitelist), or mass unsubscribe.
Repository: github.com/Kava4/mail-cleaner
| Tool | Version |
|---|---|
| Node.js | 20+ (LTS recommended) |
| npm | 10+ |
| Google account | Gmail |
| Google Cloud project | OAuth + Gmail API enabled |
Double-click run.bat in the project root:
- Checks Node.js
- Runs
npm installif needed - Warns if
data/credentials.jsonis missing - Opens the browser and starts
npm run dev
git clone https://github.com/Kava4/mail-cleaner.git
cd mail-cleaner
npm install
npm run devOpen http://localhost:3000 and click Connect Gmail.
- Open Google Cloud Console
- Select a project → New Project (e.g.
mail-cleaner)
- APIs & Services → Library
- Search Gmail API → Enable
- APIs & Services → OAuth consent screen
- User type: External (personal Gmail) or Internal (Google Workspace)
- Fill in app name and support email
- Scopes: the app requests these automatically on sign-in:
https://mail.google.com/(read, modify, permanent delete)https://www.googleapis.com/auth/gmail.settings.basic(block filters)
- Test users: add your Gmail address (required while the app is in Testing)
- APIs & Services → Credentials → Create Credentials → OAuth client ID
- Application type: Web application
- Authorized redirect URIs:
http://localhost:3000/api/auth/callback - Download JSON and save as:
mail-cleaner/data/credentials.json
Never commit
credentials.jsonto GitHub. It is listed in.gitignore.
- Run the app and click Connect Gmail
- Grant permissions (full Gmail access is required for permanent delete from Trash/Spam)
- Click Scan mailboxes
mail-cleaner/
├── apps/web/ Next.js UI + API routes
├── packages/shared/ Shared types & spam rules
├── data/ ← not committed to Git
│ ├── credentials.json OAuth client (you provide this)
│ ├── token.json Access/refresh token (created on sign-in)
│ └── whitelist.json Senders you marked as Keep
└── README.md
| Action | What it does |
|---|---|
| Scan mailboxes | Scans Spam, Trash, Inbox (up to 2000 emails per folder) |
| Block | Deletes emails + creates a Gmail filter (future mail → Trash) |
| Delete | Inbox → Trash · Spam/Trash → permanent delete |
| Keep | Whitelist — hidden when "Hide kept" is enabled |
| Unsub / Mass Unsub | List-Unsubscribe headers (newsletters) — selected or all visible |
| Empty Spam / Trash | Permanently deletes everything in that folder |
Tips
- Filter by
Type → Newsletter, then Unsub all visible, then Delete selected - If delete fails: Sign out → delete
data/token.json→ Connect again
npm run build
npm run startDefault port: 3000. For another port: PORT=3001 npm run start
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_GITHUB_URL |
https://github.com/Kava4/mail-cleaner |
GitHub link shown in the UI |
Copy .env.example to apps/web/.env.local and adjust if needed.
Self-hosted: each user runs their own instance. You share code only, never credentials or tokens.
| Method | Notes |
|---|---|
| GitHub repo | Recommended. Push code without data/. Users clone and add their own OAuth client. |
| GitHub Release (zip) | Attach source zip; users unzip, npm install, add credentials, run. |
| VPS | git clone, npm run build, PM2/systemd, nginx + HTTPS. Add production redirect URI in Google Cloud. |
Not supported out of the box: Vercel/Netlify serverless (tokens stored on local filesystem in data/).
- 100% local — tokens in
data/token.json - No third-party analytics
- Revoke access anytime: Google Account → Third-party apps
| Issue | Fix |
|---|---|
OAuth access_denied |
Add your email as a Test user on the consent screen |
| Delete / Empty Trash fails | Sign out → delete data/token.json → Connect again |
credentials.json not found |
Save OAuth JSON to data/credentials.json |
| Port 3000 in use | Stop the old dev server or use PORT=3001 npm run dev |
MIT