DonnIA
Toutes les ressources
GuideAgents25 min

Un agent qui trie la boîte mail

Classer les messages, préparer des brouillons et proposer des créneaux, sans jamais rien envoyer à ta place.


Deux cents messages non lus, dont peut-être six qui demandent une action de ta part aujourd'hui. Le coût n'est pas la lecture, c'est le tri : rouvrir la boîte quinze fois par jour pour vérifier qu'on n'a rien raté. Un agent fait très bien ce tri, à condition qu'on lui interdise formellement de répondre à ta place.

C'est la ligne rouge de ce guide, et elle n'est pas décorative. Un agent qui envoie un mail engage ton nom auprès d'un client, d'un candidat, d'une administration. Un agent qui prépare un brouillon ne fait que te faire gagner les huit minutes de rédaction. Le rapport bénéfice / risque est incomparable, et il coûte exactement une ligne de code de différence.

Deuxième point à regarder en face avant de commencer : ce qui transite. Une boîte mail professionnelle contient des noms, des adresses, des montants, parfois des données de santé ou des CV. Tout ce que l'agent lit part chez le fournisseur du modèle. Ce guide montre comment restreindre ce flux plutôt que comment l'ignorer.

Ce que l'agent fait, et ce qu'il ne fait pas

Il faitIl ne fait pas
Classer les messages par urgence et par typeDécider qu'un message n'a pas besoin de réponse
Rédiger un brouillonEnvoyer quoi que ce soit
Repérer les créneaux libresAccepter ou refuser une invitation
Signaler une échéanceCréer un événement dans ton agenda

La colonne de droite n'est pas une question de capacité technique. C'est une question de qui porte la responsabilité quand c'est faux.

Le périmètre du jeton ne suffit pas à empêcher l'envoi

Sur l'API Gmail, créer un brouillon (users.drafts.create) exige l'un des périmètres gmail.compose, gmail.modify ou https://mail.google.com/. Le périmètre gmail.readonly ne suffit pas. Or gmail.compose est décrit comme « gérer les brouillons et envoyer des e-mails » : il n'existe pas de périmètre qui autorise le brouillon sans autoriser l'envoi. La garantie « il n'envoie pas » doit donc venir de ton code, qui n'appelle jamais la méthode d'envoi, pas du consentement OAuth.

Avant de commencer

  • Un compte Google Workspace ou Gmail, et un projet Google Cloud
  • Python ou Node.js, et une clé API de modèle
  • Une définition écrite de ce qui est « urgent » chez toi

1Demander le minimum de périmètres

Deux jetons valent mieux qu'un. Le premier lit, le second écrit des brouillons. Le script de tri n'utilise que le premier.

PérimètreCe qu'il ouvre
https://www.googleapis.com/auth/gmail.readonlyLecture des messages et des réglages
https://www.googleapis.com/auth/gmail.composeGestion des brouillons, et envoi
https://www.googleapis.com/auth/calendar.readonlyLecture des agendas accessibles
https://www.googleapis.com/auth/calendar.eventsLecture et modification des événements

Pour la préparation d'agenda décrite plus bas, calendar.readonly suffit : l'agent propose des créneaux, c'est toi qui crées l'événement.

2Filtrer avant d'envoyer au modèle

C'est l'étape que tout le monde saute, et c'est la plus rentable, en coût comme en confidentialité. Le modèle n'a pas besoin du corps complet de deux cents messages pour les trier. L'expéditeur, l'objet et les trois cents premiers caractères suffisent dans la très grande majorité des cas.

import base64
from googleapiclient.discovery import build

service = build("gmail", "v1", credentials=creds)

reponse = service.users().messages().list(
    userId="me", q="is:unread newer_than:2d", maxResults=60
).execute()

resume = []
for ref in reponse.get("messages", []):
    msg = service.users().messages().get(
        userId="me", id=ref["id"], format="metadata",
        metadataHeaders=["From", "Subject", "Date"],
    ).execute()
    entetes = {h["name"]: h["value"] for h in msg["payload"]["headers"]}
    resume.append({
        "id": ref["id"],
        "de": entetes.get("From", ""),
        "objet": entetes.get("Subject", ""),
        "date": entetes.get("Date", ""),
        "extrait": msg.get("snippet", "")[:300],
    })

Le format="metadata" avec une liste d'en-têtes explicite est le point clé : tu ne télécharges même pas le corps du message. Le snippet renvoyé par Gmail donne déjà l'aperçu, et il est court par construction.

Ce qui ne doit pas partir ne doit pas être lu

Exclus des dossiers entiers en amont, avec la requête de recherche, plutôt qu'en demandant au modèle d'ignorer certains sujets. -label:RH -label:Sante dans le q coûte zéro jeton et ne dépend d'aucun jugement du modèle.

