> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oximail.ch/llms.txt
> Use this file to discover all available pages before exploring further.

# oximail-smtp

> La couche SMTP : chemins de code séparés pour le courrier entrant (port 25) et la soumission authentifiée (port 587), le pipeline d'authentification et anti-spam entrant, la file de remise sortante, la génération de DSN et le chemin MX de secours.

`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](./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écute `process_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](./oximail-store) et [oximail-mail](./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, le dossier Indésirables ou la quarantaine) et jamais abandonné en silence.

## Fonctionnalités

* **Deux chemins de code séparés** : `process_inbound_data` (port 25) et `process_submission_data` (port 587), routés par `process_data` selon 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ête `Authentication-Results` (RFC 8601), puis le pipeline anti-spam orchestré depuis le scoreur `oximail-spam`, puis la remise par le chemin d'ingestion.
* **Validation de la soumission** : le `MAIL FROM` d'enveloppe de l'utilisateur authentifié *et* l'en-tête `From:` 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).
* **Chemin MX de secours** (ADR-052) : mode file (stocker-et-relayer, par défaut) ou mode proxy synchrone.
* **SMTP AUTH** : SASL `PLAIN` et `LOGIN` sur 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'enveloppe `SRS` lors 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é](../operator/compliance). Désactivé par défaut.

## Comment ça marche

### Deux chemins, un point de routage

Chaque connexion TCP reçoit un `SmtpSession` 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 :

```text theme={null}
si session.is_submission && session.authenticated.is_some()
    → process_submission_data   (port 587)
sinon
    → process_inbound_data      (port 25)
```

Les deux handlers ne partagent rien d'autre que les octets bruts. C'est une règle de conception ferme, pas un détail d'implémentation : une soumission authentifiée ne doit jamais tomber par accident dans le pipeline anti-spam entrant, et le courrier entrant non fiable ne doit jamais atteindre la file sortante.

### Le chemin entrant

`process_inbound_data` exécute, dans l'ordre :

1. **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.
2. **Authentification.** `oximail-auth` vérifie SPF, DKIM, DMARC et la chaîne ARC. Le crate scelle ensuite la chaîne ARC (RFC 8617) et ajoute en tête un en-tête `Authentication-Results` (RFC 8601) pour que les consommateurs en aval voient le verdict sans relancer la vérification.
3. **Pipeline anti-spam.** Le pipeline scoré (orchestré ici, scoré dans `oximail-spam`) renvoie une décision. `Reject` produit une réponse de rejet `550` ; `Defer` un `451` ; les verdicts remis (`Junk` / suspect / en masse / propre) routent vers le placement de dossier et un tag `X-Spam-Status` via une unique fonction de disposition (ADR-080). Seul `Junk` est 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.
4. **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 un `451` pour que l'expéditeur réessaie ; un échec *partiel* génère un avis de non-remise pour les destinataires en échec.

<Note>
  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.
</Note>

### 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 FROM` d'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 un `From:` de corps ; ce second contrôle le refuse.

Une soumission qui passe est stockée sous forme de blob chiffré par tenant (ADR-020 : si la clé du tenant est indisponible, la soumission est rejetée avec un `451`, jamais stockée en clair) puis mise en file pour la remise sortante. 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. Depuis #693, 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é :

| Motif                                               | Réponse | Statut étendu | Standard      |
| --------------------------------------------------- | ------- | ------------- | ------------- |
| DMARC `p=reject` (alignement SPF + DKIM en échec)   | `550`   | `5.7.26`      | RFC 7372 §3.3 |
| Refusé par le pipeline de contenu anti-spam         | `550`   | `5.7.1`       | RFC 5321      |
| La boîte du destinataire n'existe pas               | `550`   | `5.1.1`       | RFC 5321      |
| Le MX de secours ne relaie pas pour ce domaine      | `550`   | `5.1.1`       | RFC 5321      |
| Échec de remise permanent (retourné à l'expéditeur) | DSN     |               | RFC 3464      |

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 é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](../operator/outbound-relay) 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`.

La signature DKIM au moment de la remise **sursigne** les en-têtes critiques pour l'affichage : la liste `h=` de la signature nomme `From`, `To` et `Subject` une fois de plus, si bien qu'un acteur en aval ne peut pas injecter un second `From:`/`To:`/`Subject:` sans casser la signature (RFC 6376 §8.15, rejeu par injection d'en-tête).

### 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 un `5xx`, 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 `5xx` du principal est propagé à l'expéditeur comme un `5xx`, 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.

### Invariants

* **Ne jamais échouer en silence.** Un message accepté (`250 OK`) est toujours remis quelque part (ADR-017) ; 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 FROM` et le `From:` 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.
* **Aucun blob en clair.** Une soumission dont la clé de chiffrement du tenant est indisponible est rejetée avec un `451`, jamais stockée en clair (ADR-020).
* **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](../operator/configuration). Le modèle de chiffrement au repos derrière les blobs en file (le schéma de type LUKS, pas le bout en bout) est traité dans [chiffrement au repos](../operator/encryption-at-rest).

## É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 :

