Ouvrir une boîte

Agents IA & MCP

MCP email : l’agent IA lit son code de confirmation

Un agent autonome arrive jusqu’à « vérifiez vos e-mails pour le code » et s’arrête là. Voici toute la solution : six outils MCP, sans compte ni clé, et l’un d’eux attend que le message arrive vraiment avant de répondre.

  • Intermédiaire
  • 13 min de lecture
Un petit robot gris tend une enveloppe bleue vers une boîte aux lettres ouverte, avec un chronomètre qui attend entre les deux

De quoi un agent a-t-il besoin que l’API REST ne lui donne pas ?

Il existe une API REST sur ce site, et un développeur qui l’intègre s’en sortira très bien. Un agent, non : il ne peut pas ouvrir la référence, choisir lequel des trois endpoints il veut, et construire à la main une requête avec la bonne query string. Il demande à un serveur ce qu’il sait faire, reçoit des schémas lisibles par une machine, et en appelle un.

Tout ce que fait le service est donc exposé une seconde fois, sous forme d’outils. Six au total, et aucun état à gérer entre les appels :

OutilÀ quoi il sert
create_inboxInvente une nouvelle adresse que l’agent peut communiquer immédiatement. Rien n’est réservé côté serveur, donc l’appel ne peut pas échouer. Accepte un prefix lisible facultatif ; un suffixe aléatoire garantit son unicité.
list_domainsLes domaines publics que tout le monde peut utiliser — utile quand un formulaire vient d’en refuser un.
list_messagesTout ce qui attend à une adresse, du plus récent au plus ancien. Répond immédiatement, même quand il n’y a rien.
read_messageUn message en entier : expéditeur, objet, texte brut, HTML, pièces jointes. C’est là que se trouve le code ou le lien de connexion.
wait_for_messageAttend que quelque chose arrive, puis le renvoie en entier. L’outil à appeler dès qu’un formulaire vient d’être soumis.
delete_messageSupprime un message tout de suite plutôt que d’attendre 5 jours qu’il expire. Idempotent, donc un agent qui réessaie ne coûte rien.

Le serveur répond aussi à initialize par un court paragraphe d’instructions, que la plupart des clients transmettent directement au modèle. Un agent arrive donc déjà en sachant à quoi sert ce service et quelle en est la seule vraie réserve, sans que personne ait eu à l’écrire dans un prompt.

Comment connecter un client MCP en une seule ligne ?

L’endpoint tient en une seule URL, et il n’y a aucune inscription à faire sur les domaines publics. Tous les clients MCP prennent la même forme de configuration — Claude Desktop, Claude Code, Cursor, Continue, l’OpenAI Agents SDK, et tout ce qui parle le protocole :

mcp.json
{"mcpServers":{"grabmail":{"url":"https://grabmail.io/mcp"}}}

Le transport est Streamable HTTP : un POST qui transporte du JSON-RPC 2.0, une réponse JSON, aucun flux qui reste ouvert. Vous pouvez donc tout vérifier depuis un terminal avant même qu’un agent n’intervienne :

lister les outils, depuis un shell
curl -sX POST https://grabmail.io/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Les clients qui cherchent un serveur avant de demander à un humain trouveront /.well-known/mcp.json sur le domaine, qui indique ce même endpoint et son transport.

Comment un agent gère toute une inscription, en quatre appels d’outils ?

C’est la séquence dont presque tout agent a besoin, et il n’y a rien d’autre à savoir :

  1. Appeler create_inbox. La réponse contient une adresse, un alias, le domaine, et une note qui indique à l’agent lequel des deux communiquer. Rien n’a été créé — la boîte commence à exister quand le premier message y arrive.
  2. Mettre l’alias dans le formulaire. Le service auprès duquel l’agent s’inscrit reçoit une adresse qui fonctionne, qui achemine vers la boîte, mais qui ne permet pas de la lire.
  3. Appeler wait_for_message avec l’adresse. Immédiatement après l’envoi du formulaire, pas sur une minuterie. L’appel attend ; il ne fait pas d’interrogation en boucle que l’agent devrait écrire lui-même.
  4. Lire le code dans le message. Le corps complet revient avec la réponse à l’attente, donc il n’y a généralement pas de second appel — read_message n’est utile que pour quelque chose arrivé plus tôt.
