Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

57 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gmail Cleaner Bot

Bot automatisé pour nettoyer les emails Gmail selon des règles personnalisées.

Fonctionnalités

  • Suppression/archivage automatique des emails selon des règles
  • Filtrage par sujet, expéditeur, destinataire, contenu du body, label
  • Opérateurs: contient, contient (exact), égal, commence par, finit par
  • Support regex via checkbox dédiée
  • Condition d'âge (ex: emails de plus de 3 jours)
  • Pagination automatique (traite jusqu'à 500 messages par règle)
  • TUI (Terminal User Interface) pour gérer les règles
  • Filtrage des règles en temps réel (vim-like avec /)
  • Modal d'exécution avec logs en temps réel (sujet, expéditeur, date)
  • Indicateur visuel du mode dry-run
  • Suivi de la dernière exécution de chaque règle
  • Logs de toutes les actions effectuées avec rotation automatique
  • Logs de progression pendant la recherche (affiche le nombre de messages récupérés)
  • Mode dry-run pour tester sans modifier
  • Exclusion configurable des dossiers (Corbeille, Spam, Brouillons, Envoyés)
  • Rate limiting automatique de l'API (40 appels/sec pour respecter les quotas Google)
  • Durée d'exécution affichée en fin de traitement et dans le rapport email

Prérequis

  • Python ≥ 3.10. Le code utilise la syntaxe d'union PEP 604 (X | None) évaluée à l'exécution ; sur Python 3.9 ou antérieur, la TUI plante au démarrage (TypeError: unsupported operand type(s) for |).
  • Un compte de service Google Workspace avec Domain-Wide Delegation (voir plus bas).

Installation

# Configurer l'environnement
cp .env.example .env
# Éditer .env avec vos paramètres

# Lancer (le venv est créé automatiquement)
./manage.sh

manage.sh crée le venv au premier lancement et le reconstruit automatiquement s'il est cassé (interpréteur supprimé/déplacé → symlink venv/bin/python mort) ou trop ancien (< 3.10). Si aucun Python ≥ 3.10 n'est trouvé, il s'arrête avec une erreur explicite plutôt que de bâtir un environnement à moitié fonctionnel.

Ou manuellement:

# Créer un environnement virtuel
python3 -m venv venv
source venv/bin/activate

# Installer les dépendances
pip install -r requirements.txt

Configuration Google Workspace

  1. Créer un projet dans Google Cloud Console
  2. Activer l'API Gmail
  3. Créer un Service Account avec Domain-Wide Delegation
  4. Télécharger la clé JSON et la placer dans credentials.json
  5. Dans Google Admin Console:
    • Security > API Controls > Domain-wide Delegation
    • Ajouter le Client ID du Service Account
    • Scope requis:
      • https://www.googleapis.com/auth/gmail.modify

Utilisation

Interface TUI

./manage.sh
# ou
./manage.sh tui

Raccourcis clavier:

  • / - Filtrer les règles (vim-like: taper le texte, Enter pour confirmer, Escape pour effacer)
  • n - Nouvelle règle
  • g - Générer des suggestions de règles (scan du compte, voir ci-dessous)
  • a - Exécuter toutes les règles actives
  • s - Exécuter la règle sélectionnée
  • t - Tester la connexion Gmail
  • d - Activer/désactiver le mode dry-run
  • q - Quitter

L'indicateur jaune "DRY MODE" s'affiche en haut quand le mode simulation est actif.

Générateur de règles (Suggestions)

Touche g (ou bouton Suggest) dans la TUI. Le bot scanne les messages récents (6 derniers mois par défaut), repère les motifs qui reviennent souvent et pour lesquels aucune règle n'existe encore, puis propose des règles de suppression prêtes à créer — classées par nombre d'occurrences.

Regroupement sur deux axes :

  • Expéditeur : adresses From fréquentes → règle from contains <adresse>.
  • Sujet : phrases de sujet récurrentes (normalisées : [tags], chiffres, dates et hostnames variables sont ignorés) → règle subject contains <phrase>. La phrase proposée est le plus long segment littéral commun au groupe, donc le contains matche bien tous les messages concernés.

Dans l'écran de suggestions :

  • c (ou Create) : créer la règle sélectionnée.
  • a (ou Create All) : créer toutes les suggestions listées.
  • Esc : fermer.

Les suggestions déjà couvertes par une règle active (ou en doublon exact) sont automatiquement écartées. Rien n'est créé sans votre action — vous validez chaque règle. ⚠️ Une suggestion par expéditeur peut être large (ex. votre propre adresse si des services vous écrivent depuis votre domaine) : vérifiez avant de créer.

Script en ligne de commande

# Exécuter le nettoyage
./manage.sh run

# Mode dry-run (ne fait aucune modification)
./manage.sh dry

# Tester la connexion
./manage.sh test

# Installer/mettre à jour les dépendances
./manage.sh install

# Déployer sur le serveur de production (via Plesk Git)
./manage.sh deploy

Déploiement serveur (prod)

Sur le serveur de production, un alias est disponible :

cleangmail        # Lance la TUI
cleangmail run    # Exécute toutes les règles
cleangmail dry    # Dry-run (simulation)
cleangmail test   # Test connexion Gmail

Cron configuré : tous les jours à 4h00

Configuration Cron

# Éditer le crontab
crontab -e

# Tous les jours à 4h — alerte email UNIQUEMENT si le run échoue (via chronic)
MAILTO="vous@example.com"
0 4 * * * /usr/bin/chronic /chemin/vers/manage.sh run

Alertes email : chronic (paquet moreutils) bufferise la sortie et ne la laisse passer — donc cron envoie un mail à MAILTOqu'en cas d'échec (code retour ≠ 0). En cas de succès, tout est masqué : pas de mail quotidien inutile.

⚠️ Éviter ... run >> logs/cron.log 2>&1 : rediriger toute la sortie vers un fichier prive cron de sortie à envoyer, donc aucun mail ne part, même en cas d'erreur (une panne peut passer inaperçue longtemps). L'application écrit de toute façon son propre logs/cleaner.log.

Cron sur WSL2

Cron ne démarre pas automatiquement sur WSL2. Pour l'activer:

# Vérifier/démarrer cron
sudo service cron status
sudo service cron start

Pour démarrer cron automatiquement, ajouter dans /etc/wsl.conf:

[boot]
command = service cron start

Note: WSL2 s'arrête après ~8 secondes d'inactivité. Pour que les tâches cron tournent en permanence:

  • Garder un terminal WSL ouvert
  • Ou utiliser le Task Scheduler Windows pour lancer wsl -e /chemin/vers/manage.sh run

Exemples de règles

Règle simple

Supprimer tous les messages de plus de 3 jours contenant "Host Up" dans le sujet:

Paramètre Valeur
Name Cleanup Host Up alerts
Field subject
Operator contains
Value Host Up
Action delete
Older than days 3

Règle avec regex

Supprimer les notifications Plesk (toutes versions):

Paramètre Valeur
Name Plesk Updates
Field subject
Regex ✓ (coché)
Value Plesk .* Update is Live
Action delete
Older than days 7

Note regex: .* signifie "n'importe quels caractères". Le pattern ci-dessus matche "Plesk Obsidian 18.0.74 Update is Live".

Règle par label

Supprimer tous les messages avec le label "Notifications" de plus de 30 jours:

Paramètre Valeur
Name Cleanup old notifications
Field label
Operator equals
Value Notifications
Action delete
Older than days 30

Note: Utiliser le nom du label tel qu'il apparaît dans Gmail (ex: "Ma Catégorie - Sous-label") ou le slug technique (ex: "ma-categorie---sous-label"). Les deux formats fonctionnent.

Structure du projet

gmail-cleaner/
├── manage.sh           # Script de gestion (point d'entrée)
├── cleaner.py          # Script principal (cron)
├── tui.py              # Interface terminal
├── src/
│   ├── config.py       # Configuration
│   ├── database.py     # Modèles et base SQLite
│   ├── gmail_client.py # Client API Gmail
│   └── rules_engine.py # Moteur de règles
├── data/               # Base de données SQLite
├── logs/               # Fichiers de logs
├── .env                # Configuration (non versionné)
└── credentials.json    # Clé Service Account (non versionné)

Variables d'environnement

Variable Description Défaut
GOOGLE_CREDENTIALS_PATH Chemin vers credentials.json ./credentials.json
GMAIL_USER_EMAIL Email à impersonner (requis)
DATABASE_PATH Chemin base SQLite ./data/gmail_cleaner.db
LOG_PATH Dossier des logs ./logs
LOG_LEVEL Niveau de log INFO
LOG_MAX_SIZE Taille max du log avant rotation (octets) 5242880 (5 MB)
LOG_BACKUP_COUNT Nombre de fichiers de backup 3
DRY_RUN Mode simulation false
MAX_SEARCH_RESULTS Messages max par règle (voir limites API ci-dessous) 500
PYTHON_PATH Chemin vers Python (auto-détecté)
Exclusion de dossiers
EXCLUDE_TRASH Exclure la corbeille de la recherche false
EXCLUDE_SPAM Exclure le spam de la recherche false
EXCLUDE_DRAFTS Exclure les brouillons de la recherche false
EXCLUDE_SENT Exclure les envoyés de la recherche (⚠️ voir note ci-dessous) false
Rapport email
SMTP_ENABLED Activer l'envoi de rapport par email false
SMTP_HOST Serveur SMTP (requis si SMTP_ENABLED)
SMTP_PORT Port SMTP 587
SMTP_USER Utilisateur SMTP (requis si SMTP_ENABLED)
SMTP_PASSWORD Mot de passe SMTP (requis si SMTP_ENABLED)
SMTP_FROM Adresse expéditeur (requis si SMTP_ENABLED)
SMTP_TO Adresse destinataire (requis si SMTP_ENABLED)
SMTP_TLS Utiliser STARTTLS true
Déploiement
DEPLOY_SSH_HOST Alias SSH du serveur de production (requis pour deploy)
DEPLOY_PLESK_DOMAIN Domaine Plesk (requis pour deploy)
DEPLOY_PLESK_REPO Nom du repo Git dans Plesk (requis pour deploy)

⚠️ EXCLUDE_SENT et messages auto-adressés

Gmail applique le label SENT selon l'en-tête From:, pas selon le transport. Un message dont le From: est votre propre adresse est classé SENT même s'il vous est livré (il porte alors à la fois INBOX et SENT) — et même s'il a été émis par un service tiers (NAS, monitoring, backup…) ou relayé par un provider (Mandrill, SES, SendGrid…). Seul compte le fait que le From: = votre adresse.

Conséquence : avec EXCLUDE_SENT=true, la requête ajoute -in:sent et toutes ces notifications auto-adressées sont ignorées par les règles, alors qu'elles sont bien dans la boîte de réception.

  • Si vous voulez que les règles traitent ces messages (ex. purger des alertes de sauvegarde/monitoring envoyées depuis votre propre domaine) → laissez EXCLUDE_SENT=false (défaut).
  • Ne passez EXCLUDE_SENT=true que si vous tenez à préserver tout ce qui porte le label SENT, en acceptant d'exclure aussi ce type de mail auto-adressé.

Symptôme typique : une règle affiche Found N messages mais 0 matched, ou ne trouve qu'une poignée de messages alors que la boîte en contient beaucoup plus.

Rapport par email

Quand SMTP_ENABLED=true, un rapport est envoyé par email après l'exécution via cleaner.py.

Quand le rapport est envoyé :

Commande Email envoyé
manage.sh run ✅ Oui
manage.sh dry ✅ Oui
Cron ✅ Oui
TUI (Run All / Run Selected) ❌ Non

Contenu du rapport :

  • Date et mode d'exécution (LIVE/DRY RUN)
  • Durée d'exécution
  • Nombre de règles traitées
  • Messages trouvés, actions réussies/échouées

Exemple de sujet :

  • [Gmail Cleaner] Rapport du 2024-01-20 04:00 - Aucune action
  • [Gmail Cleaner] Rapport du 2024-01-20 04:00 - 2 erreur(s)

Rotation des logs

La rotation des logs est gérée automatiquement par l'application (pas besoin de logrotate).

Fonctionnement :

  • Quand cleaner.log atteint la taille max (LOG_MAX_SIZE) → renommé en cleaner.log.1
  • Les anciens backups sont décalés (.1.2.3)
  • Le plus ancien est supprimé quand le nombre dépasse LOG_BACKUP_COUNT
  • Un nouveau cleaner.log vide est créé

Exemple avec les valeurs par défaut :

logs/
├── cleaner.log       # Fichier actif (max 5 MB)
├── cleaner.log.1     # Backup le plus récent
├── cleaner.log.2     # Backup intermédiaire
└── cleaner.log.3     # Backup le plus ancien (supprimé à la prochaine rotation)

Limites de l'API Gmail

L'application intègre un rate limiting automatique (40 appels/sec) pour respecter les quotas Google Workspace.

Limite Valeur
Quota par projet 1,200,000 units/min
Quota par utilisateur 15,000 units/min
messages.list 5 units
messages.get 5 units
messages.trash 5 units
messages.delete 10 units
Capacité effective ~1000-1500 emails/min

Avec MAX_SEARCH_RESULTS=500 (défaut), chaque règle peut traiter jusqu'à 500 messages. Pour des dossiers volumineux, cette valeur peut être augmentée.

Référence : Gmail API Usage Limits

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages