Domaines

Un domaine regroupe les listes d'une même zone de courrier (par exemple lists.example.org). Il porte le base_url public, le nom du robot, et les politiques par défaut héritées par ses listes.

États d'un domaine

Un domaine a l'un de ces trois états (domains.status) :

  • pending_mta : état initial à la création. Le routage MTA n'est pas encore confirmé ; la réception LMTP refuse les posts adressés à ce domaine.
  • active : le domaine accepte les posts et émet du courrier.
  • suspended : le domaine est désactivé administrativement.

La réception LMTP rejette tout courrier dont le domaine n'est pas active.

Provisionner un domaine

CREDENTIALS_DIRECTORY=/etc/difuzio/secrets difuzio add-domain --config /etc/difuzio/config.yaml \
    --name lists.example.org \
    --base-url https://lists.example.org \
    --display-name "Listes Example" \
    --robot difuzio \
    --locale fr
  • --name (obligatoire) : le domaine de courrier. Il est normalisé en ASCII (IDNA) et mis en minuscules.
  • --base-url (obligatoire) : l'URL publique vers laquelle pointent tous les liens des courriers (confirmation, désabonnement, archives). Sans base_url, difuzio refuse d'émettre pour ce domaine.
  • --display-name (optionnel) : nom lisible.
  • --robot (optionnel) : la partie locale de l'adresse robot (par défaut difuzio). C'est l'adresse d'aide globale du domaine (voir Référence CLI et la grammaire d'adresses ci-dessous).
  • --locale (optionnel) : fr (défaut) ou en, la langue des courriers transactionnels envoyés aux abonnés de ce domaine.

La commande crée le domaine en état pending_mta et affiche son identifiant.

Domaines déclarés dans la configuration

La section domains: du fichier de configuration (voir Configuration) est validée au démarrage (nom normalisé IDNA, base_url obligatoire) mais ne crée pas et n'active pas les domaines en base. Le provisionnement effectif passe par add-domain.

Activer un domaine

En profil boîte externe, il n'y a pas de routage MTA à mettre en place : le domaine passe directement en active une fois la boîte relevée déclarée. Penser aussi à difuzio domain set-command-addresses --routed=false (voir "Adresses de service" ci-dessous).

La transition pending_mta -> active se fait avec set-domain-status, une fois le routage Postfix en place et vérifié :

CREDENTIALS_DIRECTORY=/etc/difuzio/secrets difuzio set-domain-status --config /etc/difuzio/config.yaml \
    --domain lists.example.org --status active

Les statuts acceptés sont active, suspended et pending_mta. Vérifier avec difuzio doctor et difuzio check-dns (ci-dessous) avant d'activer.

Modifier les réglages d'un domaine

PATCH /api/v1/domains/{domaine} (voir API REST) applique une mise à jour partielle : seuls les champs envoyés sont écrits, les autres gardent leur valeur. Sont modifiables display_name, base_url, robot_name, locale, command_addresses, separator, max_message_size, bounce_threshold, dkim_selector, expected_spf_includes et les valeurs par défaut héritées par les nouvelles listes (default_post_policy, default_subscribe_policy, default_archive_access, default_reply_to_mode, default_from_munging).

Chaque valeur est validée avant écriture ; un refus est un 422 qui nomme le champ fautif et ne modifie rien :

  • base_url doit être une URL http(s) absolue avec un hôte.
  • separator est un caractère unique parmi -, . et _. + est refusé : il ouvre le chemin de retour VERP (bounce+).
  • robot_name suit la grammaire d'une partie locale de liste et ne doit pas entrer en collision avec une adresse de contrôle.
  • Changer separator ou robot_name est refusé si une liste existante du domaine deviendrait de ce fait une adresse de contrôle (par exemple la liste equipe.subscribe avec un séparateur passé à .) : le courrier de cette liste cesserait silencieusement d'être distribué.
  • max_message_size et bounce_threshold doivent valoir au moins 1. Un seuil de rebond à 0 désactiverait toutes les adresses au premier rebond traité.
  • locale vaut fr ou en : c'est la langue des courriers transactionnels envoyés au nom du domaine (confirmation d'abonnement, bienvenue, adieu, lien de connexion). Voir Mails transactionnels.

