oximail-smtp est la couche SMTP. Il possède le protocole de transport des deux côtés de la frontière du courrier : recevoir le courrier du monde extérieur sur le port 25, accepter le courrier authentifié du client d’un utilisateur sur le port 587, remettre le courrier en file vers les serveurs distants, générer des avis de non-remise quand la remise échoue, et fonctionner comme MX de secours pour un serveur principal indisponible. C’est le seul crate qui parle le SMTP brut. Tout ce qu’il accepte converge vers l’unique chemin d’ingestion de oximail-mail, et tout ce qu’il envoie sort de la file de remise persistante.
Vue d’ensemble
Un message atteint ce crate de deux manières, et ces deux manières sont des chemins de code volontairement distincts. Un serveur externe qui se connecte au port 25 pour remettre du courrier à un destinataire local exécuteprocess_inbound_data. Le client d’un utilisateur authentifié qui se connecte au port 587 pour envoyer du courrier exécute process_submission_data. Ce ne sont pas deux branches d’une même fonction avec un drapeau : ce sont deux méthodes distinctes avec des règles distinctes, parce que le port 25 (entrant) et le port 587 (soumission) sont des protocoles fondamentalement différents. Le courrier entrant n’est pas de confiance et doit être authentifié, scoré et scellé avant la remise. Le courrier de soumission est déjà authentifié et doit au contraire être validé contre les identités de l’utilisateur expéditeur avant d’être mis en file vers l’extérieur.
Le crate se situe au-dessus de oximail-store et oximail-mail, et dépend du crate maison oximail-auth pour chaque primitive d’authentification du courrier (DKIM, SPF, DMARC, ARC, MTA-STS, DANE, SRS). Le volet du spam lié à l’analyse de contenu est orchestré ici, mais vit dans le crate oximail-spam : ce crate décide vers où le verdict envoie le message, pas comment le message est scoré.
Chaque message accepté respecte l’ADR-017 : un courrier qui a reçu un 250 OK du SMTP est toujours remis quelque part (la boîte de réception du destinataire ou son dossier Indésirables) et jamais abandonné en silence. Rien d’accepté n’est retenu loin du destinataire : le palier de rétention en quarantaine un temps prévu par l’ADR-080 a été retiré, et un verdict dangereux est montré sur le message, jamais retenu.
Fonctionnalités
- Deux chemins de code séparés :
process_inbound_data(port 25) etprocess_submission_data(port 587), routés parprocess_dataselon que la session est une soumission authentifiée. L’entrant vérifie et score ; la soumission valide l’identité de l’expéditeur et met en file. - Pipeline d’authentification et anti-spam entrant : vérification DKIM / SPF / DMARC / ARC (via
oximail-auth), scellement ARC de la chaîne, un en-têteAuthentication-Results(RFC 8601), puis le pipeline anti-spam orchestré depuis le scoreuroximail-spam, puis la remise par le chemin d’ingestion. - Validation de la soumission : le
MAIL FROMd’enveloppe de l’utilisateur authentifié et l’en-têteFrom:du corps du message sont tous deux vérifiés contre les identités du compte (son adresse propre plus les alias JMAP). Toute divergence est refusée. Le serveur ne relaie pas un expéditeur falsifié, même pour un utilisateur authentifié. - Réponses de rejet avec une URL d’aide postmaster : chaque rejet synchrone et chaque avis de non-remise asynchrone porte une URL stable
https://oximail.ch/postmaster?p=<Reason>pour que le postmaster expéditeur puisse diagnostiquer lui-même. - File de remise persistante : une file sortante adossée à SQLite, avec réessais à backoff exponentiel et une fenêtre d’abandon RFC 5321, interrogée par un worker en arrière-plan qui résout le MX, signe en DKIM au moment de la remise et applique la politique de transport (MTA-STS / DANE).
- Génération de DSN (RFC 3464) : un avis de non-remise structuré vers l’expéditeur d’origine en cas d’échec permanent, d’échec de remise partielle ou d’expiration en file. Les diagnostics distants multilignes sont aplatis avant d’atteindre un champ d’en-tête du DSN, pour qu’une réponse distante verbeuse ne puisse jamais casser la génération de l’avis (le texte complet reste intact dans le corps lisible). La troisième partie porte par défaut les en-têtes d’origine ; là où le message lui-même ne peut pas être renvoyé (un message relayé, ou un message expiré dans la file, dont la voie d’expiration ne relit jamais le corps), c’est une partie
text/rfc822-headersqui porte le seulMessage-IDd’origine, pour qu’un traitement de rebonds puisse encore attribuer le rapport. Un expéditeur dont le domaine est signé ici mais reçoit son courrier ailleurs (un domaine d’envoi seul) reçoit son rebond comme les autres ; il était auparavant abandonné comme si le domaine était local. - Chemin MX de secours (ADR-052) : mode file (stocker-et-relayer, par défaut) ou mode proxy synchrone.
- SMTP AUTH : SASL
PLAINetLOGINsur le port de soumission, avec suivi par session des tentatives en force brute. - Extensions de transport : découpage
BDAT(RFC 3030),REQUIRETLS(RFC 8689) et réécriture d’enveloppeSRSlors du transfert. - Médiation des extensions au sortant : chaque saut sortant dérive ses exigences ESMTP du contenu du message (SMTPUTF8, 8BITMIME, SIZE) et les confronte aux capacités annoncées par la destination. Un écart impossible à combler produit un avis de non-remise permanent plutôt qu’un message remis mal encodé.
- Crochets de journalisation de conformité : le courrier entrant et sortant peut être copié en silence vers une boîte journal ou un archiveur externe selon des règles par tenant ; voir conformité. Désactivé par défaut.
Comment ça marche
Deux chemins, un point de routage
Chaque connexion TCP reçoit unSmtpSession qui suit la machine à états du protocole (Connected puis Greeted puis MailFrom puis RcptTo puis Data / Bdat) et indique si la connexion est arrivée sur un port de soumission. Quand DATA se termine, process_data prend l’unique décision qui sépare les deux mondes :
<CRLF>.<CRLF> (RFC 5321 §4.1.1.4) : une ligne à point après un LF nu ne peut plus glisser dans la première transaction une seconde, à l’enveloppe forgée. Sa limite de cinq minutes est une limite d’inactivité, réarmée par chaque commande et chaque lecture du corps, sous une durée de vie d’une heure. À l’arrêt du serveur, elle répond 421 4.3.2 à une session qui attend une commande, tandis qu’une transaction en cours se termine. La vue opérateur de ces règles est la session SMTP.
Le chemin entrant
process_inbound_data exécute, dans l’ordre :
- Contrôle de confiance (ADR-031). La boucle locale est toujours de confiance ;
[security] trusted_ipsétend l’ensemble. Un pair de confiance contourne SPF / DNSBL / rejet de politique DMARC, mais l’analyse de contenu reste active, car une application locale compromise peut quand même spammer. Un relais reconnu (un hôte publié comme MX de l’un des domaines de la box, autre que ce serveur, ADR-166) n’est pas un pair de confiance : son message est jugé sur l’adresse et l’EHLO du client lus dans la ligneReceived:la plus haute écrite par le secours, comme si ce client s’était connecté en direct (MX de secours). - Authentification.
oximail-authvérifie SPF, DKIM, DMARC et la chaîne ARC. La vérification DKIM est bornée, puisque n’importe quel pair non authentifié peut envoyer un message : 8 signatures au plus sont évaluées (les suivantes sont rapportées en un seulpermerrorqui dit leur nombre), le corps est canonicalisé une fois, et la passe entière dispose de 30 secondes, au-delà desquelles le message est évalué sans résultat DKIM et le journal le dit. DMARC juge l’auteur, lu avec la grammaire de la RFC 5322 §3.4 : l’unique boîte de l’unique champFrom:. Un nom affiché ou un commentaire ne peut plus cacher une seconde adresse (From: "x <x@attacker.example>" <ceo@victim.example>passait DMARC surattacker.examplependant que le client affichaitceo@victim.example), et une ligne d’en-tête hors grammaire ne transforme plus DMARC ennone. Un message sans exactement un auteur (pas deFrom:, plusieurs champs, plusieurs boîtes, unFrom:hors grammaire) est DMARCpermerrorsans requête DNS. Il est refusé avant le250, sur le chemin direct comme sur celui du MX de secours, par550 5.7.1et un texte fixe qui dit qu’il doit nommer exactement une boîte (RFC 5322 §3.6.2, RFC 7489 §6.6.1 ; motif postmasterAuthorAddress) ; les pairs de confiance en sont exemptés. L’exception ARC à un verdict DMARC en échec ne vaut que si le premier sceau de la chaîne (i=1) figure dans[spam] arc_trusted_sealers, vide par défaut (authentification du courrier). Une signature DKIM dont lel=laisse une partie du corps non signée est rapportéedkim=policy. Le crate scelle ensuite la chaîne ARC (RFC 8617) et ajoute en tête un en-têteAuthentication-Results(RFC 8601) pour que les consommateurs en aval voient le verdict sans relancer la vérification. L’ARC-Authentication-Resultsqu’il scelle sépare désormais ses méthodes par;comme l’exige la RFC 8601 ; sans ce séparateur, les vérificateurs, celui-ci compris, n’y lisaient nidkimnidmarc. - Pipeline anti-spam. Le pipeline scoré (orchestré ici, scoré dans
oximail-spam) renvoie une décision.Rejectproduit une réponse de rejet550;Deferun451; les verdicts remis (Junk/ suspect / en masse / propre) routent vers le placement de dossier et un tagX-Spam-Statusvia une unique fonction de disposition (ADR-080). SeulJunkest classé dans le dossier Indésirables ; les messages suspects et en masse sont remis dans la boîte de réception avec un tag et ne sont jamais marqués indésirables. - Remise. Chaque destinataire est remis par le chemin d’ingestion. Si l’ingestion échoue après l’acceptation du message, l’ADR-017 prend le relais : le message est tout de même remis (avec le mot-clé
$junk) plutôt qu’abandonné. Si tous les destinataires échouent, la réponse est un451pour que l’expéditeur réessaie ; un échec partiel génère un avis de non-remise pour les destinataires en échec.
Le scoring de contenu du spam n’est pas implémenté dans ce crate.
oximail-smtp construit le FilterContext, appelle le scoreur et agit sur la SpamDecision renvoyée : dossier, tag, rejet ou report. Le modèle de scoring lui-même (heuristiques, réputation, bayésien, analyse de contenu) vit dans oximail-spam. Cette page documente l’orchestration et les conséquences sur la remise, pas le scoring.Le chemin de soumission
process_submission_data exige une session authentifiée et ne fait aucune vérification d’authentification, aucun scoring anti-spam, aucun ARC et aucun Authentication-Results. Ce travail concerne le courrier entrant, pas le courrier que l’utilisateur envoie. Il impose à la place la légitimité de l’expéditeur deux fois :
- Le
MAIL FROMd’enveloppe doit correspondre à l’adresse du compte authentifié ou à l’une de ses identités JMAP (alias, sous-adresses). En cas d’erreur de recherche, le contrôle échoue en mode fermé (ADR-027) : un incident transitoire de base de données rejette plutôt que de relayer. - L’en-tête
From:du corps du message est vérifié contre le même ensemble d’identités. Un utilisateur authentifié qui passe le contrôle d’enveloppe peut encore falsifier unFrom:de corps ; ce second contrôle le refuse,550 5.7.1. Avant lui, la section d’en-têtes doit respecter la RFC 5322 §3.6 : un seulFrom:, au plus unSender:et unDate:, et unSender:quandFrom:nomme plusieurs boîtes ; sinon, ou quand aucunFrom:ne se lit, la réponse est554 5.6.0. La règle de cardinalité s’applique aussi aux comptes relais.
451 4.7.1, un état réversible que la file du client retente ; un domaine jamais prouvé est refusé 550 5.7.1. Le quota de destinataires par jour d’un compte relais diffère 452 4.7.1. Un compte désactivé est refusé 550 5.7.1 : une révocation décidée, pas un état à laisser passer.
Le serveur de soumission complète ensuite le message comme la RFC 6409 §8 le lui permet : un Date: ou un Message-ID: manquant est ajouté (le Message-ID reprend l’identifiant de l’entrée de file), et une ligne Received: du saut de soumission est ajoutée en tête, où un client IPv6 s’écrit [IPv6:…]. Un message relayé reçoit sa ligne Received: et rien d’autre.
Une soumission qui passe est stockée sous forme de blob (en clair depuis ADR-148 : le repos est l’affaire du volume, chiffrement au repos) puis mise en file pour la remise sortante ; tant que la garde de stockage est active, le RCPT est différé 452 4.3.1 plutôt qu’accepté sur un disque plein. La signature DKIM intervient plus tard, dans le worker sortant, au moment de la remise.
Quand le destinataire est local (un utilisateur écrit à un collègue sur le même serveur), le worker sortant remet sans saut réseau. Cette remise locale applique les règles de filtrage du destinataire et sa réponse automatique d’absence, exactement comme pour un message reçu de l’extérieur. L’ADR-117 grave la forme cible : un pipeline de remise par destinataire partagé, utilisé par chaque point d’entrée d’ingestion, pour qu’un chemin qui saute la politique du destinataire devienne irreprésentable.
Réponses de rejet et convention postmaster
Chaque rejet et chaque avis de non-remise porte une URL d’aide stable,https://oximail.ch/postmaster?p=<Reason>, sur le modèle du standard de fait du secteur (le support.google.com/mail/?p=<Reason> de Google). La valeur ?p= est un slug par motif, pas une référence par message. L’URL est donc stable et cachable, et correspond à une ancre nommée sur la page publique /postmaster. postmaster.rs est l’unique source de vérité pour les slugs ; la couche SMTP et la page d’aide la partagent.
Le code de statut étendu est choisi selon la raison du refus, pas par commodité :
Le rejet DMARC est honnête sur ce qu’il est :
5.7.26 (« plusieurs contrôles d’authentification ont échoué », RFC 7372) est une décision d’authentification, pas un score de contenu. C’est le code que Gmail et Microsoft renvoient pour un rejet DMARC. Le code précédent citait un motif de contenu arbitraire sous un 5.7.1, produisant un avis contradictoire. Les trois sites de rejet DMARC (pipeline scoré, MX de secours, repli sans pipeline) passent désormais par une unique fonction partagée smtp_dmarc_reject_reply pour rester synchronisés.
Remise sortante
Un message soumis ou relayé atterrit dans la file de remise SQLite. Un worker en arrière-plan interroge les entrées arrivées à échéance et remet chacune : il résout le MX de destination, applique la politique de transport (MTA-STS, RFC 8461 ; DANE, RFC 7672), signe le message en DKIM au moment de la remise et l’envoie sur une connexion TLS opportuniste ou imposée. Un motif MX de politique MTA-STS tel que*.example.com couvre exactement une étiquette, la plus à gauche (RFC 8461 §4.1) : la correspondance exige une étiquette non vide suivie du suffixe, comme le contrôle de nom de DANE. Elle vérifiait seulement que le MX finissait par le suffixe : un notexample.com enregistré par un attaquant, avec un certificat valide, satisfaisait une politique enforce. Un destinataire qui est une sous-adresse d’un compte local (nom+tag@domaine) est résolu comme le fait la porte d’arrivée (RFC 5233) et remis en local, au lieu de boucler par ce même serveur jusqu’à l’abandon.
Un échec temporaire planifie un réessai à backoff exponentiel (1 min puis 5 min puis 30 min puis 2 h puis 8 h puis 24 h). Un message qui ne peut pas être remis avant l’expiration de la fenêtre d’abandon (5 jours par défaut, selon la recommandation de la RFC 5321 §4.5.4.1, le même défaut que Postfix) génère un avis de non-remise RFC 3464 vers l’expéditeur d’origine et quitte la file.
Le saut de remise fait la médiation des extensions ESMTP au lieu de combler un écart en silence. Les exigences sont dérivées de manière déterministe du message lui-même, jamais d’un paramètre déclaré par l’émetteur : un octet non ASCII dans une adresse d’enveloppe ou dans la section d’en-têtes exige SMTPUTF8 (RFC 6531), un octet à bit haut dans le corps exige 8BITMIME (RFC 6152), et la longueur transmise est déclarée en SIZE= quand le pair l’annonce (RFC 1870). Les exigences supportées sont réémises vers l’aval ; une destination qui ne peut pas en satisfaire une reçoit un rejet permanent (550 5.6.7 / 554 5.6.3 / 552 5.3.4) plutôt qu’un message mal encodé. Cette médiation s’exécute au point de passage sortant unique : la remise MX directe et le chemin de relais se comportent à l’identique. Par la même exigence d’honnêteté, BINARYMIME n’est pas annoncé sur l’EHLO entrant (le client sortant travaille ligne par ligne et ne pourrait pas transporter du contenu binaire sans le corrompre), et un paramètre BODY=BINARYMIME est rejeté 555 5.5.4.
Le worker choisit son prochain message par deux lectures d’index, les entrées expirées d’abord (l’expiration la plus ancienne en tête), puis les ordinaires (la plus ancienne échéance en tête), au lieu de trier chaque entrée échue sous le verrou d’écriture qu’attendent les soumissions : mesuré à 50 000 entrées échues, un choix est passé de 163 ms à environ 0,01 ms.
Quand une remise locale réussit, la copie de l’expéditeur reçoit la même entrée deliveryStatus par destinataire qu’une remise distante (250, 2.0.0, deliveredAt). Quand un rapport arrive plus tard pour un destinataire qu’un serveur distant avait accepté en 250, l’entrée du destinataire est réécrite d’après l’Action du rapport (échec ou retard), avec son statut et son diagnostic, et son deliveredAt est retiré ; un rapport ne peut modifier qu’un destinataire déjà présent dans l’entrée, jamais en ajouter. Un message n’est traité comme rapport de remise que s’il arrive avec l’expéditeur d’enveloppe nul (RFC 3461 §6.2) : tout autre message qui en a la forme est remis comme un message ordinaire et ne change aucun statut, si bien qu’un co-destinataire ne peut pas faire échouer les autres destinataires en répondant par un rapport.
La signature DKIM au moment de la remise sursigne les en-têtes sur lesquels le lecteur agit : la liste h= de la signature nomme From, Reply-To, To, Cc, Subject, les deux en-têtes List-Unsubscribe et X-OxiMail-Flow une fois de plus, si bien qu’un acteur en aval ne peut pas en injecter une seconde copie sans casser la signature (RFC 6376 §8.15, rejeu par injection d’en-tête). Un message qui porte plus d’un champ From: n’est jamais signé ni envoyé : il échoue définitivement en 554 5.6.0, quel que soit le producteur qui l’a mis en file (un message brut importé par JMAP puis soumis compris). La clé est choisie par le domaine du From: comparé sous sa forme ASCII (A-label, RFC 8616), si bien qu’un domaine internationalisé est signé par la clé configurée pour lui. Un message qu’une règle d’utilisateur redirige vers l’extérieur n’est signé avec la clé d’un domaine hébergé que si ce serveur a authentifié son auteur (une soumission locale, un avis du serveur, ou un courrier externe qui a passé DMARC à l’entrée) ; sinon il part sans signature, si bien qu’un From: falsifié d’un domaine hébergé ne peut pas être blanchi par une redirection.
Le chemin MX de secours
Quand le serveur tourne avec[mode] role = "backup", le handler entrant branche au RCPT TO et au DATA vers l’un des deux modes (ADR-052) :
- Mode file (par défaut) : stocker-et-relayer. Le secours accepte le courrier avec un
250 OK, puis un worker de réessai le relaie vers le principal en arrière-plan. Si le principal refuse avec un5xx, un avis de non-remise part vers l’expéditeur d’origine. Conforme aux RFC, mais cela ouvre une fenêtre entre l’acceptation par l’expéditeur et l’avis, pendant laquelle un expéditeur falsifié peut considérer son spam comme remis. - Mode proxy (opt-in, ADR-052) : le secours relaie la session SMTP vers le principal en temps réel. MAIL FROM, RCPT TO, DATA, corps et réponses transitent tous de manière synchrone, si bien qu’un
5xxdu principal est propagé à l’expéditeur comme un5xx, sans backscatter ni avis différé. Si le principal est injoignable au début de la session, le secours bascule de façon transparente vers l’acceptation en file pour ce courrier.
Received: avant de relayer. Elle nomme l’EHLO du client, son adresse et l’usage de TLS (RFC 5321 §4.4). Le principal lit cette ligne pour juger le message sur le client que le secours a servi (ADR-166) : c’est le contrôle de confiance ci-dessus.
Invariants
- Ne jamais échouer en silence. Un message accepté (
250 OK) est toujours remis quelque part (ADR-017), et ce250ne part qu’une fois le journal d’écriture anticipée de la base forcé sur disque : il survit à une coupure de courant ([storage] durable_doors, RFC 5321 §6.1) ; un échec de remise permanent produit toujours un avis de non-remise vers l’expéditeur ; une erreur de recherche d’identité à la soumission échoue en mode fermé, pas ouvert. - Entrant et soumission sont des chemins séparés. La soumission valide le
MAIL FROMet leFrom:de corps contre les identités authentifiées ; l’entrant ne valide pas l’identité de l’expéditeur mais authentifie, score et scelle. Aucun chemin ne peut tomber dans l’autre. - Rien n’est accepté sur un disque plein. Tant que la garde de stockage est active (
[storage] min_free_percent), leRCPTd’une soumission est différé452 4.3.1plutôt qu’accepté (ADR-151) ; le contenu lui-même est stocké en clair depuis ADR-148. - Une réponse par motif. Chaque motif de rejet correspond à un code de statut étendu et à un slug d’aide postmaster, définis une seule fois dans
postmaster.rs.
Configuration
oximail-smtp ne lit aucun fichier de configuration directement ; le binaire résout les valeurs et construit le serveur. Les réglages côté opérateur qui façonnent la surface SMTP (les adresses et ports d’écoute entrant et soumission, le nom d’hôte utilisé dans Received: et SRS, les limites de débit, les ensembles [security] trusted_ips et [server] trusted_proxies, le bloc [mode] du MX de secours, et la surcharge de durée de vie maximale sortante) sont documentés dans la référence de configuration. Au repos, les blobs en file sont des fichiers en clair sur un volume que l’exploitant chiffre (ADR-148, pas du bout en bout) ; ce modèle est traité dans chiffrement au repos.
Écouteurs SMTP
oximail-smtp n’est pas un crate JMAP : il ne sert aucune méthode JMAP ni aucune route HTTP. Sa surface est le protocole SMTP sur ces écouteurs :
Le port de soumission gère SASL
PLAIN et LOGIN, STARTTLS, le découpage BDAT (RFC 3030) et REQUIRETLS (RFC 8689). La surface d’envoi côté JMAP (Email/send, EmailSubmission/set) vit dans oximail-mail ; ce crate implémente le contrat SubmissionSender que la file de remise remplit pour lui.
Décisions de conception
- ADR-017 (le courrier accepté doit être remis) : tout message ayant reçu un
250 OKfinit dans la boîte de réception ou les Indésirables, jamais retenu ; un échec d’ingestion remet avec$junkplutôt que d’abandonner. Le refus doit avoir lieu avant le250: la garde de stockage diffère auRCPT, jamais après l’acceptation. - ADR-052 (mode proxy du MX de secours) : le MX de secours tourne en mode file (stocker-et-relayer, relais en arrière-plan, avis différé sur
5xxdu principal) ou en mode proxy (proxy de session synchrone qui propage la réponse du principal sans backscatter). - ADR-049 (extension de la couverture MTA-STS) : la politique de sécurité du transport (MTA-STS, DANE) est honorée sur le chemin de relais du MX de secours, pas seulement sur le sortant direct.
- ADR-031 (politique de réseau de confiance) : la boucle locale et
[security] trusted_ipscontournent SPF / DNSBL / rejet DMARC, mais jamais le pipeline de contenu. Sa clause sur le greylist est remplacée par ADR-128, qui a retiré entièrement le greylisting au moment duRCPT(anti-spam). - ADR-080 (colonne vertébrale de disposition du spam) : une unique fonction de disposition mappe chaque verdict de spam remis vers le placement de dossier plus le tag
X-Spam-Status, si bien que les messages suspects et en masse sont remis dans la boîte de réception avec un tag et que seulJunkest classé Indésirables. - ADR-077 (modèle unifié de classification du spam) : un message vers un destinataire spamtrap est capturé comme corpus de spam de référence (remise forcée en
$junk) plutôt que rejeté ou reporté, pour que le piège collecte exactement le spam de masse qu’il existe pour étudier. - ADR-027 (audit de l’échec silencieux) : les contrôles d’identité de la soumission échouent en mode fermé en cas d’erreur de recherche ; un incident transitoire de base de données rejette l’envoi plutôt que de le relayer.
- ADR-076 (parser et auth restent AGPL, pas de crates.io) : les primitives d’authentification du courrier proviennent du crate maison AGPL
oximail-auth, une dépendance par chemin de l’espace de travail. - ADR-116 (relais smarthost sortant) : les routes de relais authentifiées, la rétention éphémère du relais, et l’amendement §11 de médiation des extensions décrit plus haut ; la vue opérateur est sur la page du relais sortant.
- ADR-117 (pipeline de remise locale unifié) : la localité est un détail de transport, pas une sémantique. Un destinataire local reçoit la même politique de destinataire (règles, absence, traces) qu’une remise externe. Les règles du destinataire s’appliquent déjà à la remise locale ; l’extraction du pipeline partagé complet est la forme cible gravée.
Standards
- RFC 5321 : Simple Mail Transfer Protocol. Le protocole de transport des chemins entrant et soumission, l’en-tête de trace
Received:(§4.4) et la recommandation sur la fenêtre d’abandon (§4.5.4.1). - RFC 7372 : codes de statut d’authentification du courrier. Le statut étendu
5.7.26utilisé pour un rejet DMARCp=reject(§3.3). - RFC 3464 : avis d’état de remise (DSN). L’avis structuré généré en cas d’échec de remise permanent ou partiel et d’expiration en file.
- RFC 8601 : en-tête
Authentication-Results, ajouté en tête du courrier entrant avec le verdict. - RFC 3030 :
BDAT/CHUNKINGpour la phase de données entrante. - RFC 8689 :
REQUIRETLS, propagé sur les enveloppes d’avis de non-remise et de sortie générée par Sieve, et réémis sur le fil sortant. - RFC 6531 (SMTPUTF8), RFC 6152 (8BITMIME), RFC 1870 (SIZE) : les extensions que la médiation sortante dérive du contenu du message et négocie par destination.
oximail-auth (qui aura sa propre page de référence) et consommées par oximail-smtp.
Carte des sources et tests
postmaster.rs porte un test qui vérifie que l’URL d’aide de chaque motif est bien formée et stable. Les fonctions de réponse de rejet portent des tests qui fixent le rejet DMARC à 5.7.26 et le rejet de contenu à 5.7.1, tous deux avec l’URL postmaster. La machine à états de session a son propre test de transitions.
Statut
Implémenté et en production en v0.30.0 : les deux chemins de code séparés entrant et soumission, le pipeline entrant complet d’authentification, scellement ARC, orchestration anti-spam et remise, la validation d’identité d’enveloppe et d’en-tête de la soumission, la file de remise persistante avec backoff et la fenêtre d’abandon RFC 5321, la génération de DSN RFC 3464, la convention de rejet avec URL d’aide postmaster, les deux modes du MX de secours (file et proxy, ADR-052), la médiation des extensions ESMTP au sortant, la sursignature DKIM de From/To/Subject, les règles du destinataire à la remise locale, et les crochets de journalisation de conformité par tenant. Le scoring de contenu du spam que le chemin entrant orchestre est implémenté dans le crateoximail-spam ; sur la build communautaire (AGPL), le scoreur exécute les signaux heuristiques et d’authentification, et la capture de corpus spamtrap (ADR-077) est active en production. Les primitives d’authentification du courrier sont fournies par le crate maison oximail-auth, qui aura sa propre page de référence.