Local Gmail inbox management app for previewing, labeling, archiving, marking read, and moving messages to Gmail Trash.
The app runs on your computer and uses the Gmail API through your own Google OAuth desktop client. It includes:
- FastAPI backend for Gmail API operations.
- React + Vite dashboard for rule management and execution.
- CLI fallback for scripted analysis and cleanup.
- Local rule storage in
rules.yml. - Local operation history in
cleanup_history.jsonl.
Desktop dashboard:
Mobile layout:
Install these before setup:
- Windows, macOS, or Linux with a modern browser.
- Python
3.11or newer. uvfor Python dependency management.- Node.js
20or newer and npm. - A Google Cloud project with Gmail API enabled.
- A Google OAuth desktop client saved locally as
credentials.json.
Python dependencies are declared in pyproject.toml:
fastapigoogle-api-python-clientgoogle-auth-httplib2google-auth-oauthlibPyYAMLtruststoreuvicorn[standard]
Frontend dependencies are declared in web/package.json:
@vitejs/plugin-reactlucide-reactreactreact-domtypescriptvite
The app is designed to preview before changing mail.
- Rule execution requires selecting rules, previewing matches, and confirming.
- Label cleanup moves messages to Gmail Trash, not permanent deletion.
archiveremovesINBOXbut keeps messages in All Mail.labeluses an existing Gmail label when it exists, otherwise creates it.- Label matching is case-insensitive, so
BILLandBIllresolve to the same existing Gmail label. credentials.json,token.json,rules.yml, and history files are ignored by git.
flowchart LR
User["You in browser UI"] --> Vite["React/Vite UI<br/>127.0.0.1:5173"]
Vite --> API["FastAPI backend<br/>127.0.0.1:8000"]
API --> Rules["rules.yml<br/>local rules"]
API --> History["cleanup_history.jsonl<br/>local history"]
API --> OAuth["token.json<br/>local OAuth token"]
API --> Gmail["Gmail API"]
Gmail --> Mailbox["Your Gmail mailbox"]
You only need to do this once.
- Open Google Cloud Console.
- Create a new project, for example
Gmail Automation, or select an existing private project.
- In Google Cloud Console, open APIs & Services > Library.
- Search for Gmail API.
- Open Gmail API.
- Click Enable.
-
Open Google Auth Platform or APIs & Services > OAuth consent screen.
-
Choose External for a personal Gmail account.
-
Fill in the app name, for example
Gmail Local Cleanup. -
Add your email as the support/contact email.
-
Add these scopes:
https://www.googleapis.com/auth/gmail.modify https://www.googleapis.com/auth/gmail.labels -
Keep the app in Testing mode.
If you skip this, Google shows:
Access blocked: app has not completed the Google verification process
Error 403: access_denied
To fix it:
-
Open Google Auth Platform > Audience.
-
Find Test users.
-
Click Add users.
-
Add the Gmail account you will clean, for example:
user@example.com -
Save.
-
Open Google Auth Platform > Clients.
-
Click Create Client.
-
Choose Application type: Desktop app.
-
Name it
Gmail Cleanup Local. -
Click Create.
-
Download the JSON file.
-
Rename it to:
credentials.json -
Place it in this folder:
C:\path\to\Gmail_Automation\credentials.json
From the project root:
cd C:\path\to\Gmail_Automation
uv sync --system-certsInstall frontend dependencies:
cd C:\path\to\Gmail_Automation\web
npm installIf npm fails with a certificate error such as
UNABLE_TO_VERIFY_LEAF_SIGNATURE, either configure your system/company CA, or
temporarily use:
npm config set strict-ssl false
npm installOpen two terminals.
Terminal 1, backend:
cd C:\path\to\Gmail_Automation
uv run --system-certs uvicorn app_api:app --reload --host 127.0.0.1 --port 8000Terminal 2, frontend:
cd C:\path\to\Gmail_Automation\web
npm run devOpen:
http://127.0.0.1:5173
On first Gmail access, a Google sign-in window opens. Approve the app. The app
then creates token.json locally for future runs.
Use this page to execute rules safely.
- Select one or more rules.
- Set a small Limit, for example
25or50. - Click Preview selected.
- Inspect sender, subject, and date samples.
- Click Apply confirmed.
- Type
APPLYto confirm.
Use this page to create and maintain cleanup rules.
Each rule is a collapsible card. The collapsed view shows:
- Rule name.
- Query summary.
- Attachment status.
- Action badges.
- Duplicate and delete icon buttons.
Open a rule to edit:
- Rule name.
- Gmail search query.
- Attachment-only option.
- Actions.
Recommended company-domain pattern:
(from:company.com OR to:company.com OR cc:company.com)
Organization domain example:
(from:example.org OR to:example.org OR cc:example.org)
Only emails with attachments:
(from:bank.com OR to:bank.com OR cc:bank.com) has:attachment
The UI checkbox adds or removes has:attachment for you.
Use this page to inspect existing Gmail labels.
- Load labels fetches labels from Gmail.
- Samples shows example messages under a label.
- Move to Trash moves up to the selected limit of messages from that label
to Gmail Trash after typing
TRASH.
The active label is highlighted and moved to the top while a label action is in progress or after samples are loaded.
Shows local history of rule apply and label trash actions.
History is stored in:
cleanup_history.jsonl
Supported actions:
| Action | Effect |
|---|---|
label |
Creates or applies a Gmail label. |
archive |
Removes INBOX; message stays in All Mail and labels. |
mark_read |
Removes UNREAD. |
trash |
Moves message to Gmail Trash. |
The GUI is preferred, but the CLI remains available.
Analyze inbox clutter:
uv run --system-certs python gmail_cleanup.py analyze --limit 500Preview rule actions:
uv run --system-certs python gmail_cleanup.py plan --rules rules.yml --limit 200 --samples 5Apply planned actions:
uv run --system-certs python gmail_cleanup.py apply --rules rules.yml --limit 50 --confirm.
|-- app_api.py FastAPI backend for local dashboard
|-- gmail_cleanup.py Gmail API and CLI logic
|-- docs/screenshots/ Public-safe UI screenshots
|-- pyproject.toml Python dependencies managed by uv
|-- rules.example.yml Shareable example rules
|-- rules.yml Your private local rules, gitignored
|-- token.json Your private OAuth token, gitignored
|-- credentials.json Your private OAuth client, gitignored
|-- web/ React + Vite dashboard
`-- README.md
Add your Gmail account under Google Auth Platform > Audience > Test users. You do not need Google app verification for your private local testing app.
Download the desktop OAuth client JSON from Google Cloud Console, rename it to
credentials.json, and place it in the project root.
Use:
uv run --system-certs ...The app also uses truststore so runtime Gmail API calls use the Windows system
certificate store.
Prefer configuring the correct CA certificate. If you are on a personal machine and accept the tradeoff, this can unblock install:
npm config set strict-ssl false
npm installThe app now matches labels case-insensitively. If Gmail has BIll and your rule
uses BILL, the existing label is reused.
These files should stay local:
credentials.json
token.json
rules.yml
cleanup_history.jsonl
web/node_modules/
web/dist/
Issues and pull requests are welcome. Anyone can open an issue or propose a pull request, but changes are reviewed and merged by the repository owner or maintainers. See CONTRIBUTING.md for details.
This project is licensed under the MIT License. See LICENSE.