Votre agentobtient une adresse et un aliasLe sitereçoit l’alias, envoie le codeGrabMailconserve ce qui arrivewait_for_message, jusqu’à 25 srenvoie le message complet, ou timed_out
Quatre appels, et un seul d’entre eux attend. L’alias part vers le site ; l’adresse reste chez l’agent, c’est elle qu’il écoute.

Pourquoi wait_for_message répond avant que le courrier n’arrive ?

C’est l’outil qui rend un agent réellement utilisable, et celui dont le comportement surprend le plus, donc ça vaut une minute d’explication. Un appel ressemble à ceci :

attendre un message dont l’objet contient « code »
curl -sX POST https://grabmail.io/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":
        {"name":"wait_for_message",
         "arguments":{"address":"demo.5kuqarzuch@grabmail.io",
                       "subject_contains":"code"}}}'

L’appel attend jusqu’à 25 secondes. Si rien n’est arrivé d’ici là, ce n’est pas un échec : il répond simplement et demande à être rappelé :

réponse après une attente sans résultat
{
  "timed_out": true,
  "waited_seconds": 25,
  "message": null,
  "note": "Nothing arrived yet. Call wait_for_message again ..."
}
Pourquoi une limite existe
Chaque seconde d’attente correspond à un worker serveur qui ne fait rien d’autre que dormir, et leur nombre est limité. Une attente qui durerait cinq minutes reviendrait à laisser un agent occuper une place que cent autres réclament. 25 secondes reste aussi sous le délai par défaut de la plupart des clients, si bien que l’appel répond avant que le client n’abandonne de son côté.
Seulement 8 attentes à la fois
Au-delà, l’outil répond immédiatement par timed_out et une note qui l’explique. Mieux vaut se faire dire de revenir que d’être mis en file derrière sept autres agents sans aucun moyen de le savoir.
Le filtrage, pour qu’un mauvais message n’arrête pas l’attente
from_contains et subject_contains font ignorer par l’attente tout ce qui arrive d’autre entre-temps. since_id est celui à passer quand la boîte contenait déjà quelque chose : donnez-lui le dernier id déjà vu, et seul un message réellement nouveau satisfera l’appel.

Faut-il donner l’alias ou l’adresse ?

Chaque boîte ici possède une seconde adresse, longue de douze caractères, qui livre dans la même boîte mais ne peut pas la lire. Cette distinction compte bien plus pour un agent que pour une personne, parce qu’un agent collera sans hésiter ce qu’on lui a donné dans le premier champ venu.

create_inbox ne se contente donc pas de renvoyer une adresse en espérant que ça suffise. Il renvoie les deux, avec un next_step qui précise laquelle est laquelle — l’agent lit lui-même le résultat de l’outil, donc l’instruction arrive là où il en a besoin, plutôt que de rester sur une page de documentation que personne dans la boucle ne peut lire.

Que mettre dans les instructions de l’agent ?

Les outils se décrivent assez bien pour qu’un modèle compétent fasse les choses correctement sans qu’on le lui dise. Cinq lignes suffisent à rendre cela fiable plutôt que simplement probable :

  • Une adresse par inscription. Pas une seule adresse réutilisée partout : une boîte qui reçoit le courrier de six services, ce sont six confirmations que l’agent doit distinguer, et une seule fuite qui les expose toutes.
  • Communiquer l’alias, jamais l’adresse. Ça vaut la peine de le dire explicitement, même si le résultat de l’outil le précise déjà.
  • Appeler wait_for_message juste après l’envoi, et le rappeler en cas de timed_out plutôt que d’y voir un échec. Deux ou trois fois, c’est normal.
  • Passer since_id quand la boîte n’est pas neuve, sinon un ancien message satisfait l’attente et l’agent lit un code expiré depuis une heure.
  • Supprimer le message une fois le code utilisé. Ce n’est pas obligatoire — tout disparaît de toute façon au bout de 5 jours — mais cela referme la fenêtre plus tôt, pour le prix d’un appel idempotent.

