Organizes emails in catch-all domain inboxes by sorting them into subfolders based on the recipient address.
Catch-all domains are great for privacy - you can give every service a unique address like amazon@yourdomain.com. The downside: everything lands in one inbox. After a few years, you've got thousands of emails from dozens of aliases, all jumbled together. Good luck finding that one receipt.
fltr-mail fixes this by sorting emails into subfolders based on who they were sent to:
INBOX/
amazon/ <- emails sent to amazon@yourdomain.com
github/ <- emails sent to github@yourdomain.com
newsletter/ <- emails sent to newsletter@yourdomain.com
- Python 3.11+
- uv (recommended) or pip
- An IMAP-enabled email account
git clone git@github.com:nostoslabs/fltr-mail.git
cd fltr-mail
# With uv
uv sync
# Or with pip
pip install -e .cp .env.example .envEdit .env:
IMAP_HOST=imap.example.com
IMAP_PORT=993
IMAP_SSL=true
IMAP_USER=your-email@example.com
IMAP_PASS=your-password
MAIL_DOMAIN=yourdomain.comMailfence:
IMAP_HOST=imap.mailfence.com
IMAP_PORT=993
IMAP_SSL=trueProtonMail (via Bridge):
IMAP_HOST=127.0.0.1
IMAP_PORT=1143
IMAP_SSL=false
IMAP_PASS=<password-from-proton-bridge>Fastmail:
IMAP_HOST=imap.fastmail.com
IMAP_PORT=993
IMAP_SSL=trueuv run fltr test-connectionSee email counts by recipient address:
uv run fltr statsTotal emails: 1247
Unique addresses: 43
amazon: 312 (25.0%)
github: 198 (15.9%)
newsletter: 87 (7.0%)
...
uv run fltr foldersSee what would be moved without touching anything:
uv run fltr organizeuv run fltr organize --execute -x, --execute Actually move emails (default is dry-run)
-f, --folder TEXT Source folder [default: INBOX]
-n, --limit INT Max emails to process
-e, --env PATH Path to .env file
# Process first 100 emails only
uv run fltr organize --limit 100 --execute
# Organize a different folder
uv run fltr organize --folder "Archive" --execute
# Use a specific config
uv run fltr organize --env /path/to/.env --execute- Connects via IMAP
- Fetches headers (To, From, Subject) for each email
- Extracts the local part of addresses matching your domain (
amazonfromamazon@yourdomain.com) - Creates subfolders as needed (
INBOX/amazon) - Copies each email to its subfolder
- Marks originals as deleted
- Expunges at the end
A progress bar shows what's being processed.
Nothing moves unless you pass --execute. Emails are copied first, then marked deleted - the expunge only runs after all copies succeed. If you kill the script mid-run, you might end up with duplicates, but you won't lose mail.
uv sync --group dev
uv run ruff check src/
uv run pytestMIT