Planifier des tests de charge mail : comparaison des outils pour des rafales de 10'000 e-mails sous Linux et Windows
Quiconque migre une passerelle ou dimensionne un environnement de messagerie a besoin de chiffres fiables plutôt que d’intuitions. Quels outils génèrent des rafales de plusieurs dizaines de milliers d’e-mails, à quoi ressemble un plan de test rigoureux et comment exploiter les résultats à partir des journaux.
La seule façon de vérifier si une nouvelle passerelle de messagerie supporte la charge de pointe d’un traitement nocturne de factures est d’effectuer un test de charge. Quiconque remplace une appliance, dimensionne un environnement Exchange ou prévoit l’envoi d’une newsletter via sa propre infrastructure a besoin au préalable de chiffres fiables : combien de messages par seconde le système accepte-t-il, comment la file d’attente se comporte-t-elle sous pression et à partir de quel point les reports commencent-ils ? Cet article compare les générateurs de charge courants sous Linux et Windows et montre comment planifier, exécuter et évaluer un test avec des rafales de plusieurs dizaines de milliers d’e-mails.
La règle la plus importante d’emblée : les tests de charge doivent être effectués exclusivement sur sa propre infrastructure ou dans un environnement de test explicitement autorisé à cet effet. Une rafale contre des systèmes tiers constitue une attaque, et un test utilisant des adresses d’expéditeur inventées contre des destinations de production génère du backscatter qui mène aux listes de blocage. Une architecture correcte se compose d’un générateur de charge, du système à tester et d’un puits contrôlé qui accepte puis rejette les e-mails.
Ce qu’un test de charge mail doit mesurer
Avant même de parler d’outil, il convient de se demander quelle mesure est réellement intéressante. En pratique, il y en a quatre, et elles exigent des configurations de test différentes :
- Taux d’acceptation : Combien de messages par seconde le premier saut accepte-t-il via SMTP ? C’est la mesure classique du débit et la valeur que les générateurs de charge fournissent directement.
- Latence de session : Combien de temps dure une transaction SMTP individuelle, de l’établissement de la connexion jusqu’au
250aprèsDATA? Sous charge, cette valeur augmente souvent bien avant que le taux d’acceptation ne s’effondre. - Latence de bout en bout : Combien de temps met un message entre son injection et sa livraison au puits, en passant par toutes les étapes intermédiaires ? C’est la mesure perçue par les utilisateurs.
- Comportement de la file d’attente : Jusqu’où la file d’attente augmente-t-elle durant la rafale et à quelle vitesse se vide-t-elle ensuite ? Une passerelle qui accepte 50’000 e-mails puis les traite pendant trois heures réussit le test d’acceptation, mais échoue malgré tout.
Un test qui ne mesure que le taux d’acceptation ne dit pas grand-chose d’un environnement à plusieurs niveaux avec passerelle, couche de chiffrement et serveur cible. C’est précisément dans ce cas que la vision de bout en bout est déterminante.
Le profil de charge détermine l’outil
Outre la mesure, une seconde question détermine le choix de l’outil et elle est souvent ignorée : quel comportement de connexion présente la charge à simuler ? Il faut distinguer deux profils de charge.
Un expéditeur en masse avec des sessions ouvertes correspond aux traitements de factures, aux décomptes de salaire et aux systèmes de newsletter : un seul système établit peu de connexions et y envoie des centaines à des milliers de messages d’affilée. La surcharge de connexion intervient une fois par session, et non une fois par message, et la passerelle voit peu de connexions avec beaucoup de transactions.
De nombreux injecteurs indépendants correspondent aux paysages applicatifs et au trafic des utilisateurs : de nombreux systèmes injectent chacun des messages individuels via leurs propres connexions. Ici, l’établissement de la connexion, y compris TLS et AUTH, fait partie de chaque message.
Pour dimensionner un envoi de masse, le premier profil de charge est pertinent et le générateur de charge doit donc pouvoir maintenir les sessions ouvertes : smtp-source le fait (de nombreux messages répartis sur peu de sessions), tout comme Postal et les scripts maison utilisant une connexion persistante. JMeter ne le peut pas ; les raisons sont expliquées dans la section Windows. Pour la charge de pointe d’un traitement de factures, ce critère de session est donc déterminant, et non la plateforme ; sous Windows, il faut alors passer par WSL.
Outils sous Linux
smtp-source et smtp-sink du paquet Postfix sont la référence pour la charge SMTP brute et sont disponibles sur pratiquement tout système où Postfix est installé. smtp-source génère des messages avec une taille, un parallélisme et un nombre configurables, tandis que smtp-sink est son pendant : un serveur SMTP qui accepte tout et rejette tout. Une rafale de 10’000 e-mails avec 50 sessions parallèles et des messages de 5 Ko tient sur une ligne :
time smtp-source -s 50 -m 10000 -l 5120 -c -f last@test.example -t senke@test.example gateway.test.example:25
Limites importantes : smtp-source ne mesure pas les percentiles de latence et les messages synthétiques sont uniformes. Il reste néanmoins le premier choix pour répondre à la question « quelle quantité le système accepte-t-il au maximum », car il génère des dizaines de milliers de messages par minute, même sur du matériel modeste, et le générateur ne devient pratiquement jamais le goulot d’étranglement.
Postal est la référence historique des benchmarks de serveurs de messagerie dédiés sous Linux. Il fait varier automatiquement l’expéditeur, le destinataire et la taille des messages, maintient un débit cible sur de longues périodes et écrit des statistiques par minute. Il est donc mieux adapté que smtp-source aux tests d’endurance, c’est-à-dire à une charge continue durant des heures. Le bhm associé (Black Hole Mailer) assure le rôle de puits. Postal est ancien, mais a été conçu précisément pour cela et figure dans les dépôts de paquets de la plupart des distributions.
swaks n’est pas un générateur de charge, mais il devrait faire partie de tout plan de test. Il exécute une transaction SMTP individuelle en donnant un contrôle complet sur chaque étape : authentification, STARTTLS, en-têtes arbitraires, pièces jointes. Avant chaque test de charge, un passage avec swaks doit servir de test fonctionnel afin que la rafale n’échoue pas à cause d’un mauvais destinataire ou d’un problème TLS, ce qui rendrait la mesure inutilisable. Dans une boucle avec xargs -P, swaks peut aussi être détourné en petit générateur de charge, mais la surcharge de processus est trop élevée pour des dizaines de milliers d’e-mails.
Les scripts maison en Python (smtplib, aiosmtplib) ou Go sont la solution lorsque le test doit utiliser des mélanges de messages réalistes : tailles variées, vraies pièces jointes, nombres de destinataires variables par transaction, cas d’erreur ciblés. L’effort est plus élevé, mais le script mesure exactement ce que l’environnement verra plus tard et peut consigner des horodatages par message pour l’analyse des latences.
Outils sous Windows
Apache JMeter est l’outil approprié sous Windows lorsque le profil de charge correspond à de nombreux injecteurs indépendants ou lorsque les percentiles, le mélange de messages et les rapports sont prioritaires. Le SMTP Sampler intégré prend en charge Auth, STARTTLS, les pièces jointes et les fichiers EML comme source de messages, et le mécanisme JMeter apporte ce qui manque aux outils Postfix : groupes de threads pour des profils de charge progressifs, percentiles de temps de réponse, taux d’erreur et rapports. Pour des rafales dépassant quelques milliers d’e-mails par minute, la règle habituelle de JMeter s’applique : utiliser l’interface graphique uniquement pour créer le plan de test et exécuter la mesure elle-même en mode CLI, faute de quoi on mesure l’interface.
Une limite du SMTP Sampler doit toutefois être connue : JMeter ne peut pas maintenir les sessions SMTP ouvertes. Chaque exécution d’échantillon ouvre une nouvelle connexion, parcourt le dialogue complet incluant le handshake TCP, EHLO, éventuellement STARTTLS et AUTH, envoie exactement un message puis ferme la connexion avec QUIT. Il ne peut pas reproduire plusieurs messages sur une même connexion ouverte, comme le font les expéditeurs en masse avec réutilisation de session ; smtp-source répartit en revanche de nombreux messages sur peu de sessions ouvertes. La raison tient à l’architecture : JMeter est un framework de test de charge multi-protocole, non un outil SMTP. Son modèle d’exécution traite chaque sampler comme une unité autonome et mesurée indépendamment, car c’est la seule manière d’assurer un fonctionnement uniforme des temporisateurs, assertions et évaluations par percentile pour tous les protocoles pris en charge. Le SMTP Sampler est donc une fine couche au-dessus de la bibliothèque JavaMail qui, en tant qu’API cliente, établit puis ferme une connexion pour chaque opération d’envoi ; la réutilisation d’une connexion entre plusieurs échantillons, telle que celle offerte par le HTTP Sampler avec Keep-Alive, n’a jamais été implémentée pour SMTP. En termes de mesure, cela signifie que JMeter génère le profil de charge de nombreux injecteurs individuels, non celui d’un expéditeur en masse avec session ouverte. Le débit mesuré inclut, pour chaque message, l’intégralité de la surcharge de connexion et de TLS, et les limites de connexion à la passerelle s’appliquent donc plus tôt qu’avec la réutilisation de session. Pour le profil de charge d’expéditeur en masse d’un traitement de factures, JMeter n’est donc pas le bon outil ; sous Windows, la solution WSL avec smtp-source est préférable.
PowerShell avec MailKit est la solution utilisant les moyens du bord. Microsoft indique lui-même que le Send-MailMessage auparavant courant est obsolète et recommande une migration ; MailKit peut être chargé via NuGet et parallélisé avec des runspaces depuis PowerShell 7. Cela permet en pratique d’atteindre quelques centaines à quelques milliers d’e-mails par minute, ce qui suffit aux tests fonctionnels et de régression, mais pas à la mesure de charge maximale. L’avantage : le script s’exécute sans installation supplémentaire sur tout poste de travail d’administration et peut écrire les résultats directement au format CSV pour l’analyse.
Microsoft Exchange Load Generator (LoadGen) a été pendant des années l’outil officiel pour charger des environnements Exchange avec des profils utilisateurs simulés (Outlook, ActiveSync, OWA). Microsoft ne l’a plus maintenu après Exchange 2013 et a retiré le téléchargement. LoadGen n’était de toute façon pas le bon outil pour de la charge SMTP pure ; quiconque souhaite aujourd’hui simuler une charge de boîtes aux lettres Exchange ne dispose d’aucun outil officiel et devrait plutôt tester le chemin SMTP directement.
WSL mérite son propre point : quiconque travaille sur une machine Windows mais a besoin d’outils Linux peut installer smtp-source et Postal dans une distribution WSL et disposer ainsi de l’ensemble des outils Linux sans VM de test séparée. Pour les charges discutées ici, le chemin réseau WSL ne constitue pas un goulot d’étranglement pertinent.
Comparaison
| Outil | Plateforme | Point fort | Limite |
|---|---|---|---|
| smtp-source / smtp-sink | Linux (Postfix) | Charge brute maximale avec un minimum d’effort, générateur et puits intégrés | Pas de percentiles de latence, messages uniformes |
| Postal / bhm | Linux | Charge continue avec débit cible, messages variés, statistiques par minute | Outillage vieillissant, analyse à construire soi-même |
| swaks | Linux, Windows (Perl) | Test individuel entièrement contrôlable, idéal comme vérification fonctionnelle avant la rafale | Pas un générateur de charge |
| JMeter (SMTP Sampler) | Windows, Linux (Java) | Profils de charge, percentiles, rapports, sources de messages EML | Surcharge Java, mode GUI inadapté aux débits élevés, une connexion par message (pas de réutilisation de session) |
| PowerShell + MailKit | Windows | Sans installation supplémentaire sur tout poste d’administration, sortie CSV | Débit limité, parallélisation à construire soi-même |
| Script maison (Python/Go) | les deux | Mélange de messages réaliste, points de mesure propres | Effort de développement, générateur à valider soi-même |
Le puits : où envoyer les e-mails
La moitié sous-estimée de la configuration de test est la destination. Trois variantes ont fait leurs preuves :
- smtp-sink ou
bhmcomme trou noir : accepte tout, rejette tout et mesure la chaîne de transport pure.smtp-sinkpeut, au besoin, générer artificiellement des retards de réponse et des codes d’erreur, permettant ainsi de tester le comportement du système testé face à une destination lente ou répondant avec des erreurs. - Postfix avec transport discard comme puits plus réaliste, lorsque la destination doit elle-même être un serveur SMTP complet avec mise en file d’attente.
- Quelques véritables boîtes aux lettres de contrôle en complément du puits, afin de vérifier ponctuellement que les messages arrivent intacts sur le plan du contenu, y compris au niveau du chiffrement ou de la signature.
Les outils dotés d’une interface web tels que Mailpit sont conçus pour le développement et deviennent rapidement eux-mêmes le goulot d’étranglement avec des dizaines de milliers d’e-mails. Ils ne conviennent pas comme puits pour un test de charge ; la mesure évaluerait l’outil d’analyse plutôt que le système testé.
Planifier le test
Un test fiable se déroule en trois étapes, chacune avec sa propre question :
- Référence : Une charge modérée et connue (environ 10 % de la pointe attendue) pendant quelques minutes. Elle fournit les valeurs de référence pour la latence et la consommation de ressources, et révèle les erreurs de configuration avant qu’elles ne disparaissent dans la mesure de rafale.
- Rafale : La mesure de charge de pointe proprement dite, par exemple 10’000 à 50’000 e-mails aussi rapidement que possible ou avec un débit cible défini. Plusieurs passages avec un parallélisme croissant indiquent où le taux d’acceptation plafonne et où la latence bascule.
- Endurance : La charge quotidienne attendue durant plusieurs heures. C’est seulement ici que se révèlent les fuites mémoire, les partitions de spool saturées, la rotation des journaux sous charge et les limites de connexion qu’une courte rafale n’atteint jamais.
Pour le mélange de messages, il faut être aussi réaliste que nécessaire. Une mesure composée exclusivement d’e-mails texte de 5 Ko surestime de plusieurs fois le débit d’un environnement dont le quotidien comprend des pièces jointes PDF. Un mélange issu de son propre parc est pertinent, par exemple 70 % de petits messages, 25 % avec une pièce jointe typique et 5 % de gros messages. TLS doit également faire partie du test si la production utilise TLS : le handshake coûte nettement plus par connexion que le transfert du message lui-même, et les générateurs qui ouvrent une nouvelle connexion par e-mail mesurent sinon principalement la terminaison TLS.
Pour l’analyse ultérieure, chaque message de test reçoit un marqueur unique, le plus simplement dans son propre en-tête tel que X-Loadtest-Id avec numéro d’exécution et horodatage, ainsi qu’une convention d’objet reconnaissable. Les exécutions de test peuvent ainsi être clairement séparées dans les journaux les unes des autres et du trafic restant, et les e-mails de test peuvent être supprimés de façon ciblée des quarantaines et journaux après l’exécution.
Trois points sont régulièrement oubliés lors de la planification : premièrement, les limitations de débit et le tarpitting sur le chemin de test ; une passerelle qui ralentit après 100 e-mails par minute et par IP source ne teste sinon que sa propre limitation (à exclure spécifiquement pour la mesure de charge maximale, à conserver délibérément pour le contrôle de réalisme). Deuxièmement, le DNS : si le système testé résout les domaines destinataires ou effectue des requêtes DNSBL pour chaque message, un résolveur doit faire partie de l’environnement de test, faute de quoi le test mesure le DNS amont. Troisièmement, le générateur lui-même : avant le premier passage contre le système cible, il faut exécuter le générateur directement contre le puits afin de démontrer qu’il peut effectivement produire le débit cible.
Évaluer les résultats
Les mesures du générateur de charge ne représentent que la moitié de la vérité, car elles montrent le point de vue de l’injecteur. L’autre moitié se trouve dans les journaux du système testé.
Sous Postfix, le journal de messagerie fournit pour chaque message les champs delay et delays, ce dernier étant ventilé entre le temps dans la file d’attente, l’établissement de la connexion et le transfert. Une analyse sur une exécution de test s’effectue avec les outils intégrés :
grep "status=sent" /var/log/mail.log |
grep -o "delay=[0-9.]*" | cut -d= -f2 | sort -n |
awk '{a[NR]=$1} END {print "n="NR, "p50="a[int(NR*0.5)], "p95="a[int(NR*0.95)], "p99="a[int(NR*0.99)], "max="a[NR]}'
Côté Exchange, le Message Tracking Log est la source centrale. Pour une exécution de test avec convention d’objet :
$p = @{
Start = "24.08.2026 14:00"
End = "24.08.2026 15:00"
MessageSubject = "LOADTEST"
ResultSize = "Unlimited"
}
Get-MessageTrackingLog @p | Group-Object EventId |
Sort-Object Count -Descending | Format-Table Name, Count
La différence entre les horodatages des événements RECEIVE et DELIVER du même MessageId donne la latence de bout en bout par message ; une fois exportée en CSV, elle permet de calculer la distribution des percentiles.
Trois principes sont essentiels pour l’interprétation. Premièrement : les percentiles plutôt que les moyennes. Une moyenne de deux secondes peut signifier que tout dure deux secondes, ou que 95 % des messages passent en une demi-seconde tandis que le reste reste bloqué dans la file d’attente ; p50, p95 et p99 distinguent ces cas. Deuxièmement : analyser les codes de réponse SMTP de manière croisée. La distribution des réponses 4xx dans le temps montre quand le système commence à ralentir, et la nature des codes (limite de connexion, protection de file d’attente, greylisting) indique quel mécanisme intervient en premier. Troisièmement : tracer la profondeur de la file d’attente dans le temps, sous Postfix avec qshape ou postqueue -j, sous Exchange avec Get-Queue à intervalles d’une minute. La surface sous cette courbe, et non le taux d’acceptation, détermine si l’environnement absorbe une rafale ou s’il ne fait que la stocker.
Les métriques système du système testé doivent être analysées en parallèle des journaux de messagerie : CPU, temps d’attente I/O sur la partition de spool, descripteurs de fichiers, compteurs de connexion. Dans les environnements à plusieurs niveaux, le constat le plus fréquent est que ce n’est pas le processus de messagerie qui limite, mais une étape d’inspection de contenu (antivirus, module de chiffrement, DLP) avec un nombre fixe de workers. Ce sont précisément de tels constats qui constituent la vraie valeur du test : ils identifient le paramètre à ajuster avant que la production ne le découvre.
Conclusion
Pour une mesure rapide de charge maximale sous Linux, smtp-source avec smtp-sink est incontournable ; Postal complète le cas de la charge continue. Sous Windows, JMeter fournit la mesure la plus complète, PowerShell avec MailKit couvre les tests fonctionnels et de régression, et WSL apporte au besoin les outils Linux sur le poste de travail d’administration. Plus important que l’outil est le plan : mesure séparée de l’acceptation, de la latence et du comportement de la file d’attente, mélange de messages réaliste, exécution de test marquée et analyse intégrant les percentiles et les journaux du système cible plutôt que le seul compteur du générateur.

Commentaires
Les commentaires sont chargés depuis GitHub / Giscus.