---
title: "Délivrabilité"
weight: 70
description: "SPF, DKIM, DMARC, munging de l'en-tête From, rebonds, plaintes FBL et pools d'envoi."
---

# Délivrabilité

La délivrabilité est le résultat d'une chaîne : authentification entrante,
réécriture conditionnelle des en-têtes, signature sortante, gestion des rebonds et
des plaintes, et isolation de la réputation. difuzio assure la part applicative ;
Postfix et les milters frontaux assurent le reste (voir
[Installation, section 7](/difuzio/admin/installation)).

## Authentification entrante

difuzio ne calcule pas SPF/DKIM/DMARC lui-même : il lit les en-têtes
`Authentication-Results` posés par les milters frontaux de confiance. Seuls les
en-têtes dont l'authserv-id correspond à celui de l'instance sont pris en compte ;
les autres sont ignorés comme potentiellement falsifiés. C'est pourquoi les
milters frontaux DOIVENT supprimer tout `Authentication-Results` préexistant à
notre authserv-id à l'entrée (anti-forge).

Les verdicts SPF, DKIM, DMARC et la politique DMARC de l'auteur sont enregistrés
sur le message ; ils alimentent les décisions du pipeline (rétention, munging).

## Signature DKIM de l'auteur

Une signature DKIM ne survit que si le message n'est pas modifié : le moindre
octet réécrit dans le corps, et même un simple réencodage des en-têtes, la rend
invalide.

difuzio en tient compte et distingue deux chemins :

- **la liste ne réécrit rien** (pas d'étiquette de sujet, pas de pied de page,
  pas de munging) : le message est transmis octet pour octet. Seuls les en-têtes
  que difuzio possède sont posés (les `List-*`, `Precedence`, `Feedback-ID`) et
  les en-têtes de transport de l'entrée sont retirés. La signature de l'auteur
  reste donc valide, et avec elle son alignement DMARC. C'est le comportement à
  privilégier pour la délivrabilité ;
- **la liste réécrit le message** : la signature de l'auteur est de toute façon
  cassée, difuzio la retire alors purement et simplement, avec
  l'`Authentication-Results` d'entrée. Laisser une signature morte est pire que
  ne pas en avoir : les destinataires la comptabilisent en `dkim=fail`.

Concrètement, activer une étiquette de sujet ou un pied de page sur une liste
sacrifie la signature de l'auteur. Ce n'est pas grave si le domaine de la liste
signe lui-même ses envois en frontal (voir plus bas) ; ce l'est si personne ne
signe.

Dans tous les cas, difuzio ne signe pas lui-même : la signature du domaine de la
liste est apposée par le MTA frontal, et elle est indispensable pour que le
désabonnement en un clic soit honoré par les grandes messageries (RFC 8058).

## Réécriture de l'en-tête From (munging)

Quand le domaine de l'auteur publie une politique DMARC stricte, relayer le
message tel quel le ferait rejeter par les destinataires (le From ne s'aligne plus
après passage par la liste). difuzio réécrit alors l'en-tête From au nom de la
liste et retire la signature DKIM de l'auteur (devenue invalide). Le comportement
est piloté par la politique `from_munging` de la liste :

- `auto` : munging seulement quand le domaine auteur est en DMARC strict
  (recommandé) ;
- `always` : munging systématique ;
- `never` : jamais.

Un échec DMARC entrant sur un domaine auteur en `p=reject`, pour une liste `open`
ou `members`, met le post en attente de modération (raison `dmarc_inbound`, voir
[Modération](/difuzio/admin/moderation)).

## Désabonnement en un clic (one-click)

Chaque message de liste sortant porte les en-têtes :

    List-Unsubscribe: <https://.../p/unsubscribe-oneclick?t=...>, <mailto:...>
    List-Unsubscribe-Post: List-Unsubscribe=One-Click

conformément à la RFC 8058. Le lien HTTPS pointe vers `POST /p/unsubscribe-oneclick`
(sans authentification ni CSRF, le token VERP fait foi). Cet endpoint doit être
exclu de tout filtrage WAF pour rester fonctionnel (voir
[Installation](/difuzio/admin/installation)).

## Rebonds (bounces)