| Écouteur      | Port | Chemin                    | Rôle                                                                                                                                                                                                         |
| ------------- | ---- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| MX entrant    | 25   | `process_inbound_data`    | Recevoir le courrier des serveurs externes pour les destinataires locaux. Vérifie SPF / DKIM / DMARC / ARC, exécute le pipeline anti-spam, remet par l'ingestion. Aucune validation d'identité d'expéditeur. |
| Soumission    | 587  | `process_submission_data` | Accepter le courrier authentifié du client d'un utilisateur. Exige SMTP AUTH ; valide le `MAIL FROM` et le `From:` de corps contre les identités du compte ; met en file pour la remise sortante.            |
| MX de secours | 25   | branche secours (ADR-052) | Quand `role = "backup"` : stocker-et-relayer (file) ou proxy synchrone vers le principal.                                                                                                                    |

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](./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 OK` finit dans la boîte de réception, les Indésirables ou la quarantaine ; un échec d'ingestion remet avec `$junk` plutôt que d'abandonner. Pour l'entrant, l'ADR-017 l'emporte sur le chiffrement (remise avec `$junk`) ; pour la soumission sortante, le chiffrement l'emporte (rejet `451` avant tout `250 OK`).
* **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 `5xx` du 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_ips` contournent 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 du `RCPT` ([anti-spam](../operator/anti-spam#pas-de-greylisting)).
* **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 seul `Junk` est 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](../operator/outbound-relay).
* **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.

Les ADR vivent dans le dépôt du serveur OxiMail ; voir l'[index des ADR](../reference/adr-index).

## Standards

* [RFC 5321](https://www.rfc-editor.org/rfc/rfc5321) : 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](https://www.rfc-editor.org/rfc/rfc7372) : codes de statut d'authentification du courrier. Le statut étendu `5.7.26` utilisé pour un rejet DMARC `p=reject` (§3.3).
* [RFC 3464](https://www.rfc-editor.org/rfc/rfc3464) : 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](https://www.rfc-editor.org/rfc/rfc8601) : en-tête `Authentication-Results`, ajouté en tête du courrier entrant avec le verdict.
* [RFC 3030](https://www.rfc-editor.org/rfc/rfc3030) : `BDAT` / `CHUNKING` pour la phase de données entrante.
* [RFC 8689](https://www.rfc-editor.org/rfc/rfc8689) : `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](https://www.rfc-editor.org/rfc/rfc6531) (SMTPUTF8), [RFC 6152](https://www.rfc-editor.org/rfc/rfc6152) (8BITMIME), [RFC 1870](https://www.rfc-editor.org/rfc/rfc1870) (SIZE) : les extensions que la médiation sortante dérive du contenu du message et négocie par destination.

Les RFC d'authentification du courrier elles-mêmes ([RFC 6376](https://www.rfc-editor.org/rfc/rfc6376) DKIM, [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208) SPF, [RFC 7489](https://www.rfc-editor.org/rfc/rfc7489) DMARC, [RFC 8617](https://www.rfc-editor.org/rfc/rfc8617) ARC, [RFC 8461](https://www.rfc-editor.org/rfc/rfc8461) MTA-STS, [RFC 7672](https://www.rfc-editor.org/rfc/rfc7672) DANE) sont implémentées dans le crate maison `oximail-auth` (qui aura sa propre page de référence) et consommées par `oximail-smtp`.

## Carte des sources et tests

| Fichier (dans le crate)                                                                              | Contenu                                                                                                                                                                                                                                                     |
| ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `src/inbound.rs`                                                                                     | Le `SmtpServer`, la boucle de commandes, `process_data` (la séparation des chemins), `process_inbound_data`, `process_submission_data`, `deliver_to_recipient`, et les fonctions de réponse de rejet (`smtp_dmarc_reject_reply`, `smtp_spam_reject_reply`). |
| `src/session.rs`                                                                                     | `SmtpSession` et la machine à états `SessionState`.                                                                                                                                                                                                         |
| `src/auth.rs`                                                                                        | L'enveloppe de vérification `oximail-auth` (`AuthResolver`, `verify_message`, `should_reject`, `should_flag_junk`).                                                                                                                                         |
| `src/outbound.rs`                                                                                    | Le worker sortant : résolution MX, politique de transport, signature DKIM à la remise, TLS.                                                                                                                                                                 |
| `src/queue.rs`                                                                                       | `DeliveryQueue` : la file sortante persistante, le backoff de réessai et la fenêtre d'abandon.                                                                                                                                                              |
| `src/dsn.rs`                                                                                         | La génération d'avis de non-remise RFC 3464.                                                                                                                                                                                                                |
| `src/postmaster.rs`                                                                                  | `PostmasterReason` : l'unique source de vérité pour les slugs de rejet `?p=` et les URL d'aide.                                                                                                                                                             |
| `src/backup.rs`, `src/backup_proxy.rs`                                                               | Le mode file et le mode proxy synchrone du MX de secours (ADR-052).                                                                                                                                                                                         |
| `src/srs.rs`                                                                                         | La réécriture d'enveloppe SRS lors du transfert.                                                                                                                                                                                                            |
| `src/mta_sts.rs`, `src/dane.rs`                                                                      | Les contrôles de politique de transport sortante (consomment les primitives `oximail-auth`).                                                                                                                                                                |
| `src/bayes.rs`, `src/spam_store.rs`                                                                  | Le stockage local du corpus de spam que le scoreur lit.                                                                                                                                                                                                     |
| `src/header_mutate.rs`, `src/sanitize.rs`, `src/transport.rs`, `src/rate_limit.rs`, `src/trusted.rs` | Mutation d'en-têtes, assainissement du contenu, helpers de transport, limitation de débit et ensemble des pairs de confiance.                                                                                                                               |

`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 crate `oximail-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.
