Post

đŸ› ïžâš™ïž MAINTENANCE đŸ“© Stalwart Mail Server yannig.net

đŸ› ïžâš™ïž MAINTENANCE đŸ“© Stalwart Mail Server yannig.net

Parefeu - Rejeter une adresse IP

Parefeu UFW, rejeter une adresse IP

Pour rejeter l’IP publique 77.83.39.87 (sur tous les ports) :

1
sudo ufw reject from 77.83.39.87 to any

Si vous voulez bloquer seulement le SMTP (ports 25 et 587) :

1
2
sudo ufw reject from 77.83.39.87 to any port 25
sudo ufw reject from 77.83.39.87 to any port 587

Ensuite rechargez/activez et vérifiez :

1
2
sudo ufw reload
sudo ufw status numbered

Pour supprimer plus tard (remplacez N par le numéro de la rÚgle) :

1
sudo ufw delete N

Pour un blocage silencieux (ne pas répondre aux tentatives de connexion), utilisez deny au lieu de reject.

Le parefeu aprĂšs modification

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 55240/tcp                  ALLOW IN    Anywhere                  
[ 2] 443                        ALLOW IN    Anywhere                  
[ 3] 25                         ALLOW IN    Anywhere                  
[ 4] 993                        ALLOW IN    Anywhere                  
[ 5] 465                        ALLOW IN    Anywhere                  
[ 6] 587/tcp                    ALLOW IN    Anywhere                  
[ 7] Anywhere                   DENY IN     77.83.39.87               
[ 8] 55240/tcp (v6)             ALLOW IN    Anywhere (v6)             
[ 9] 443 (v6)                   ALLOW IN    Anywhere (v6)             
[10] 25 (v6)                    ALLOW IN    Anywhere (v6)             
[11] 993 (v6)                   ALLOW IN    Anywhere (v6)             
[12] 465 (v6)                   ALLOW IN    Anywhere (v6)             
[13] 587/tcp (v6)               ALLOW IN    Anywhere (v6)             

MTA Outbound Strategies

j’ai installĂ© un serveur de messagerie stalwart en avril 2026, je souhaite avoir quelques explications sur le message d’avertissement suivant:

1
queueId = 310958057209264640, queueName = "default", from = "noreply-dmarc@yannig.net", to = ["dmarc@oglix.ba"], size = 2629, total = 1, id = "report", details = "Queue strategy not found"
Ce message signifie surtout que Stalwart a essayĂ© d’envoyer ce rapport DMARC via une file d’attente nommĂ©e `default`, mais qu’il n’a trouvĂ© aucune stratĂ©gie de file d’attente associĂ©e Ă  cet envoi, donc le routage interne n’a pas pu ĂȘtre dĂ©terminĂ©.

Analyse du problĂšme

  • queueId = 310958057209264640 : identifiant interne de la file utilisĂ©e pour cet envoi.
  • queueName = "default" : Stalwart a placĂ© le message dans la file logique default, qui existe comme concept de file virtuelle et doit ĂȘtre dĂ©finie avec une stratĂ©gie.
  • from = "noreply-dmarc@yannig.net" et to = ["dmarc@oglix.ba"] : il s’agit d’un rapport DMARC, donc d’un message systĂšme de notification/authentification, pas d’un mail utilisateur classique.
  • details = "Queue strategy not found" : la cause est que la stratĂ©gie de planification/acheminement de cette file n’a pas pu ĂȘtre rĂ©solue pour ce message.

Le problĂšme vient d’un dĂ©calage entre le nom retournĂ© par ta stratĂ©gie de scheduling (report) et le nom de la file virtuelle associĂ©e Ă  la stratĂ©gie de schedule (remote) dans Stalwart.

A-Ce qui est mal aligné

  • Dans ta stratĂ©gie Scheduling (MTA Outbound) :
    1
    2
    3
    
    IF source == 'report'
    THEN 'report'
    ELSE 'remote'
    

    Cela signifie que si le message est de type rapport (comme ton DMARC), Stalwart doit retourner le nom de la stratégie report.

  • Dans ta configuration de Schedule Details (ce que tu as collĂ©) :
  • Name : remote
  • Virtual Queue* : remote

Donc tu as dĂ©fini une stratĂ©gie nommĂ©e remote associĂ©e Ă  la file virtuelle remote, mais tu n’as pas dĂ©fini la stratĂ©gie report qui retourne le nom, ni la file virtuelle correspondante lors de l’utilisation de ce nom.

Stalwart essaie donc d’utiliser la stratĂ©gie nommĂ©e report pour livrer le rapport DMARC, mais il ne trouve pas cette stratĂ©gie (ou bien la file associĂ©e), donc il remonte :

details = "Queue strategy not found"

