Skip to main content
Le courrier entrant sur le port 25 traverse un pipeline scoré avant d’atteindre la boîte de réception de quiconque. Cette page couvre le pipeline tel que la version communautaire (AGPL) le livre, les réglages qui l’ajustent, et la boucle de retour qui l’entraîne. Les conséquences d’un verdict sur la remise (quel dossier, quel tag, quelle réponse SMTP) sont décrites sur la couche SMTP ; cette page explique comment le verdict se forme.
La version communautaire score avec les signaux d’authentification, de réseau, d’heuristique et bayésiens. Des étages d’analyse de contenu plus avancés existent en extension commerciale et sont volontairement absents ici : les champs qu’ils rempliraient restent vides plutôt que d’être simulés.

Le pipeline, dans l’ordre

  1. Contrôle des pairs de confiance (ADR-031). La boucle locale et [security] trusted_ips sautent SPF, DNSBL et le rejet de politique DMARC, mais jamais l’analyse de contenu : une application locale compromise peut toujours spammer.
  2. Verdicts d’authentification. Les résultats SPF, DKIM, DMARC et ARC (issus de la passe de vérification entrante) alimentent le score. Un échec DMARC p=reject est rejeté d’emblée avec 550 5.7.26, avant le scoring de contenu : c’est une décision d’authentification, pas un score de spam.
  3. DNSBL. L’IP qui se connecte est vérifiée contre les listes de blocage que vous configurez ([spam] dnsbl_servers, vide par défaut). Un listage pèse dans le score.
  4. Signaux de contenu. Des heuristiques (chaînes de raccourcisseurs d’URL, falsification d’en-têtes, anomalies structurelles) et un classifieur bayésien entraîné par organisation. Deux garde-fous gardent le Bayes honnête : il s’entraîne exactement sur la représentation qu’il score (pas de dérive entraînement/scoring), et les votes dans sa zone morte statistique sont écartés plutôt que forcés en verdict.
  5. Disposition (ADR-080). Une fonction partagée unique traduit le verdict final en action : Reject vers 550 ; Defer vers 451 ; Junk vers le dossier Indésirables ; suspect et en masse vers la boîte de réception, avec un tag X-Spam-Status, jamais aux Indésirables. Seul un verdict confiant écarte du courrier de la vue.
Deux flux particuliers vivent à côté :
  • La liste blanche des réponses. Un correspondant à qui vous avez répondu est en liste blanche, mais elle n’est honorée que si l’enveloppe entrante est authentifiée (alignement SPF/DKIM) : un From: falsifié d’un contact connu n’y gagne rien.
  • La capture spamtrap (ADR-077). Le courrier vers un destinataire piège désigné est accepté et classé de force en $junk comme vérité terrain pour le corpus, plutôt que rejeté : le piège existe pour collecter exactement ce courrier.

Pas de greylisting

Il n’y a aucune étape de greylisting, et aucun réglage n’en active une. La barrière au moment du RCPT, qui refusait temporairement un triplet (IP, expéditeur, destinataire) inconnu par un 451 en attendant un réessai, a été retirée (ADR-128), parce que l’hypothèse sur laquelle elle reposait a cessé de tenir : les botnets modernes réessaient, les gros expéditeurs légitimes répondent depuis des pools d’adresses qui ne re-présentent jamais le même triplet, et le coût retombait précisément sur les correspondants que vous voulez le plus voir arriver, ceux qui vous écrivent pour la première fois. Cela impliquait aussi d’accepter une écriture en base avant toute authentification. L’exigence d’authentification et le pipeline scoré portent cette charge à la place. Si vous migrez depuis un serveur où le greylisting faisait un travail visible, les équivalents ici sont la pondération DNSBL, les verdicts d’authentification et le corpus bayésien, pas un interrupteur à réactiver.
Une variante conditionnée au score est spécifiée : ne retarder que dans la bande de score ambiguë, là où un réessai est une preuve plutôt qu’un péage. Elle n’est pas active dans cette version et n’est pas réglable par l’opérateur ; la seule chose qui tourne aujourd’hui est la tâche de ménage qui purge par âge l’ancienne table de triplets. Rien sur cette page n’en dépend.

Entraînement et retour

Le corpus Bayes apprend des actions des utilisateurs : déplacer un message vers les Indésirables l’entraîne comme spam, en repêcher un l’entraîne comme légitime (avec un plafond sur les votes légitimes répétés pour une même classe de message, pour qu’un utilisateur enthousiaste ne fausse pas le modèle). Le corpus est versionné par époque : quand la représentation des jetons change, le modèle est reconstruit depuis le corpus stocké au lieu de mélanger des générations incompatibles :
Pour demander au filtre ce qu’il pense maintenant, et non ce qu’il pensait à l’ingestion :
La commande score les messages les plus récents du compte (boîte de réception et Indésirables) contre le corpus courant, et affiche le verdict vivant à côté du score enregistré à l’ingestion. Elle n’écrit rien. La distinction est tout l’intérêt : les scores stockés sont figés à l’arrivée du message, donc après tout entraînement ou reconstruction ils décrivent un modèle qui n’existe plus, ce qui est précisément le moment où quelqu’un demande « ce message serait-il encore classé indésirable aujourd’hui ? ». Le réentraîneur horaire échoue bruyamment une fois plutôt que de journaliser une erreur toutes les heures pour toujours. Par l’API d’administration, /admin/v1/spam/stats, /spam/test, /spam/feedback/{tenant} et /spam/retrain/{tenant} exposent les mêmes opérations pour l’outillage. POST /spam/retrain/{tenant} lance un vrai réentraînement et renvoie son résultat (précision, échantillons utilisés, version du modèle) ; sans réentraîneur configuré (spam.retrain_enabled vaut false par défaut, aucune box n’embarque de script d’entraînement), la route répond 503 en nommant les deux réglages à changer, jamais un succès pour un travail qui n’a pas eu lieu.

Configuration

Les seuils ajustables à l’exécution se règlent en surcharges de configuration, sans redémarrage.

Anti-abus : limitation de débit et fail2ban

La protection contre la force brute et les inondations est dans le binaire ; n’installez pas le démon fail2ban à côté d’OxiMail :
  • Limiteur de débit : seau à jetons par IP ([rate_limit]), couvrant les surfaces HTTP et SMTP.
  • Fail2ban : les échecs d’authentification sur tous les protocoles (JMAP, IMAP, SMTP AUTH, DAV, ManageSieve) sont suivis par IP ; franchir [security] fail2ban_max_attempts bannit l’IP avec escalade (60 min puis 6 h puis 24 h). Derrière un proxy, la vraie IP cliente est lue depuis X-Forwarded-For (uniquement depuis [server] trusted_proxies) ou le protocole PROXY : les bannissements frappent l’attaquant, pas votre proxy.
  • Surface opérateur : oximail unban <ip>, oximail ban list|add, et GET/DELETE /admin/v1/bans : voir Exploitation.
[security] trusted_ips contourne les deux mécanismes pour votre propre infrastructure.

Lire le verdict sur un message

Chaque message scoré porte un en-tête X-Spam-Status avec le verdict et les signaux qui y ont contribué : le premier endroit où regarder quand un utilisateur demande « pourquoi ce message est aux Indésirables » (ou « pourquoi celui-ci n’y est pas »). La décision de remise produite est dans les journaux du serveur avec son contexte complet.