Coulisses

12 ans de défi-réponse : ce que j'ai appris à coder un anti-spam tout seul

En 2014, mon mail était devenu invivable. J'ai codé FrozenSpam un week-end. Douze ans plus tard, il tourne toujours. Voici la vraie histoire — celle qui n'apparaît pas dans la page « à propos ».

Publié le 23 mai 2026 par Emmanuel Daunizeau · 12 min de lecture

Le déclencheur

Été 2014. Je dirigeais deux sociétés IT en parallèle. Tous mes mails arrivaient sur un Windows Server avec SmarterMail. Le filtre anti-spam natif était dépassé : je recevais 200 spams par jour, et surtout, je perdais des mails clients dans le dossier spam.

Un dimanche soir, j'ai vu un brief client important qui datait de jeudi, retrouvé par hasard. J'avais perdu trois jours et failli perdre le projet. C'est devenu personnel. Lundi matin, j'ai ouvert Visual DialogScript (le langage que j'avais co-créé avec Julian Moss en 1993, toujours mon outil de prédilection pour les hooks Windows) et j'ai commencé à coder.

L'idée initiale

Le défi-réponse existait depuis le début des années 2000 (TMDA, Spamarrest...). À l'époque, c'était jugé « lourd » par la communauté. Mais j'avais lu Brad Templeton (son essai sur les principes du C/R) et j'étais convaincu que bien implémenté, c'était la seule technique avec un taux de faux positif structurellement nul.

« Bien implémenté », ça voulait dire :

  • Un défi par expéditeur, UNE seule fois dans la vie
  • Pas de défi sur les domaines whitelistés (newsletters, partenaires)
  • Pas de défi sur les `noreply@`, `bounce@`, `mailer-daemon@`
  • Pas de défi sur les SPF/DMARC ratés (backscatter guard)
  • Pas de défi sur les gens à qui J'AI écrit — l'idée centrale qui n'existait nulle part ailleurs

Le premier piège : le backscatter

La première version, sortie en septembre 2014, envoyait un défi à chaque expéditeur inconnu. Erreur. Un spammeur usurpait l'adresse comptable@grosseboite.fr. Mon défi partait à la vraie comptable. Qui recevait mes défis pour des mails qu'elle n'avait pas envoyés. Backscatter.

Trois semaines après mise en service, j'ai reçu un mail furieux de la DSI d'une banque cliente : leur antispam avait blacklisté mon domaine pour cause de backscatter. J'ai dû faire un appel humble, expliquer, et corriger le bug en 48 h.

La correction : vérifier SPF + DMARC du domaine de l'expéditeur AVANT d'envoyer un défi. Si l'authentification est ratée, drop silencieux. Pas de défi. C'est devenu la « couche 4 » de FrozenSpam (le backscatter guard).

Le deuxième piège : les fils de discussion

Décembre 2014. Je me rends compte qu'un partenaire commercial ne reçoit pas mes réponses. Pourquoi ? Parce que quand je lui répondais à un mail, mon serveur SmarterMail envoyait via un autre flux que ce que FrozenSpam observait. FrozenSpam ne savait pas que j'avais écrit. Donc quand le partenaire répondait, FrozenSpam lui envoyait un défi. Le partenaire le ratait dans son spam folder.

J'ai donc dû hooker l'envoi sortant de SmarterMail dans FrozenSpam, pour alimenter une table outbound_log en temps réel. Toute personne à qui j'ai écrit dans les 90 derniers jours est automatiquement whitelistée. C'est l'auto-whitelist sortants, qui est devenue la marque de fabrique de FrozenSpam.

Personne d'autre ne le fait correctement. Détails techniques dans cet article.

Le troisième piège : la libération en masse

Quand un défi est validé, que se passe-t-il avec les mails qui sont arrivés depuis du même expéditeur ? Dans la première version, je libérais juste le mail qui avait déclenché le défi. Mauvaise idée : un client m'a écrit 4 mails en rafale (urgence chantier), j'ai répondu au défi du premier, et n'ai vu les 3 autres que 30 jours plus tard à la purge de quarantaine.

La correction : libération en masse. À la validation d'un défi, je libère TOUS les mails en quarantaine du même expéditeur. Évident en rétrospective. Ça m'a pris deux mois à comprendre.

Le pivot 2026 : SaaS multi-tenant

Pendant 11 ans (2014-2025), FrozenSpam était mon outil personnel + celui de quelques admins SmarterMail à qui je l'avais filé. Il tournait sur mes propres machines, avec mon code Visual DialogScript, jamais commercialisé.

En 2025, deux choses ont changé :

  1. Le spam a réexplosé (cf cet article) — les LLM ont rendu le spam rentable à nouveau.
  2. J'ai pris assez de recul pour me dire : ce que j'ai construit pour moi-même n'est pas une lubie privée. Ça résout un vrai problème pour des milliers de TPE/PME françaises qui se débattent avec MailInBlack à devis ou Gmail Workspace qui ne suit plus.

J'ai donc porté le moteur en Python sur Linux, avec isolation multi-tenant en PostgreSQL. Le code historique en VDS sur Windows me sert toujours de référence — il tourne sur mes domaines perso et continue à bloquer mes spams.

Ce que je referais pareil

  • Coder seul, lentement, sur 12 ans — ça donne un produit qui tient.
  • Le défi-réponse combiné à du SPF/DMARC + auto-WL sortants + DNSBL — pas pris isolément.
  • Refuser d'analyser le contenu des mails. Trop de violations symboliques pour un anti-spam.
  • Garder le pouvoir de dire non aux features non demandées. FrozenSpam fait UNE chose et la fait bien.

Ce que je ferais différemment

  • Démarrer en Linux dès 2014 (j'ai perdu beaucoup à dépendre du combo Windows Server + SmarterMail closed-source).
  • Documenter publiquement plus tôt. L'effet réseau aurait été énorme.
  • Ne pas attendre 2026 pour porter en SaaS. J'ai laissé MailInBlack prendre tout le marché français pendant 10 ans en restant dans mon coin.

FrozenSpam est aujourd'hui disponible publiquement. 12 ans de production sur mes domaines, près d'un million de spams bloqués, zéro faux positif. Démarrez pour 1 €, remboursable sous 15 jours.