Skip to main content
OxiMail filtre le courrier côté serveur à travers deux couches complémentaires :
  • Les règles : des objets de filtre structurés (conditions vers actions) gérés en JMAP. C’est ce qu’édite un écran de réglages du webmail : pas de syntaxe de script, introspectable, ordonnable.
  • Les scripts Sieve : le langage de filtrage standard (RFC 5228), pour les utilisateurs avancés et pour les clients qui parlent ManageSieve. Un script peut exprimer ce que la forme structurée ne peut pas.
Les deux s’exécutent à la remise finale, là où la RFC 5228 §1.1 les place. Cela inclut le courrier qu’un collègue vous envoie depuis le même serveur : le raccourci de remise locale applique les règles du destinataire et sa réponse d’absence exactement comme pour un message reçu de l’extérieur (voir la couche SMTP et l’ADR-117).

Les règles

Une règle associe des conditions (expéditeur, destinataire, sujet, en-têtes…) à des actions (classer dans un dossier, marquer, transférer…). Deux propriétés comptent en exploitation :
  • Un ordre total et déterministe. Les règles s’évaluent dans un ordre défini, sans égalité possible : le même message prend toujours le même chemin. L’ordre fait partie des données, pas d’un accident de stockage.
  • Application au courrier existant. Rule/apply exécute une règle sur les messages existants d’un dossier, du plus récent au plus ancien, par lots bornés : la réponse porte totalInFolder, truncated et nextPosition, pour qu’un client continue explicitement au lieu de croire un plafond silencieux (chaque message évalué est une lecture de blob plus un déchiffrement : une application sans borne serait un déni de service auto-infligé). dryRun: true évalue et compte sans rien modifier, et les arguments inconnus sont rejetés en invalidArguments plutôt qu’ignorés : sur une méthode qui modifie en masse, un dryRun avalé en silence n’est pas acceptable.

Les scripts Sieve

En JMAP (RFC 9661)

Les scripts Sieve se gèrent avec les méthodes JMAP SieveScript de la RFC 9661. Le contenu du script voyage comme un blob : on téléverse le script, on le référence par blobId à la création ou à la mise à jour, et on le relit de la même façon (§2.1/2.2 : l’aller-retour renvoie les octets stockés à l’identique). La validation est une étape distincte de l’activation, et détruire le script actuellement actif est refusé avec scriptIsActive : désactivez d’abord, détruisez ensuite.

Extensions prises en charge

L’interpréteur prend en charge, et la ligne de capacité ManageSieve annonce, exactement cet ensemble (l’annonce est construite depuis la liste du compilateur lui-même, les deux ne peuvent donc pas diverger) :
Un require de quoi que ce soit d’autre échoue bruyamment à la compilation. À noter : un test Sieve header avec plusieurs noms d’en-têtes (["From", "Sender"]) reconnaît chacun d’eux. La liste n’est jamais tronquée à son premier élément.

Le script global

[sieve] global_script désigne un script optionnel à l’échelle du serveur, exécuté avant le script de chaque utilisateur. Si le script global se termine par une action terminale (redirect, discard, reject avec stop), le script de l’utilisateur est sauté. Utilisez-le pour une politique d’organisation que les utilisateurs ne doivent pas pouvoir contourner.
Les scripts compilés sont rechargés à chaud par échange atomique de pointeur : modifier un script n’exige jamais de redémarrage et ne bloque jamais les remises en cours.

ManageSieve (RFC 5804)

Les clients qui gèrent les scripts Sieve nativement (le module Sieve de Thunderbird, sieve-connect) parlent la RFC 5804. L’écouteur se lie par défaut à 127.0.0.1:4190, en local seulement, parce que ManageSieve est antérieur aux conventions TLS modernes. Pour l’exposer, terminez le TLS devant (stunnel, stream nginx) et activez le protocole PROXY pour que le serveur voie encore la vraie adresse du client :
Sans l’en-tête PROXY, chaque connexion ressemblerait à la boucle locale (généralement de confiance) et les échecs de connexion ne pourraient pas alimenter fail2ban. L’authentification prend en charge SASL PLAIN et LOGIN (y compris la variante en plusieurs étapes), et les tentatives échouées comptent dans la même mécanique fail2ban que tous les autres protocoles. GETSCRIPT renvoie les octets originaux archivés du script, pas une resérialisation.

La réponse automatique d’absence

La réponse d’absence est exposée deux fois, comme objet JMAP VacationResponse et comme extension Sieve vacation, au-dessus d’un seul mécanisme avec déduplication des réponses (une réponse automatique par correspondant et par période). Deux comportements à connaître :
  • Les réponses d’absence sont supprimées pour un compte désactivé : le courrier est toujours remis, mais une identité désactivée ne parle pas.
  • Une réponse d’absence est générée à la remise finale, donc elle répond aussi aux expéditeurs locaux.

Où regarder quand un filtre se comporte mal

  • Les verbes CLI oximail sieve ... et oximail rule ... inspectent et gèrent les deux couches par compte : voir la référence CLI.
  • Les décisions de remise sont journalisées avec le compte et le contexte de règle ou de script : voir Exploitation pour le travail avec journald.
  • Une règle qui semble ignorer le courrier envoyé par un collègue du même serveur aurait relevé de la lacune d’avant #693 ; depuis, la remise locale exécute la politique du destinataire. Si vous l’observez, c’est un bug, pas une subtilité de configuration.