B-Ce qui existe dans la config

  • Une file virtuelle :
    • Name : report
    • Description : “DMARC and TLS report delivery queue”
    • Delivery Threads : 5
  • Une stratĂ©gie de schedule :
    • Name : remote
    • Virtual Queue* : remote

C-Mais il manque :

  • Une stratĂ©gie de schedule nommĂ©e report (ou une autre stratĂ©gie qui renvoie le nom de la file report), associĂ©e Ă  la file virtuelle report.

Settings → MTA → Outbound → Strategy

Voici la configuration MTA Outbound Strategies Ă  appliquer pour simplifier et tout envoyer vers une file unique, par exemple remote

StratĂ©gies MTA Outbound : Settings → MTA → Outbound → Strategy

Routing

1
2
3
IF is_local_domain(rcpt_domain)
THEN 'local'
ELSE 'mx'

(Laisse cette partie telle quelle, elle ne change pas.)

Scheduling (Ă  remplacer)

Remplace l’expression actuelle par celle-ci :

1
2
3
IF is_local_domain(rcpt_domain)
THEN 'local'
ELSE 'remote'

Cela signifie :

  • Si le destinataire est sur un domaine local → utilises la stratĂ©gie local.
  • Sinon (domaine distant, y compris pour les rapports DMARC, DSN, etc.) → utilises la stratĂ©gie remote.[^1][^2]

Ainsi, plus besoin de traiter séparément source == 'dsn' ou source == 'report' : tout le trafic sortant vers des domaines externes passe par remote, qui correspond bien à une stratégie qui est déjà configurée.

Connection

Laisser tel quel :

1
`default`

TLS

Laisser tel quel :

1
2
3
IF retry_num > 0 && last_error == 'tls'
THEN 'invalid-tls'
ELSE `default`

Cliquer sur Save

MTA Outbound Delivery Schedules

Vérifications :

  • Une stratĂ©gie nommĂ©e local → associĂ©e Ă  une file virtuelle existante (par exemple local).
  • Une stratĂ©gie nommĂ©e remote → associĂ©e Ă  la file virtuelle remote (dĂ©jĂ  prĂ©sente dans ton config).

    Tu peux alors désactiver ou supprimer la file virtuelle report si tu ne veux plus de file séparée pour les rapports DMARC/TLS, ou la laisser inactive sans conséquence.

Sauvegarde et redémarrage (si nécessaire)

Management → Actions → Server settings

  • Le rapport DMARC de noreply-dmarc@yannig.net vers dmarc@oglix.ba sera envoyĂ© via la stratĂ©gie remote.
  • Stalwart ne cherchera plus la stratĂ©gie report qui n’existe pas, donc l’avertissement Queue strategy not found ne devrait plus apparaĂźtre

Ajustements DNS OVH (spf)

Mail Tester:

1
[SPF] cinay.eu n'autorise pas votre serveur 51.38.37.240 Ă  utiliser yani@cinay.eu

Le message d’erreur signifie que l’envoi d’un email avec l’adresse yani@cinay.eu Ă©choue au test SPF parce que l’IP 51.38.37.240 (yannig.net) n’est pas considĂ©rĂ©e comme autorisĂ©e par le SPF de cinay.eu

Pour un domaine secondaire oĂč le MX pointe vers un autre domaine, la configuration la plus simple et robuste

1
cinay.eu. IN TXT "v=spf1 include:yannig.net -all"

Cela évite les problÚmes de résolution de MX et assure que 51.38.37.240 est bien autorisé.

Voici les lignes exactes Ă  mettre dans OVH pour les domaines secondaires cinay.eu et yick.eu avec la meilleure configuration SPF.

Dans la zone DNS de cinay.eu, vérifier et ajouter ou remplacer

1
2
3
4
cinay.eu. IN MX 10 yannig.net.
cinay.eu. IN TXT "v=spf1 include:yannig.net -all"
_dmarc.cinay.eu. IN TXT "v=DMARC1; p=reject; rua=mailto:postmaster@cinay.eu"
_smtp._tls.cinay.eu. IN TXT "v=TLSRPTv1; rua=mailto:postmaster@cinay.eu"

Dans la zone DNS de yick.eu, vérifier et ajouter ou remplacer

1
2
3
4
yick.eu. IN MX 10 yannig.net.
yick.eu. IN TXT "v=spf1 include:yannig.net -all"
_dmarc.yick.eu. IN TXT "v=DMARC1; p=reject; rua=mailto:postmaster@yick.eu"
_smtp._tls.yick.eu. IN TXT "v=TLSRPTv1; rua=mailto:postmaster@yick.eu"

Pourquoi include:yannig.net ?

  • include:yannig.net utilise le SPF de yannig.net.
  • Si yannig.net autorise 51.38.37.240 (avec v=spf1 a mx -all), alors cinay.eu et yick.eu l’autorisent aussi.
  • Cela Ă©vite les problĂšmes de rĂ©solution de MX et garantit la cohĂ©rence.

