制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗MailTag is a Python-based email automation tool that classifies and organizes emails into a 19-category business taxonomy using on-device AI. It supports both IMAP and Gmail, with MLX-powered local inference on Apple Silicon.
MailTag files mail into 19 business-sector categories (Banque & Placements, Santé, Achats, Éditeurs IT & Cloud, Contacts…) instead of hundreds of IMAP folders. New mail first lands in an action folder (1-A traiter, 2-A payer, 3-A lire, 4-Pour info, the provider's standard Promotions, or 5-A revoir when unsure) and moves into its category once read and a week old. Category folders follow PARA: Domaines/ (areas: bank, health, family…), Ressources/ (topics: newsletters, IT vendors, media…) and the standard Archive/ (purchases, parcels); projects are your own folders.
The classification chain, first match wins:
nomic-embed-text-v1.5, accepted at a score of at least nomic_threshold5-A revoir — anything elseIMAP runs in two steps: rules on message headers first (junk folder and INBOX), then the models on the full body of the rest (Pass 3, nomic + Gemma, is currently at rest with [mlx] enabled = false: the rules classify and everything else goes to 5-A revoir). Filing a mail out of 5-A revoir teaches MailTag its sender. The rules were learned from the legacy folders with scripts/taxonomy_setup.py and a local Streamlit review page; see the usage docs. Day-to-day use (folders, archiving, teaching MailTag, Gmail) is in the user guide.
git clone https://github.com/fjacquet/mailtag.git
cd mailtag
uv sync -U --all-extras
Configuration uses two sources:
config.toml — main config (logging, imap, gmail, fast_parse, mlx, taxonomy, webhook).env — secrets only (IMAP_USER, IMAP_PASSWORD, WEBHOOK_API_KEY).env variables[email protected]
IMAP_PASSWORD=your-password
# Only for `serve`: WEBHOOK_API_KEY=your-key
[mlx]
enabled = true
embedding_model = "nomic-ai/nomic-embed-text-v1.5" # nomic centroids
llm_model = "mlx-community/gemma-4-e4b-it-OptiQ-4bit" # Gemma second opinion
Gmail runs through the Gmail API (OAuth), not IMAP. Create an OAuth desktop client in
Google Cloud Console, save it as secrets/credentials.json, and run
run --provider gmail --validate once to open the browser and save secrets/token.json. See the
configuration docs for details.
python src/main.py run --provider all # Classify all providers
python src/main.py run --provider imap # IMAP only
python src/main.py run --provider gmail # Gmail (through the Gmail API) only
python src/main.py run --provider imap --validate # Read-only (no moves)
python src/main.py serve # Webhook API server
Taxonomy setup and legacy folder migration (dry run unless --apply):
uv run python scripts/taxonomy_setup.py scan # read-only pass over the legacy folders
uv run python scripts/taxonomy_setup.py crosscheck # Gemma opinion per sender
uv run streamlit run scripts/taxonomy_review.py # local review page
uv run python scripts/taxonomy_setup.py build # rules and nomic centroids
uv run python scripts/taxonomy_setup.py migrate [--apply] # move legacy folder mail into the categories
uv run python scripts/taxonomy_setup.py prune [--apply] # delete the emptied legacy folders
uv run python scripts/taxonomy_setup.py reorganize [--apply] # PARA folders, standard Promotions
Bulk review of 5-A revoir (own the decision per domain or per sender instead of mail by mail; dry
run unless --apply):
uv run python scripts/taxonomy_setup.py review-scan --provider imap|gmail # group, Gemma suggestion
uv run streamlit run scripts/taxonomy_review.py # stage 5: decide
uv run python scripts/taxonomy_setup.py refile-review --provider imap|gmail [--apply] # move covered mail
db/taxonomy/: validated, learned and domain rules (validated.json, senders.json, domains.json, validated_domains.json, folder_overrides.json, control.json)db/pending_archive*.json: category of each mail waiting in an action folder (one file per account)db/backups/: copies of both, taken at the start of each run (10 per file)data/taxonomy_centroids.npz: nomic centroids per categorydata/legacy_folders.json: frozen list of the legacy folders (migration, centroids)data/non_commercial_domains.yaml: domains that never get a domain ruleThe Docker image runs the webhook API with rules only (no MLX): validated and learned senders and domain rules classify; everything else goes to 5-A revoir. Do not run serve in Docker (with db/ mounted) while a run works on the Mac: flock does not cross the Docker Desktop VM boundary.