Écrit comme un bloc d’instructions, cela tient à peu près en ceci :

prompt système, ou une ligne dans AGENTS.md
Quand vous avez besoin d’une adresse, appelez create_inbox et communiquez
l’ALIAS renvoyé, jamais l’adresse. Juste après l’envoi du formulaire,
appelez wait_for_message avec l’adresse. S’il répond timed_out,
rappelez-le — c’est normal, rien n’est perdu. Passez since_id si la boîte
avait déjà du courrier. Supprimez le message une fois le code utilisé.

Quelles sont les limites à connaître avant de s’appuyer dessus ?

Elles sont toutes publiées plutôt que laissées à découvrir, et aucune offre payante ne les relève :

LimiteValeurCe que cela signifie pour un agent
Une attente25 secondesPuis timed_out. Rappelez ; ne le traitez pas comme une erreur.
Attentes simultanées8Au-delà, l’outil répond immédiatement et le signale. Repli sur list_messages.
LecturesUne par seconde, par adresseBien au-delà de ce qu’une boucle d’appels d’outils demande. Une attente bloquante, c’est une requête, pas soixante.
Taille du message5 MBRefusé pendant la conversation SMTP, donc c’est l’expéditeur qui est prévenu, plutôt que l’agent qui attend quelque chose qui ne viendra jamais.
Rétention5 joursUne limite stricte, appliquée par une tâche automatisée. Tout ce que l’agent doit conserver, il doit l’écrire lui-même ailleurs.

Il n’existe ni endpoint d’envoi ni outil pour ça. Ce service ne fait que recevoir, ce qui empêche une boîte non authentifiée de devenir un relais de spam — un agent qui doit répondre à un humain a donc besoin d’une vraie boîte mail ailleurs.

Que faire quand un formulaire refuse les domaines publics ?

De nombreux services tiennent des listes de domaines de mail jetable, et les trois domaines publics d’ici y figurent. Pour un agent, cela se traduit par un formulaire qui rejette l’adresse qu’on venait de lui donner — ou pire, qui l’accepte et n’envoie jamais rien.

La réponse durable, c’est un domaine qui vous appartient. Un seul enregistrement MX transforme chaque adresse qui s’y trouve en boîte ici, il ne figure sur aucune liste puisqu’il n’est imprimé nulle part sur ce site, et les six mêmes outils fonctionnent dessus sans rien changer — seul create_inbox fait exception, puisqu’il invente des adresses sur les domaines publics. L’agent utilise simplement vous-choisissez@votre-domaine et appelle wait_for_message dessus.

Enregistrement MX pour votre domaine10 smtp.grabmail.io

Le guide complet se trouve ici — l’enregistrement, ce que sa publication prouve, et les limites d’une boîte sans mot de passe.

Que ne faut-il pas laisser un agent faire avec ceci ?

La partie honnête, et celle qui vous épargne un après-midi perdu :

  • Rien que vous auriez besoin de récupérer plus tard. Rien qui touche à l’argent, à l’identité ou au travail. La boîte redevient vide au bout de 5 jours et reste lisible par quiconque connaît l’adresse, donc une réinitialisation de mot de passe envoyée là l’an prochain n’atteint personne — ou quelqu’un d’autre.
  • Pas comme second facteur. Une boîte sans mot de passe n’est pas un facteur.
  • Pas pour quoi que ce soit de privé. Pas parce que nous le lisons, mais parce que l’adresse est le seul secret en jeu, et qu’un agent a fort bien pu l’écrire dans un journal, une transcription ou un message de commit.
  • Pas en volume. Un agent qui ouvre des comptes par centaines, c’est exactement le comportement que toute liste noire existe pour repérer, et c’est le moyen le plus rapide de faire refuser les domaines publics pour tout le monde.