3Le prompt de tri

Un seul appel sur la liste entière. Le modèle voit tout d'un coup, ce qui lui permet de repérer les relances et les fils dupliqués.

Tu tries une boite mail professionnelle. Voici [N] messages au format
identifiant, expediteur, objet, date, extrait.

Classe chaque message dans exactement une categorie :
- ACTION : demande explicite qui attend une reponse de moi
- ECHEANCE : contient une date limite qui me concerne
- INFORMATION : a lire, sans action attendue
- IGNORER : notification automatique, newsletter, accuse de reception

Regles :
1. Dans le doute entre ACTION et INFORMATION, choisis ACTION.
2. Si plusieurs messages appartiennent au meme fil, garde le plus recent
   et signale les autres comme relances.
3. Pour chaque ACTION et chaque ECHEANCE, ecris en une ligne ce qui est
   attendu de moi, et la date si elle est mentionnee.
4. Ne resume pas les IGNORER. Donne seulement leur nombre.
5. Tu ne rediges aucune reponse a cette etape.

[LISTE]

Le point 5 n'est pas superflu. Sans lui, un modèle un peu zélé commence à proposer des formulations, et tu perds la lisibilité du tri.

4Rédiger des brouillons, sans envoi possible

Deuxième appel, uniquement sur les messages classés ACTION, et cette fois avec le corps complet du message. La règle : le script crée le brouillon, point.

brouillon = service.users().drafts().create(
    userId="me",
    body={"message": {"threadId": fil_id, "raw": corps_encode}},
).execute()

Il n'y a pas d'appel à drafts().send() ni à messages().send() dans le fichier. C'est ça, la garantie. Si tu veux la rendre visible pour l'équipe, ajoute un commentaire au-dessus qui dit pourquoi elle n'y est pas.

Le threadId place le brouillon dans le bon fil de discussion, ce qui te permet de le relire dans son contexte plutôt que dans un dossier à part.

5Préparer l'agenda sans y toucher

Même logique côté agenda : l'agent lit les événements de la semaine, croise avec les ECHEANCE sorties du tri, et rend une proposition en texte. C'est toi qui cliques.

from datetime import datetime, timedelta, timezone

debut = datetime.now(timezone.utc)
fin = debut + timedelta(days=7)

cal = build("calendar", "v3", credentials=creds)
evenements = cal.events().list(
    calendarId="primary",
    timeMin=debut.isoformat(),
    timeMax=fin.isoformat(),
    singleEvents=True,
    orderBy="startTime",
).execute().get("items", [])

Le singleEvents=True développe les événements récurrents en occurrences réelles. Sans lui, une réunion hebdomadaire apparaît une seule fois et tes créneaux « libres » sont faux.

Le rendu quotidien

Vise dix lignes. Trois actions, deux échéances, un créneau proposé, un compteur de messages ignorés. Un rapport plus long ne sera pas lu, et un agent secrétaire qui n'est pas lu ne fait qu'ajouter une notification de plus à ta journée.

Garde aussi une trace : la liste des identifiants de messages classés IGNORER, dans un fichier. Le jour où quelque chose passe à travers, tu sauras si c'est le tri qui a failli ou la collecte.

Quelques prompts pour aller plus loin

ObjectifPrompt à adapter
Écrire ta définition de l'urgenceVoici 20 mails que j'ai traites le jour meme et 20 que j'ai laisses une semaine. Deduis-en une regle de classement en trois lignes, formulee pour un agent de tri.
Calibrer le triVoici ma consigne de tri et 40 messages avec mon propre verdict pour chacun. Signale uniquement les cas ou ta consigne aurait donne un verdict different du mien, et pourquoi.
Réduire la donnee transmiseVoici mon script de collecte Gmail. Liste chaque champ envoye au modele et signale ceux qui ne servent pas au classement. Propose la version minimale.
Écrire un brouillon sobreVoici un mail recu et le contexte : [CONTEXTE]. Redige une reponse de 5 lignes maximum, sans formule d'enthousiasme, qui repond a la question posee et rien d'autre. Si une information me manque pour repondre, dis-le au lieu d'inventer.
Auditer le perimetreVoici les perimetres OAuth demandes par mon application et la liste des appels API qu'elle effectue reellement. Signale tout perimetre demande mais jamais utilise.

Tu as d’autres ressources comme ça ?

Ce que tu viens de lire est entièrement gratuit. Une nouvelle ressource part chaque semaine dans la newsletter : guides, modèles à copier et liens triés, sans compte à créer.

Cette page est en accès libre, n’hésite pas à la partager.