A program to delete trash emails based on keyword and label filters.
Node.js & npm (Node 18+)
npm install -g trash-cleanergit clone https://github.com/hasankhan/trash-cleaner
cd trash-cleaner
# If you want to try out the development version then 'git checkout dev'
npm install -g
The simplest way to get started. Works with any email provider.
Store credentials securely in your OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service):
trash-cleaner init # Create config directory with sample files
trash-cleaner login # Prompts for IMAP credentials, saves to OS keychainFor other services:
trash-cleaner login -s gmail
trash-cleaner login -s outlookTo remove stored credentials:
trash-cleaner logout # Remove IMAP credentials from keychain
trash-cleaner logout -s gmailIf your system doesn't have a keychain, credentials fall back to JSON files:
- Run
trash-cleaner initto create sample config files - Edit
config/imap.credentials.jsonwith your email settings:{ "host": "imap.gmail.com", "port": 993, "user": "your-email@gmail.com", "password": "your-app-password" }
- Gmail: Create an App Password (requires 2FA)
- Outlook: Use your regular password or an app password
- Yahoo: Account Security → Generate app password
Common IMAP servers:
| Provider | Host | Port |
|---|---|---|
| Gmail | imap.gmail.com | 993 |
| Outlook/Hotmail | outlook.office365.com | 993 |
| Yahoo | imap.mail.yahoo.com | 993 |
| iCloud | imap.mail.me.com | 993 |
Note: Some features (undo) are only available with the Gmail/Outlook API backends. Use
--service gmailor--service outlookfor those.
- Create a Google Cloud Platform project with the API enabled.
- Create Authorization credentials for a desktop application and download
gmail.credentials.jsonfile in theconfigdirectory. - Rename
keywords.json.samplefile in theconfigdirectory tokeywords.jsonand update its contents.
- Register an application with the Microsoft identity platform.
- Rename
outlook.credentials.json.samplefile in theconfigdirectory tooutlook.credentials.jsonand update its contents. - Rename
keywords.json.samplefile in theconfigdirectory tokeywords.jsonand update its contents.
Initialize the config directory with sample files:
trash-cleaner init [configDirPath]This creates starter keywords.json, imap.credentials.json, gmail.credentials.json, and outlook.credentials.json files. Edit them to match your setup (see configuration sections above).
Rules live in keywords.yaml in your config directory (~/.config/trash-cleaner/ by default). The file is a YAML list of rule objects. Each rule tells trash-cleaner which emails to match and what to do with them.
Note: JSON config files (
keywords.json, etc.) are also supported for backward compatibility. If both exist, YAML takes priority.
| Field | Required | Description |
|---|---|---|
value |
Yes | Keyword rules: A regex pattern to match. LLM rules: A natural language description. |
title |
No | A human-readable name for the rule, shown when it matches. Defaults to value if omitted. |
fields |
No | Comma-separated email fields to search: from, subject, snippet, body, or * for all. Default: * |
labels |
No | Comma-separated folder/label names to scope the rule: inbox, spam, trash, junk email, or * for all. Default: * |
action |
No | What to do with matches: delete, archive, or mark-as-read. Default: delete |
type |
No | Rule type: keyword (regex, default) or llm (external LLM classification). |
llm |
For LLM rules | Name of the LLM provider (must match a key in llm-providers.yaml). |
Keyword rules use regular expressions to match email content. They are fast and precise.
- value: casino
fields: "*"
labels: "*"
title: Casino spam
- value: credit|loan
fields: subject
labels: spam, junk email
title: Credit scams
- value: newsletter
fields: subject
labels: inbox
action: archive
title: Newsletters
- value: notification
fields: subject
labels: inbox
action: mark-as-read- Delete all trash:
value: "."withlabels: trash, deleted items— the.regex matches any character. - Match multiple words:
value: lucky|winner|prize— uses regex|(OR) to match any of the words. - Match emoji in subject:
value: "[\\u{1F600}-\\u{1F64F}]"— uses Unicode character ranges. - Matching is case-insensitive and diacritic-insensitive (e.g., "café" matches "cafe").
LLM rules invoke an external AI tool (Claude, Copilot, Ollama, etc.) to classify emails by meaning. Write a natural language description of what you want to match — the tool decides if each email fits.
- value: marketing or promotional email
labels: "*"
type: llm
llm: claude
action: archive
title: Marketing emails
- value: someone selling me something
labels: inbox
type: llm
llm: claudeCreate llm-providers.yaml in your config directory (~/.config/trash-cleaner/):
claude:
command: claude
args: ["--print", "{{prompt}}"]
copilot:
command: copilot-cli
args: ["-p", "{{prompt}}"]
ollama:
command: ollama
args: ["run", "llama3", "{{prompt}}"]Each provider needs:
command— the CLI executable name (must be in your PATH)args— arguments array with{{prompt}}as a placeholder for the rendered promptprompt(optional) — custom prompt template; defaults to asking "does this email match?" with true/false response
The {{prompt}} placeholder in args is replaced with the full prompt containing the rule description and email content. The tool must respond with "true" or "false".
- LLM rules are slower than keyword rules (network call per email) but can catch things regex can't.
- No data is sent to trash-cleaner servers — classification goes through your configured CLI tool.
- Run
trash-cleaner initto create a samplellm-providers.yaml.
Use labels to limit which folders a rule applies to:
"labels": "inbox"— only match emails in your inbox"labels": "spam,junk email"— only match emails in spam/junk folders"labels": "trash,deleted items"— only match emails in trash"labels": "*"— match emails in any folder
Use fields to limit which parts of an email are searched (keyword rules only):
"fields": "subject"— only search the subject line"fields": "subject,body"— search subject and body"fields": "*"— search all fields (from, subject, snippet, body)
- value: "."
fields: "*"
labels: trash, deleted items
title: Clean trash folder
- value: casino|lottery|winner
fields: "*"
labels: spam, junk email
title: Gambling spam
- value: unsubscribe
fields: body
labels: inbox
action: archive
title: Bulk mail
- value: notification
fields: subject
labels: inbox
action: mark-as-read
- value: marketing or promotional email
labels: inbox
type: llm
llm: claude
action: archive
title: Marketing emailsRules are evaluated in order — the first matching rule wins. Place more specific rules before general ones.
To get the list of all parameters type trash-cleaner -h
Usage: trash-cleaner [options]
Options:
-V, --version output the version number
-r, --reconfig reconfigures the auth for a service
-t, --dry-run perform a dry-run cleanup without deleting the emails
-d, --debug output extra debugging info
-l, --launch launch the auth url in the browser
-q, --quiet suppress verbose output (for cron/scripts)
-i, --interactive preview matches and confirm before acting
-f, --format <format> output format: text or html (default: "text")
-m, --min-age <days> only process emails older than N days
-c, --configDirPath <path> the path to config directory (default: "config")
-s, --service <service> the email service to use (choices: "imap", "gmail", "outlook", default: "imap")
-a, --account <name> the account name for multi-account support (default: "default")
-h, --help display help for command
Creates a config directory with sample configuration files.
Displays all active keyword rules and allowlist patterns.
Validates configuration files and reports any issues.
Shows the last batch of processed emails and offers to restore them.
Prompts for credentials and saves them securely in the OS keychain. Supports --service imap (default), gmail, or outlook.
Removes stored credentials from the OS keychain.
Run against different accounts using the -a flag:
trash-cleaner -s gmail -a work
trash-cleaner -s gmail -a personalEach account stores its own credentials (e.g., gmail.credentials.work.json).
Create config/allowlist.json to protect specific senders from any actions:
[
"boss@company\\.com",
".*@important\\.org"
]Patterns are case-insensitive regular expressions matched against the sender.
Use --interactive to preview matched emails before taking action:
trash-cleaner --interactiveUse --quiet for cron jobs or scripts — suppresses spinner and verbose output:
trash-cleaner --quietGenerate an HTML report instead of console output:
trash-cleaner --format htmlThis creates a timestamped HTML file in the current directory.
API calls automatically retry with exponential backoff on transient failures (429, 5xx, network errors).
Only process emails older than a certain number of days:
trash-cleaner --min-age 7Check your configuration files for errors before running:
trash-cleaner validateAfter processing, actions are logged. Use trash-cleaner undo to restore the last batch:
trash-cleaner undoTo run trash-cleaner automatically on a schedule:
Run crontab -e and add a line. For example, to run every hour:
0 * * * * /usr/local/bin/trash-cleaner --quiet -c /path/to/config
Create ~/Library/LaunchAgents/com.trash-cleaner.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.trash-cleaner</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/trash-cleaner</string>
<string>--quiet</string>
<string>-c</string>
<string>/path/to/config</string>
</array>
<key>StartInterval</key>
<integer>3600</integer>
</dict>
</plist>Load it with: launchctl load ~/Library/LaunchAgents/com.trash-cleaner.plist
schtasks /create /tn "TrashCleaner" /tr "trash-cleaner --quiet -c C:\path\to\config" /sc hourlynpm install # Install dependencies
npm test # Run tests
npm run lint # Run ESLint
npm run typecheck # Run JSDoc type checking
npm run coverage # Generate coverage reportReleases are automated via GitHub Actions. To publish a new version:
npm version patch # or minor, or major
git push --follow-tagsThis triggers the publish workflow which runs tests and publishes to npm.
Requires NPM_TOKEN secret configured in the repository settings.