Tester les e-mails dans des tests automatisés
Vérifier inscriptions, réinitialisations de mot de passe et codes de confirmation dans des tests de bout en bout, avec de vraies boîtes et sans instabilité.
Par Umut TufanogluMis à jour le 20 octobre 20266 min de lecture
Inscription, réinitialisation du mot de passe, invitations, codes à deux facteurs : beaucoup de parcours importants d’une application passent par un e-mail. Pourtant, la plupart des tests de bout en bout s’arrêtent précisément là où l’e-mail part. Personne ne vérifie s’il arrive, si le lien pointe vers le bon environnement ou si le code figure dans le texte. Ce guide montre comment combler ce vide sans rendre tes tests instables.
Trois niveaux, trois outils
Tous les tests n’ont pas besoin d’une vraie boîte. Il est utile de les répartir par niveau :
| Niveau | Ce que tu vérifies | Outil typique |
|---|---|---|
| Tests unitaires et fonctionnels | Le bon message est-il déclenché avec les bonnes données ? | les faux mailers du framework, comme Mail::fake() dans Laravel |
| Développement local | À quoi ressemble le message, les liens fonctionnent-ils ? | un capteur SMTP local comme Mailpit |
| Bout en bout en staging et en CI | Le message arrive-t-il par le vrai circuit d’envoi ? | une vraie boîte avec une API |
Les deux premiers niveaux sont rapides et devraient représenter l’essentiel de tes tests. Une vraie boîte n’est nécessaire que pour les quelques tests qui couvrent tout le parcours.
Quand une vraie boîte est nécessaire
Les faux mailers vérifient seulement que ton application a voulu créer un message. Ce qui se passe ensuite reste invisible. Une vraie boîte détecte des erreurs comme celles-ci :
- L’environnement de staging utilise encore le mailer de log, et aucun message ne quitte le serveur.
- Le lien de confirmation pointe vers
localhostou vers la production au lieu du staging. - Le service d’envoi refuse les messages parce que le domaine de l’expéditeur n’est pas vérifié.
- Une erreur de template casse le code, qui n’apparaît plus dans le texte.
- La file d’attente qui envoie les e-mails ne tourne pas dans cet environnement.
Le schéma : créer, déclencher, attendre, lire, nettoyer
Presque tous les tests d’e-mail suivent les cinq mêmes étapes :
- Créer : le test crée une adresse neuve et unique.
- Déclencher : il remplit le formulaire de ton application avec cette adresse.
- Attendre : il attend l’arrivée du message, avec une limite fixe.
- Lire : il récupère le code ou le lien dans le message et l’utilise.
- Nettoyer : il supprime l’adresse.
Avec l’API de TossPost, cela donne ceci dans Playwright :
import { test, expect } from '@playwright/test';
const api = 'https://tosspost.com/api/v1';
const headers = {
Authorization: `Bearer ${process.env.TOSSPOST_TOKEN}`,
Accept: 'application/json',
};
test('l’inscription envoie un code de confirmation', async ({
page,
request,
}) => {
const created = await request.post(`${api}/mailboxes`, {
headers,
data: { lifetime: 10 },
});
const { data: inbox } = await created.json();
await page.goto('https://staging.example.com/inscription');
await page.getByLabel('E-mail').fill(inbox.address);
await page.getByRole('button', { name: 'S’inscrire' }).click();
const waited = await request.get(
`${api}/mailboxes/${inbox.id}/messages/wait?timeout=30&since=${encodeURIComponent(inbox.created_at)}`,
{ headers, timeout: 35_000 },
);
expect(waited.status()).toBe(200);
const { data: message } = await waited.json();
await page.getByLabel('Code').fill(message.verification_code);
await request.delete(`${api}/mailboxes/${inbox.id}`, { headers });
});
Attendre plutôt que dormir
La cause la plus fréquente des tests d’e-mail instables est un sleep(5000) fixe. Parfois il ne suffit pas, parfois il fait perdre du temps. Une requête qui reste ouverte exactement jusqu’à l’arrivée du message fonctionne mieux.
Le endpoint messages/wait fait cela : il garde la requête ouverte jusqu’à 30 secondes et répond avec 200 et le message dès qu’il arrive. Si rien n’arrive pendant ce temps, il répond avec 204. Le test échoue alors avec un message clair, au lieu de trébucher plus loin.
Attention au paramètre since. Sans lui, seul compte ce qui arrive après le début de la requête d’attente. Si ton application est plus rapide que le test, le message serait déjà là et passerait inaperçu. Passe comme since le moment de création de la boîte (created_at), et aucun message ne t’échappera. Comme cette heure vient du serveur, une horloge déréglée sur la machine de CI ne pose pas non plus de problème.
Lire les codes et les liens
Chaque message contient les champs verification_code et verification_url. TossPost détecte les codes et liens de confirmation dans le texte dès la réception, tu n’as donc pas à maintenir tes propres expressions régulières. Si tu as besoin de plus, par exemple pour vérifier un en-tête précis ou la structure HTML, charge le message complet via messages/{id} ou l’original via messages/{id}/raw.
Tester en parallèle
Ne partage jamais une adresse entre plusieurs tests. Si deux tests tournent en même temps, l’un lirait le code de l’autre. Chaque test crée sa propre boîte ; cela coûte une seule requête.
Les requêtes en attente sont limitées par compte, car chacune garde une connexion ouverte. Avec beaucoup de tests en parallèle, l’API répond 429 dès que tous les créneaux sont occupés. Pour les grandes suites de tests, les webhooks conviennent mieux : TossPost appelle une URL de ton choix à chaque nouveau message, signée avec un HMAC-SHA256 que tu vérifies avant de la traiter.
Conseils pour des tests d’e-mail stables
- Stocke le token comme secret : garde le token de l’API dans les secrets de ta CI, jamais dans le dépôt.
- Limite les droits : donne au token uniquement les droits dont le test a besoin, comme créer des boîtes et lire les messages.
- Choisis une courte durée de vie : une boîte qui expire au bout de dix minutes se nettoie toute seule si le test s’interrompt.
- Des délais clairs : règle le timeout du client HTTP quelques secondes au-dessus de la limite d’attente, pour que l’API réponde en premier.
- Seulement les parcours clés : teste de bout en bout l’inscription, la réinitialisation du mot de passe et les invitations. Les niveaux plus rapides couvrent tout le reste.
Pour commencer
Pour utiliser l’API, il te faut un compte TossPost. Crée un token dans Réglages → API ; la documentation de l’API décrit tous les endpoints, les webhooks et la vérification de la signature.
Ouvre la documentation de l’API : avec des exemples pour curl et Playwright.
Écrit par Umut Tufanoglu, qui développe et gère TossPost. À propos de TossPost