> Profil MTA local uniquement. En profil boîte externe, les rapports de non-remise
> ne reviennent pas à difuzio : cette section, la suivante (plaintes FBL) et le
> kill-switch de réputation ne s'appliquent pas. Un abonné dont l'adresse cesse de
> fonctionner se retire à la main depuis la console.

Le chemin de retour de chaque envoi est une adresse VERP signée
(`bounce+<token>@domaine`). À réception d'un rapport de non-remise (DSN), difuzio
décode le token, identifie l'abonné et le message, puis applique un score :

- rebond dur (5.x.x, boîte inexistante par exemple) : l'abonné est désactivé
  immédiatement (raison `bounce`) ;
- rebond mou (4.x.x, temporaire) : le score s'incrémente (environ 20 points par
  défaut) ; au-delà du seuil `bounce.threshold` (100) sur la fenêtre
  `bounce.window_days` (30 jours), l'abonné est désactivé ;
- un même DSN re-livré est dédupliqué (hash token + statut + destinataire) : il ne
  compte pas deux fois.

Les rebonds de courrier de service utilisent le préfixe `bounce+svc.` et ne sont
pas comptabilisés dans le score d'un abonné (seulement journalisés). Un token VERP
plus vieux que `bounce.verp_max_age_days` (90 jours) est rejeté.

difuzio est l'unique rédacteur du score de rebond d'un abonné : le calcul est
sérialisé pour éviter les courses entre workers.

## Plaintes (FBL / ARF)

Une plainte reçue sur l'adresse de boucle de rétroaction (`fbl@domaine`, format
ARF) désactive immédiatement l'abonné concerné sur la liste (raison `complaint`),
quel que soit son score. Enregistrer `fbl@` auprès des programmes FBL (Yahoo CFL,
Microsoft JMRP) est indispensable pour recevoir ces signaux.

## Réputation et kill-switch

Les rebonds durs et les plaintes alimentent des compteurs de réputation par liste
et par jour. Quand le taux de plaintes ou de rebonds durs dépasse les seuils sur
la fenêtre, l'envoi de la liste est suspendu automatiquement. Voir
[Modération, kill-switch](/difuzio/admin/moderation).

## Pools d'envoi et isolation de la réputation

Le courrier sortant est réinjecté par pool (`relay.pools`). Chaque pool permet de
mapper l'envoi vers une IP source dédiée, pour isoler la réputation entre usages
(par exemple transactionnel vs lettres d'information) :

- `selector_mode: header` ajoute un en-tête `X-Difuzio-Pool` à mapper côté Postfix
  (via `header_checks`) vers un transport et une IP source ;
- `selector_mode: verp_subdomain` utilise un sous-domaine VERP, à router via
  `sender_dependent_default_transport_maps`.

Le pool par défaut (`relay.default_pool`) est obligatoire dès qu'un domaine émet.

### Contre-pression adaptative (AIMD)

Comme un `250` du relais signifie "remis au relais" et non "livré", difuzio peut
saturer la file Postfix s'il pousse un gros envoi pendant qu'un fournisseur ralentit
en aval. Sans lire `mailq`, le worker observe par pool le ratio
deferred/timeout vs sent et applique un contrôleur **AIMD** : au-delà d'un seuil de
dégradation, le débit effectif décroît par moitié ; quand la santé revient, il
remonte par paliers vers le plafond nominal (`per_pool_messages_per_minute`, jamais
au-dessus). Chaque changement de régime est journalisé (pool, ancien/nouveau débit,
raison). Le contrôleur est par processus : superviser la profondeur de file Postfix
(`mailq`) côté ops reste recommandé.

## Enregistrements DNS à publier

Pour chaque domaine émetteur, publier :

- SPF (`v=spf1 ...`) autorisant les IP sources des pools ;
- une clé DKIM par sélecteur signé en frontal ;
- une politique DMARC (`_dmarc`, au moins `p=none` pour commencer, puis durcir).

Vérifier l'ensemble :

    difuzio check-dns --domain lists.example.org --dkim-selector default

La commande conclut par un drapeau `bulk-sender-ready`. Compléter par la
surveillance de la file Postfix (`mailq`) : un `250` du relais signifie "remis au
relais", pas "livré au destinataire".