Utilisé pour ce qu’il est — l’étape de confirmation qui sépare un agent de ce qu’on lui a réellement demandé de faire — il supprime le seul obstacle qui l’arrête à coup sûr.

Questions

Faut-il une clé API ou un compte ?

Non. Les domaines publics, les outils et un domaine personnel sont tous gratuits et sans authentification. Le seul cas qui exige une clé est un domaine fermé sur demande, qui attend alors un en-tête Authorization.

Avec quels clients cela fonctionne-t-il ?

N’importe quel client qui parle le Model Context Protocol — Claude Desktop, Claude Code, Cursor, Continue, l’OpenAI Agents SDK, et les autres. Le transport est Streamable HTTP, celui que les clients actuels utilisent par défaut, et trois versions du protocole sont acceptées, si bien qu’un client plus ancien se connecte quand même.

Pourquoi wait_for_message répond-il timed_out ?

Parce qu’une seule attente est plafonnée à 25 secondes, volontairement. Ce n’est pas une erreur et rien n’est perdu : rappelez l’outil. Le courrier met souvent plus de temps que ne le laisse penser la page qui l’a promis, et deux ou trois attentes de suite, c’est une inscription ordinaire.

L’agent peut-il utiliser mon propre domaine ?

Oui, et seule l’adresse change. Pointez un enregistrement MX vers smtp.grabmail.io et chaque adresse de ce domaine devient lisible avec les mêmes outils. Seul create_inbox est réservé aux domaines publics, puisque c’est lui qui invente un nom à votre place.

Un agent peut-il envoyer un e-mail avec ceci ?

Non. Il n’existe ni outil ni endpoint d’envoi, volontairement : un service sans authentification capable d’envoyer du courrier deviendrait un relais de spam en une journée. Notre SPF est v=spf1 -all et notre DMARC est p=reject, donc tout message prétendant venir d’une adresse d’ici est falsifié.

La boîte de réception est-elle privée ?

Non, et c’est la seule réserve à préciser explicitement à un agent. Sur un domaine public, quiconque connaît ou devine l’adresse peut la lire. Utilisez une adresse impossible à deviner, communiquez l’alias plutôt que l’adresse, et ne laissez jamais rien de privé s’en approcher.

Deux agents peuvent-ils attendre sur la même adresse en même temps ?

Oui, et les deux recevront le message à son arrivée. Ce qui est plafonné, c’est le nombre d’attentes en cours sur tout le service à la fois, 8 ; au-delà, l’outil répond immédiatement et le signale, et list_messages continue de fonctionner.

Combien de temps les messages restent-ils disponibles ?

5 jours à partir de l’arrivée, lu ou non, et aucun réglage ne permet de prolonger ce délai. Chaque message porte un champ expires_at, donc un agent n’a jamais à calculer cette date lui-même.

En quoi est-ce différent d’appeler l’API REST depuis un script ?

Pour un script, ce n’est pas différent, et l’API REST est mieux adaptée — le guide sur les tests de parcours de vérification couvre cette approche, délais et utilitaires compris. MCP sert au cas où personne n’a écrit la boucle : c’est le modèle qui décide d’ouvrir une boîte, et il a besoin que les outils soient détectables plutôt que documentés.

Essayez-le pendant que c'est encore frais

Une adresse s'obtient en un clic, sans compte et sans carte. Tout ce que contient ce guide fonctionne avec elle, immédiatement.

Bon retour

Vos boîtes et vos domaines, au même endroit.