Stalwart Default “Allow Relaying”

Cette configuration par défaut est essentielle pour éviter que votre serveur ne devienne un open relay, ce qui pourrait entraßner des problÚmes de sécurité et faire que votre serveur soit blacklisté.

Settings â€ș MTA â€ș Session â€ș RCPT TO Stage

Dans le WebUI, vous pouvez trouver cette rĂšgle sous Settings â€ș MTA â€ș Session â€ș RCPT TO Stage, oĂč le champ “Allow Relaying” dernier est par dĂ©faut Ă  false pour les utilisateurs non authentifiĂ©s.

1
2
3
[session.rcpt]
relay = [ { if = "!is_empty(authenticated_as)", then = true }, 
          { else = false } ]

WebUI

Cela garantit que :

  • ✅ Tous les utilisateurs authentifiĂ©s (yannig.net, cinay.eu, yick.eu) peuvent faire du relais , Allow Relaying = true (autorisĂ©)
  • ❌ Les utilisateurs non authentifiĂ©s ne peuvent pas faire du relais, Allow Relaying = false (interdit)

Test de relais (Allow Relaying)

Pour tester la rĂšgle Allow Relaying de Stalwart avec swaks, vous devez effectuer 2 tests : un sans authentification (doit ĂȘtre rejetĂ©) et un avec authentification (doit ĂȘtre acceptĂ©).

Installation de swaks

1
2
3
4
5
6
# Sur Debian/Ubuntu
apt-get install swaks
# Ou télécharger le script Perl
wget https://jetmore.org/john/code/swaks/files/swaks-20201014.0/swaks
chmod +x swaks
mv swaks /usr/local/bin/

1-Pour confirmer que le relais est bloqué pour les non-authentifiés :

1
2
3
4
5
6
7
8
9
# Sans authentification (doit rejeter)
swaks --to user@external.com \
      --from sender@external.com \
      --server yannig.net:587 \
      --tls \
      --auth LOGIN \
      --auth-user yann@yannig.net \
      --auth-password yann_mot_de_passe \
      --quit-after RCPT

❌ <~* 501 5.5.4 You are not allowed to send from this address. 2-Et avec authentification (doit accepter) :

1
2
3
4
5
6
7
8
swaks --to user@external.com \
      --from yann@yannig.net \
      --server yannig.net:587 \
      --tls \
      --auth LOGIN \
      --auth-user yann@yannig.net \
      --auth-password yann_mot_de_passe \
      --quit-after RCPT

✅ <~ 250 2.1.5 OK

Tableau des résultats attendus

Test Domaine Authentification Destinataire Résultat
1 yannig.net ❌ Non externe 550 Relay not allowed
2 yannig.net ✅ Oui externe 250 OK
3 cinay.eu ✅ Oui externe 250 OK
4 yick.eu ✅ Oui externe 250 OK
Si Test 1 réussit (message accepté), votre serveur est un open relay,c'est une configuration dangereuse.

SPAM ‘FORGED_RECIPIENTS’

FORGED_RECIPIENTS (destinataire forgĂ©) est un indicateur de spam dĂ©tectĂ© quand l’adresse visible dans le header To: ne correspond pas Ă  l’adresse rĂ©elle du destinataire dans l’enveloppe SMTP (RCPT TO / Delivered-To:).

Filtre Thunderbird