Attention : base_url est l'origine des liens (confirmation, désabonnement, archives) déjà présents dans les courriers envoyés. Le modifier casse ces liens tant que l'ancienne origine ne répond plus ; ne le changer qu'en même temps que le vhost public.

Le statut se change par le même appel (champ status) mais reste réservé à un super_admin, alors que les réglages ci-dessus sont ouverts à l'administrateur du domaine. Un appel qui mêle les deux est refusé en bloc si l'une des deux autorisations manque : rien n'est écrit.

Adresses de service : les annoncer ou non

Un domaine déclare si ses adresses de service (liste-subscribe@, liste-unsubscribe@, liste-owner@, liste-request@) sont réellement remises à difuzio :

difuzio domain set-command-addresses --domain lists.example.org --routed=false

Ce n'est pas une préférence, c'est la description du serveur de messagerie placé devant. La valeur par défaut est true, le cas d'un domaine routé vers difuzio.

Elle décide de ce que difuzio promet aux abonnés. Avec --routed=false :

  • List-Help, List-Subscribe et List-Owner ne portent plus que leur URL web (List-Owner renvoie vers la page d'aide de la liste) ;
  • List-Unsubscribe ne porte plus que le lien de désabonnement en un clic, sans le repli mailto: ;
  • la page publique d'aide et le formulaire d'abonnement cessent d'afficher ces adresses.

L'adresse de la liste elle-même (liste@domaine) reste annoncée dans tous les cas : en profil boîte externe, c'est précisément la boîte relevée.

Laisser ce réglage à true sans routage correspondant est le défaut à éviter : chaque message annonce alors des adresses que l'hébergeur rejette, et un abonné qui suit l'en-tête List-Owner de son client de messagerie reçoit un rapport de non-remise au lieu d'une réponse.

Intégration Postfix

Profil MTA local uniquement. En profil boîte externe, aucun MX n'est modifié et aucune adresse de commande n'existe : la réception se fait par relève IMAP (voir Comptes de messagerie externes). La section suivante, "Grammaire des adresses d'un domaine", ne s'applique pas non plus : seule l'adresse de la liste est utilisée.

Imprimer les lignes de routage Postfix pour un domaine :

difuzio mta-config --domain lists.example.org

La commande affiche les blocs main.cf, transport et master.cf à reporter dans Postfix. L'option --socket permet d'indiquer la socket LMTP de difuzio (par défaut /run/difuzio/lmtp.sock). Le principe : le domaine entier est routé vers difuzio via le transport LMTP. difuzio valide lui-même les destinataires RCPT (ne pas définir virtual_mailbox_maps pour ce domaine), et difuzio reçoit les posts, les bounces VERP (bounce+*@) et les plaintes (fbl@).

Grammaire des adresses d'un domaine

Pour une liste <liste> sous un domaine routé, difuzio reconnait :

  • <liste>@domaine : poster sur la liste.
  • <liste>-subscribe@domaine : s'abonner.
  • <liste>-unsubscribe@domaine : se désabonner.
  • <liste>-request@domaine : demande d'aide / contact gestion.
  • owner-<liste>@domaine ou <liste>-owner@domaine : contacter les propriétaires.
  • bounce+<token>@domaine : chemin de retour VERP (rebonds).
  • bounce+svc.<token>@domaine : rebond de courrier de service (non comptabilisé dans le score de rebond).
  • fbl@domaine : adresse de plainte (boucle de rétroaction FBL).
  • <robot>@domaine : adresse d'aide globale du domaine.

Le séparateur par défaut est -. La résolution suit une correspondance de plus longue liste existante (comme Mailman) : dev-team-subscribe route vers la liste dev-team-subscribe si elle existe, sinon vers la liste dev-team avec l'action subscribe.

Vérifier le DNS et la délivrabilité

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

La commande vérifie la présence d'un enregistrement SPF (v=spf1), d'une politique _dmarc (au moins p=none) et, si --dkim-selector est fourni, du sélecteur DKIM correspondant. Elle conclut par un drapeau bulk-sender-ready (YES/NO) et un code de sortie non nul si un enregistrement manque. Voir Délivrabilité pour le détail des enregistrements à publier.