J’applique un filtre Thunderbird (Pour, ne contient pas, @cinay.eu) afin de rejeter ce type de message

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Delivered-To: [yani@cinay.eu](mailto:yani@cinay.eu)
X-Spam-Status: No
Received: from mx.wilde-wood.skin (mx.wilde-wood.skin [62.173.142.230] (AS34300 Internet-Cosmos LLC, RU))
	(using TLSv1.2 with cipher TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
	by yannig.net (Stalwart SMTP) with ESMTPS id 455559D67A04A00;
	Thu, 11 Jun 2026 10:05:47 +0000
Authentication-Results: yannig.net;
	spf=none (yannig.net: no SPF records found for postmaster@mx.wilde-wood.skin) smtp.helo=mx.wilde-wood.skin;
	spf=pass (yannig.net: domain of [uwhedmn@zirenma.tech](mailto:uwhedmn@zirenma.tech) designates 62.173.142.230 as permitted sender) [smtp.mailfrom=uwhedmn@zirenma.tech](mailto:smtp.mailfrom=uwhedmn@zirenma.tech);
	iprev=pass policy.iprev=62.173.142.230;
	dmarc=pass header.from=zirenma.tech policy.dmarc=none
Received-SPF: pass (yannig.net: domain of [uwhedmn@zirenma.tech](mailto:uwhedmn@zirenma.tech) designates 62.173.142.230 as permitted sender)
	receiver=yannig.net; client-ip=62.173.142.230; envelope-from="uwhedmn@zirenma.tech"; helo=mx.wilde-wood.skin;
X-Spam-Result: DMARC_POLICY_ALLOW (-0.50),
	SPF_ALLOW (-0.20),
	MIME_GOOD (-0.10),
	ARC_NA (0.00),
	DBL_BLOCKED_OPENRESOLVER (0.00),
	DKIM_NA (0.00),
	DNSWL_BLOCKED (0.00),
	FROM_EQ_ENV_FROM (0.00),
	FROM_HAS_DN (0.00),
	HAS_ATTACHMENT (0.00),
	HTML_SHORT_1 (0.00),
	MID_RHS_MATCH_ENV_FROMTLD (0.00),
	MID_RHS_MATCH_FROMTLD (0.00),
	RBL_SENDERSCORE_REPUT_BLOCKED (0.00),
	RCPT_COUNT_ONE (0.00),
	RCVD_TLS_LAST (0.00),
	RWL_MAILSPIKE_POSSIBLE (0.00),
	SOURCE_ASN_34300 (0.00),
	TO_DN_NONE (0.00),
	RCVD_COUNT_ZERO (0.10),
	SUBJECT_ENDS_QUESTION (1.00),
	FORGED_RECIPIENTS (2.00)
X-Spam-Score: ham, score=2.30
Return-Path: <uwhedmn@zirenma.tech>
Message-ID: <05345665P85002234O26030028V22606824U@mta.uwhedmn.zirenma.tech>
From: "NooBark" <uwhedmn@zirenma.tech>
To: <g.singer@changestrategy.eu>
Subject: Dog barking nonstop?
Date: Thu, 11 Jun 2026 13:03:10 +0300
MIME-Version: 1.0
Content-Type: multipart/related;
	type="multipart/alternative";
	boundary="----=_NextPart_000_0006_01DCF9A2.A5630360"

This is a multi-part message in MIME format.
[...]

A-Ce que montrent les en-tĂȘtes

  • Delivered-To: yani@cinay.eu
  • Received: ... by yannig.net (Stalwart SMTP) ...
  • X-Spam-Result: ... FORGED_RECIPIENTS ...
  • To: <hello@cherryshop.eu>

Cela indique que le message a Ă©tĂ© livrĂ© Ă  yani@cinay.eu, mais que l’expĂ©diteur a mis un To: interne diffĂ©rent dans le corps du message. Les antispam dĂ©tectent justement ce genre de dĂ©calage avec des rĂšgles comme FORGED_RECIPIENTS

B-Pourquoi ça arrive, Il y a plusieurs causes possibles

  • BCC / copie cachĂ©e : vous ĂȘtes le vrai destinataire SMTP, mais pas visible dans le To: du message.
  • Spam ou envoi de masse mal formĂ© : l’expĂ©diteur met un faux To: pour masquer la liste rĂ©elle des destinataires.
  • Forçage / falsification d’en-tĂȘtes : le champ To: peut ĂȘtre complĂštement inventĂ©, car ce n’est pas lui qui dĂ©cide de la distribution.
  • Alias ou capture de domaine : si cinay.eu ou yick.eu accepte plusieurs variantes d’adresses, le message peut ĂȘtre arrivĂ© sur une adresse valide chez vous mĂȘme si l’en-tĂȘte affiche autre chose.

C-Le plus probable est que votre serveur reçoit un spam envoyĂ© Ă  une adresse de votre domaine, puis que l’expĂ©diteur ait mis un To: fictif (hello@cherryshop.eu) pour brouiller les pistes. Le score antispam contient d’ailleurs FORGED_RECIPIENTS, ce qui va dans ce sens.

Le X-Spam-Result: ... TO_DN_NONE, RCPT_COUNT_ONE et FORGED_RECIPIENTS suggĂšrent aussi un message techniquement livrĂ© Ă  un seul destinataire rĂ©el, mais avec des en-tĂȘtes trompeurs.

Vérifier cÎté serveur Stalwart

  • les logs SMTP pour voir le RCPT TO rĂ©el ;
  • les Ă©ventuels alias, catch-all ou rĂšgles de routage sur cinay.eu et yick.eu ;
  • si Delivered-To correspond Ă  une boĂźte rĂ©elle ou Ă  une adresse attrape-tout ;
  • la politique anti-spam pour renforcer la dĂ©tection des messages avec Recipient forgĂ©.

Si vous voyez souvent des mails avec un To: qui ne vous concerne pas, ce n’est gĂ©nĂ©ralement pas une erreur de livraison : c’est presque toujours un message de masse, un BCC, ou un en-tĂȘte volontairement falsifiĂ©.

Pour filtrer sur le header To:, utilisez :

  1. Thunderbird (filtre local) → ✅ Votre filtre actuel fonctionne
  2. Score de spam avec FORGED_RECIPIENTS → Rejette les spams avec destinataire forgĂ©

Définition de FORGED_RECIPIENTS

FORGED_RECIPIENTS (destinataire forgĂ©) est un indicateur de spam dĂ©tectĂ© quand l’adresse visible dans le header To: ne correspond pas Ă  l’adresse rĂ©elle du destinataire dans l’enveloppe SMTP (RCPT TO / Delivered-To:).

Dans le message reçu :

Header Valeur
Delivered-To: yani@cinay.eu ✅ (votre adresse rĂ©elle)
To: chris@chris-music.eu ❌ (adresse forgĂ©e/fausse)

Le spammeur a forgé le header To: pour :

  1. Faire croire au destinataire que le message n’est pas destinĂ© Ă  lui (rĂ©duire le taux de rĂ©ponse)
  2. Échapper aux filtres qui vĂ©rifient le To:
  3. Rendre le spam plus “crĂ©dible” en apparence

Dans le message X-Spam-Result, FORGED_RECIPIENTS a un score de 2.00 :

1
FORGED_RECIPIENTS (2.00)

C’est un score Ă©levĂ© qui indique un spam probable.

A-Technique utilisée par les spammeurs
Un email forgé (spoofé) est un email maquillé :

  • La victime voit une adresse spĂ©cifique qui n’est pas l’adresse dont provient rĂ©ellement le message
  • Cette technique permet de rĂ©pandre plus facilement du spam, du phishing, ou des tentatives d’insultes/diffamations[hackersrepublic]

B-Pourquoi Sieve peut le détecter
Rspamd (et Stalwart qui utilise des mécanismes similaires) détecte FORGED_RECIPIENTS en comparant :

  • Les adresses dans le header To: / Cc:
  • Les adresses dans l’enveloppe SMTP (RCPT TO)

Quand ils ne correspondent pas → FORGED_RECIPIENTS est ajoutĂ© au rapport avec un score de 2.00[lists.rspamd]

Votre script Sieve qui rejette les messages avec FORGED_RECIPIENTS dans X-Spam-Result bloque correctement ce type de spam avec destinataire forgé. script Sieve avec le score de spam pour rejeter les messages FORGED_RECIPIENTS

Sieve - Rejet message FORGED_RECIPIENTS

Voici le script Sieve pour rejeter les messages avec le tag FORGED_RECIPIENTS dans le rapport de spam de Stalwart

reject-forged-recipients

1
2
3
4
5
6
7
8
9
10
11
12
13
require ["reject","regex","envelope","subaddress"];

if anyof (
  header :contains "X-Spam-Result" "FORGED_RECIPIENTS",
  header :contains "X-Spam-Status" "FORGED_RECIPIENTS",
  header :regex "X-Spam-Report" "FORGED_RECIPIENTS"
) {
  reject "Message rejeté : destinataire forgé détecté.";
}

if header :regex "X-Spam-Result" "\\bFORGED_RECIPIENTS\\b" {
  reject "Message rejeté : destinataire forgé détecté.";
}

Comment ça marche

Dans votre spam, l’en-tĂȘte X-Spam-Result contient :

1
X-Spam-Result: DMARC_POLICY_ALLOW (-0.50), SPF_ALLOW (-0.20), ..., FORGED_RECIPIENTS (2.00)

Ce script :

  1. Vérifie si X-Spam-Result contient FORGED_RECIPIENTS
  2. Si oui → rejette avec 554 erreur SMTP

Mise en place du script

  1. Ouvrez le WebUI : Settings → Sieve → System Scripts
  2. Créez un nouveau script :
    • Script Id : reject-forged-recipients
    • Script : collez le code Sieve ci-dessus
  3. Sauvegardez
  4. Settings → MTA → Session → DATA Stage
    • Run Script : reject-forged-recipients
  5. Redémarrez Stalwart :
    1
    
    sudo systemctl restart stalwart-mail
    

    Test avec swaks

Le script sieve est valide, mode debug actif, pas de dovecot, me rappeler la commande de test swaks

Utilisez cette commande swaks (envoi direct vers yann@yannig.net, ajoute l’en-tĂȘte X-Spam-Result contenant FORGED_RECIPIENTS) :

1
swaks --server yannig.net --from tst@cinay.eu --to yann@yannig.net --header "X-Spam-Result: FORGED_RECIPIENTS" --header "To: yannig@forged.example" --data message.eml

Pour forcer un en-tĂȘte prĂ©cis dans DATA sans utiliser –data file, vous pouvez inline le message ainsi :

1
2
3
4
5
6
7
8
(
  echo "From: tst@cinay.eu"
  echo "To: yannig@forged.example"
  echo "X-Spam-Result: FORGED_RECIPIENTS"
  echo "Subject: Test FORGED_RECIPIENTS"
  echo
  cat message.eml
) | swaks --server yannig.net --from tst@cinay.eu --to yann@yannig.net --data -

Surveillez les logs en temps rĂ©el aprĂšs l’envoi (mode debug actif) :

1
sudo tail -f /var/log/stalwart/stalwart.2026-06-15

La zone correspondante à l’envoi du message de test

1
2
3
4
5
6
7
8
[...]
2026-06-15T06:12:32Z DEBUG Pyzor success (spam.pyzor) listenerId = "smtp", localPort = 25, remoteIp = fe80::f816:3eff:fe25:b53a, remotePort = 51144, result = false, details = [200, 0, 0], elapsed = 11ms
2026-06-15T06:12:32Z DEBUG Sieve action: Reject (sieve.action-reject) listenerId = "smtp", localPort = 25, remoteIp = fe80::f816:3eff:fe25:b53a, remotePort = 51144, id = "reject-forged-recipients", details = "Message rejeté : destinataire forgé détecté.", elapsed = 0ms
2026-06-15T06:12:32Z DEBUG SMTP QUIT command (smtp.quit) listenerId = "smtp", localPort = 25, remoteIp = fe80::f816:3eff:fe25:b53a, remotePort = 51144
2026-06-15T06:12:32Z DEBUG SMTP connection ended (smtp.connection-end) listenerId = "smtp", localPort = 25, remoteIp = fe80::f816:3eff:fe25:b53a, remotePort = 51144, elapsed = 1691ms
2026-06-15T06:12:32Z DEBUG HTTP store updated (store.http-store-fetch) url = "https://disposable.github.io/disposable-email-domains/domains_mx.txt", total = 21463, elapsed = 134ms
2026-06-15T06:12:32Z DEBUG HTTP store updated (store.http-store-fetch) url = "https://gist.githubusercontent.com/okutbay/5b4974b70673dfdcc21c517632c1f984/raw/993a35930a8d24a1faab1b988d19d38d92afbba4/free_email_provider_domains.txt", total = 96640, elapsed = 234ms
[...]

Le log montre que le script Sieve a bien rejeté le message :

1
2026-06-15T06:12:32Z DEBUG Sieve action: Reject ... id = "reject-forged-recipients" ... details = "Message rejeté : destinataire forgé détecté."

La rÚgle Sieve reject-forged-recipients fonctionne et a rejeté le message à la réception.

  • Le filtre Sieve avec FORGED_RECIPIENTS ne bloque pas vos envois lĂ©gitimes
  • rejet signifie que le message est refusĂ© pendant la phase de livraison et n’est pas placĂ© dans une boĂźte utilisateur (Inbox, Spam, Trash, etc.).
    • Rejet SMTP (reject) renvoie une erreur au client Ă©metteur et empĂȘche la livraison locale.
    • Aucun dossier utilisateur ne reçoit le message (ni Spam, ni Junk, ni Trash).
    • Le serveur peut conserver un enregistrement de l’évĂ©nement dans ses logs et Ă©ventuellement une copie interne si vous avez explicitement configurĂ© une quarantaine sĂ©parĂ©e — mais ce n’est pas automatique avec un simple reject Sieve.

Sieve fishing sites gouvernementaux

Filtrer/rejeter automatiquement les e-mails de phishing prĂ©tendant provenir de gouv.fr en combinant vĂ©rifications d’en-tĂȘtes (SPF, DKIM, DMARC) et rĂšgles Sieve/Thunderbird.

Ne pas rejeter automatiquement tout message contenant “gouv.fr” : certains lĂ©gitimes utilisent d’autres domaines ou forwarding. PrĂ©fĂ©rer un blocage des messages qui prĂ©tendent venir d’un domaine gouv.fr mais Ă©chouent aux contrĂŽles d’authentification (SPF/DKIM/DMARC) ou dont l’adresse d’expĂ©diteur est forgĂ©e.

domaines officiels utilisés par le gouvernement français

Voici une liste des principaux domaines officiels utilisés par le gouvernement français pour la messagerie et les sites officiels :

  • .gouv.fr — domaine principal des administrations et ministĂšres français (ex. service-public.gouv.fr, interieur.gouv.fr).
  • .service-public.fr — portail officiel de l’administration française (utilisĂ© pour certaines messageries/formulaires liĂ©s aux services publics).
  • .etat.fr — utilisĂ© par certaines entitĂ©s d’État (rare).
  • .pref.gouv.fr — domaines des prĂ©fectures (souvent prĂ©fecture-.gouv.fr ou pref..gouv.fr).
  • .france.fr — site institutionnel de promotion (moins utilisĂ© pour messagerie).
  • .legifrance.gouv.fr — publications juridiques officielles (principalement site, pas messagerie).
  • .assemblee-nationale.fr — domaine de l’AssemblĂ©e nationale (emails officiels pour dĂ©putĂ©s/personnel).
  • .senat.fr — domaine du SĂ©nat.
  • .conseil-constitutionnel.fr — Conseil constitutionnel.
  • .cours-finances.gouv.fr / .dgfip.finances.gouv.fr — exemples de sous-domaines pour la direction gĂ©nĂ©rale des finances publiques (DGFIP).
  • .ac-.fr — acadĂ©mies (Ă©ducation nationale) ; messagerie des rectorats et Ă©tablissements scolaires utilise souvent ces sous-domaines (ex. ac-paris.fr).
  • .collectivites-locales.fr / .departement.fr / .metropole.fr — domaines utilisĂ©s par certaines collectivitĂ©s territoriales (mairies, dĂ©partements, rĂ©gions) ; beaucoup utilisent sous-domaines en .gouv.fr ou domaines locaux (ex. ville-xxx.fr).
  • .gendarmerie.interieur.gouv.fr et .police.interieur.gouv.fr — sous-domaines pour gendarmerie et police du ministĂšre de l’IntĂ©rieur.

Remarques courtes :

  • La plupart des adresses e-mail officielles se prĂ©sentent sous la forme prenom.nom@organisation.gouv.fr ou contact@organisation.gouv.fr.
  • Les administrations locales (mairies, rĂ©gions, dĂ©partements) peuvent utiliser des domaines propres (ex. mairie-xxx.fr) ; vĂ©rifier l’adresse sur le site officiel de l’entitĂ©.

Voici le script Sieve prĂȘt Ă  coller dans Settings → Sieve → System Scripts. Il fileinto “Junk”, ajoute le flag, et prĂ©fixe le sujet par “[POSSIBLE PHISHING]”. AprĂšs le script je fournis une commande swaks d’exemple pour tester (adaptĂ©e Ă  un relais SMTP local ; ajustez destinataire/source/host).

Stalwart/Dovecot Sieve uses the “envelope” test with keys “from” or “to”. Change “envelope :matches ‘MAIL FROM’ 
” to “envelope :matches “from” "@.gouv.fr"”. Also ensure quoting/escaping. Here’s the corrected script — compatible with Dovecot/Manage Sieve

phishing_gouv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
require ["fileinto","imapflags","regex","variables","envelope","editheader"];

if header :regex "From" "(?i)(gouv|antai|anta[iĂŻ])" {

  if anyof (
    not header :regex "From" "(?i)@[^\\s>]+\\.gouv\\.fr",
    header :contains "Authentication-Results" "dmarc=fail",
    header :contains "Authentication-Results" "dmarc=permerror",
    header :contains "Authentication-Results" "spf=fail",
    header :contains "Authentication-Results" "dkim=fail"
  ) {
    if exists "Subject" {
      addheader "Subject" "[POSSIBLE PHISHING] ";
    } else {
      addheader "Subject" "[POSSIBLE PHISHING] (no subject)";
    }
    fileinto "Junk";
    setflag "\\Flagged";
    stop;
  }

  if allof (
    not envelope :matches "from" "*@*.gouv.fr",
    not header :contains "Authentication-Results" "dmarc=pass"
  ) {
    if exists "Subject" {
      addheader "Subject" "[POSSIBLE PHISHING] ";
    } else {
      addheader "Subject" "[POSSIBLE PHISHING] (no subject)";
    }
    fileinto "Junk";
    setflag "\\Flagged";
    stop;
  }
}

Collez et sauvegardez dans System Scripts

Remarques rapides :

  • Certains serveurs utilisent d’autres noms pour le dossier spam ; remplacez “Junk” si nĂ©cessaire.
  • L’usage de deleteheader “Subject” est optionnel selon le comportement de votre MTA/IMAP client ; testez et supprimez la ligne si ça supprime le sujet visible.

Commande swaks d’exemple pour tester (remplacez valeurs) :

  • but : envoyer un message simulant From “Agence
 ...@oglix.ba” vers yannig.net via votre MX Stalwart.
  • ajustez –server, –from, –to, –h-Header, –data as needed.

Le serveur refuse l’adresse MAIL FROM car swaks a envoyĂ© une adresse non-ASCII/avec espace/brackets — la syntaxe SMTP attend un adresse-mail simple entre <>. Utilisez l’option –from pour dĂ©finir une adresse simple et mettez l’en-tĂȘte From sĂ©parĂ©ment.

1
2
3
4
5
6
7
swaks --server yannig.net:25 \
  --from "amendes-antai-gouv@oglix.ba" \
  --to "yani@cinay.eu" \
  --header "From: Agence Nationale de Traitement Automatisé des Infractions <amendes-antai-gouv@oglix.ba>" \
  --header "Subject: ANTAI - test phishing" \
  --header "Authentication-Results: yannig.net; dkim=pass header.d=oglix.ba; spf=pass smtp.mailfrom=oglix.ba; dmarc=none header.from=oglix.ba" \
  --data "Ceci est un test."

Notes :

  • Ne mettez pas de nom convivial dans –from ; utilisez une adresse pure (ASCII). Placez le nom convivial dans l’en-tĂȘte “From”.
  • Si vous envoyez via TLS/REQUIRETLS, ajoutez –timeout et –tls –auth (si nĂ©cessaire) ou utilisez le port 587 avec authentification.

Avec la commande swaks , le message test a Ă©tĂ© placĂ© dans le dossier “indĂ©sirables”

Debug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2026-06-15T09:06:57Z INFO Authentication successful (auth.success) listenerId = "imaps", localPort = 993, remoteIp = 2a01:e0a:95a:e2f0:d357:db0:cdb0:70ab, remotePort = 50666, accountName = "yani@cinay.eu", accountId = 4
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) accountId = 4, collection = "email", changeId = 1289, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG IMAP ID command (imap.id) listenerId = "imaps", localPort = 993, remoteIp = 2a01:e0a:95a:e2f0:d357:db0:cdb0:70ab, remotePort = 50666, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG IMAP ENABLE command (imap.enable) listenerId = "imaps", localPort = 993, remoteIp = 2a01:e0a:95a:e2f0:d357:db0:cdb0:70ab, remotePort = 50666, details = ["Utf8Accept"], elapsed = 0ms
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) key = 4, collection = "accessToken"
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) accountId = 4, collection = "email", changeId = 1289, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) accountId = 4, collection = "email", changeId = 1289, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG IMAP SELECT command (imap.select) listenerId = "imaps", localPort = 993, remoteIp = 2a01:e0a:95a:e2f0:d357:db0:cdb0:70ab, remotePort = 50666, mailboxName = "Junk Mail", accountId = 4, mailboxId = 2, total = 1, uidNext = 34, uidValidity = 660552631, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) key = 4, collection = "accessToken"
2026-06-15T09:06:57Z DEBUG IMAP MYRIGHTS command (imap.my-rights) listenerId = "imaps", localPort = 993, remoteIp = 2a01:e0a:95a:e2f0:d357:db0:cdb0:70ab, remotePort = 50666, mailboxName = "Junk Mail", accountId = 4, mailboxId = 2, details = ["r", "l", "i", "t", "e", "s", "w", "k", "x", "p", "a"], elapsed = 0ms
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) key = 4, collection = "accessToken"
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) key = 4, collection = "account"
2026-06-15T09:06:57Z DEBUG IMAP GET ACL command (imap.get-acl) listenerId = "imaps", localPort = 993, remoteIp = 2a01:e0a:95a:e2f0:d357:db0:cdb0:70ab, remotePort = 50666, mailboxName = "Junk Mail", accountId = 4, mailboxId = 2, total = 1, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) key = 4, collection = "accessToken"
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) accountId = 4, collection = "email", changeId = 1289, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) key = 4, collection = "account"
2026-06-15T09:06:57Z DEBUG IMAP GETQUOTA command (imap.get-quota) listenerId = "imaps", localPort = 993, remoteIp = 2a01:e0a:95a:e2f0:d357:db0:cdb0:70ab, remotePort = 50666, mailboxName = "Junk Mail", details = [1514023, 0], elapsed = 0ms
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) accountId = 4, collection = "email", changeId = 1289, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) accountId = 4, collection = "email", changeId = 1289, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG IMAP FETCH command (imap.fetch) listenerId = "imaps", localPort = 993, remoteIp = 2a01:e0a:95a:e2f0:d357:db0:cdb0:70ab, remotePort = 50666, accountId = 4, mailboxId = 2, documentId = [625], details = ["Uid", "Flags"], elapsed = 0ms
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) accountId = 4, collection = "email", changeId = 1289, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG Cache hit (store.cache-hit) accountId = 4, collection = "email", changeId = 1289, elapsed = 0ms
2026-06-15T09:06:57Z DEBUG IMAP FETCH command (imap.fetch) listenerId = "imaps", localPort = 993, remoteIp = 2a01:e0a:95a:e2f0:d357:db0:cdb0:70ab, remotePort = 50666, accountId = 4, mailboxId = 2, documentId = [625], details = ["Uid", "Rfc822Size", "Flags", "BodySection { peek: true, sections: [HeaderFields { not: false, fields: ["From", "To", "Cc", "Bcc", "Subject", "Date", "Message-ID", "Priority", "X-Priority", "References", "Newsgroups", "In-Reply-To", "Content-Type", "Reply-To", "Received", "Reply-To"] }], partial: None }"], elapsed = 0ms

Les logs confirment que le message a bien Ă©tĂ© dĂ©placĂ© dans “Junk Mail” (mailboxId = 2, documentId = 625) et que l’IMAP client a rĂ©cupĂ©rĂ© l’en-tĂȘte.

Cet article est sous licence CC BY 4.0 par l'auteur.