đ·Stalwart vĂ©rification serveur
- Vérification manuelle serveur messagerie
- Script vérification multi-domaines
- Script complet
- Exécution
- Enregistrements DKIM testés
- SPF recommandé
- Point à vérifier dans Stalwart
- Niveau de SPAM ?
Vérification manuelle serveur messagerie
Linux, outils ligne de commande, liens web pour faire une vĂ©rification complĂšte de mon serveur de messagerie âStalwart web uiâ
- DOMAINE OVH yannig.net
- MX yannig.net
- IMAP SSL/TLS Port 993
- SMTP SSL/TLS Port 465
Pour vĂ©rifier complĂštement votre serveur Stalwart associĂ© Ă yannig.net, contrĂŽlez sĂ©parĂ©ment DNS, routage SMTP, certificats TLS, IMAP, authentification SPF/DKIM/DMARC, rĂ©putation et configuration Stalwart. Les ports 993/IMAPS et 465/SMTPS sont adaptĂ©s aux clients, mais le port 25 doit Ă©galement ĂȘtre testĂ© pour la rĂ©ception et la livraison entre serveurs.
1. Vérification DNS depuis Linux
Effectuez ces commandes depuis une machine externe au serveur, si possible un VPS ou une connexion différente :
1
2
3
4
5
6
7
8
9
10
DOMAIN=yannig.net
dig "$DOMAIN" A +short
dig "$DOMAIN" AAAA +short
dig "$DOMAIN" MX +short
dig "$DOMAIN" NS +short
dig "$DOMAIN" CAA +short
dig "$DOMAIN" TXT +short
dig "_dmarc.$DOMAIN" TXT +short
dig "$DOMAIN" DNSKEY +dnssec
Vérifiez en particulier :
- Le MX de
yannig.netdoit pointer vers un nom dâhĂŽte stable, par exemplemail.yannig.net. - Le nom indiquĂ© par le MX doit possĂ©der un enregistrement
Aet Ă©ventuellementAAAA. - Lâadresse IPv4 publique doit avoir un reverse DNS cohĂ©rent.
- Il ne doit exister quâun seul enregistrement SPF
v=spf1. - Le domaine doit posséder un enregistrement DMARC.
- Le sĂ©lecteur DKIM doit ĂȘtre rĂ©cupĂ©rĂ© dans lâinterface Stalwart, puis testĂ© ainsi :
1
dig TXT SELECTEUR._domainkey.yannig.net +short
Remplacez SELECTEUR par le sélecteur réellement affiché par Stalwart.
Pour connaĂźtre le reverse DNS de lâadresse IPv4 :
1
dig -x ADRESSE_IPV4 +short
Le rĂ©sultat devrait ĂȘtre un nom tel que mail.yannig.net, et ce nom devrait ensuite rĂ©soudre vers la mĂȘme adresse IP :
1
dig mail.yannig.net A +short
Stalwart documente les enregistrements nécessaires pour MX, SPF, DKIM, DMARC, TLSA et les autres mécanismes DNS de messagerie.
2. Vérification des ports réseau
Depuis une machine extérieure :
1
2
3
4
nc -vz -w5 yannig.net 25
nc -vz -w5 yannig.net 465
nc -vz -w5 yannig.net 587
nc -vz -w5 yannig.net 993
Résultat attendu :
1
succeeded
Le port 25 est important mĂȘme si vous nâutilisez pas ce port dans Thunderbird ou K-9 Mail : les autres serveurs SMTP lâutilisent pour remettre les messages Ă votre serveur.
Vous pouvez obtenir davantage dâinformations avec Nmap :
1
nmap -Pn -sV -p 25,465,587,993 yannig.net
Puis analyser les suites cryptographiques :
1
2
3
nmap -Pn -p 465,993 \
--script ssl-enum-ciphers \
yannig.net
Ne vous limitez pas Ă un test exĂ©cutĂ© depuis le serveur lui-mĂȘme : un pare-feu local, Docker, OVH ou un routeur peut autoriser les connexions locales tout en bloquant lâaccĂšs public.
3. Test des certificats TLS
SMTP implicite sur 465
Le port 465 démarre directement en TLS :
1
2
3
4
5
6
openssl s_client \
-connect yannig.net:465 \
-servername yannig.net \
-showcerts \
-verify_return_error \
-brief </dev/null
IMAP implicite sur 993
1
2
3
4
5
6
openssl s_client \
-connect yannig.net:993 \
-servername yannig.net \
-showcerts \
-verify_return_error \
-brief </dev/null
ContrĂŽlez notamment :
Verification: OK.- Le certificat nâest pas expirĂ©.
- Le certificat contient
yannig.netdans le SAN. - La chaĂźne complĂšte est fournie.
- Le certificat présenté sur
465et993est bien celui attendu. - TLS 1.2 ou TLS 1.3 est disponible.
- TLS 1.0 et TLS 1.1 sont désactivés.
Pour vérifier explicitement les protocoles :
1
2
3
4
5
6
7
8
for version in tls1 tls1_1 tls1_2 tls1_3; do
echo "===== $version ====="
openssl s_client \
-connect yannig.net:465 \
-servername yannig.net \
-$version </dev/null 2>&1 | grep -E \
'Protocol|Cipher|alert|handshake failure'
done
Pour le port SMTP 587, le mode correct est généralement STARTTLS :
1
2
3
4
5
6
openssl s_client \
-connect yannig.net:587 \
-servername yannig.net \
-starttls smtp \
-verify_return_error \
-brief </dev/null
Le mĂȘme test peut ĂȘtre effectuĂ© sur le port 25 :
1
2
3
4
5
6
openssl s_client \
-connect yannig.net:25 \
-servername yannig.net \
-starttls smtp \
-verify_return_error \
-brief </dev/null
La commande openssl s_client -connect hÎte:port convient aux connexions TLS implicites comme 465 et 993, tandis que -starttls smtp est nécessaire pour tester STARTTLS sur 25 ou 587.
4. Vérification du protocole IMAP
Pour vérifier que le serveur ne fait pas uniquement une négociation TLS mais répond bien en IMAP :
1
2
3
4
5
6
printf 'a001 CAPABILITY\r\na002 LOGOUT\r\n' |
openssl s_client \
-connect yannig.net:993 \
-servername yannig.net \
-quiet \
-crlf
Vous devez obtenir une réponse contenant notamment une ligne similaire à :
1
* CAPABILITY IMAP4rev1 ...
Testez ensuite lâauthentification uniquement avec un compte de test :
1
2
3
4
openssl s_client \
-connect yannig.net:993 \
-servername yannig.net \
-crlf
Une fois connecté, utilisez les commandes IMAP suivantes :
1
2
3
4
a001 CAPABILITY
a002 LOGIN utilisateur@yannig.net MOT_DE_PASSE_DE_TEST
a003 LIST "" "*"
a004 LOGOUT
Nâutilisez pas votre compte administrateur et ne laissez pas le mot de passe dans lâhistorique du shell.
5. Vérification SMTP authentifiée
Installez éventuellement swaks :
1
sudo apt install swaks
Pour tester lâenvoi authentifiĂ© sur 465 :
1
2
3
4
5
6
7
8
swaks \
--server yannig.net \
--port 465 \
--tls \
--auth LOGIN \
--auth-user utilisateur@yannig.net \
--to adresse-externe@example.net \
--from utilisateur@yannig.net
swaks demandera normalement le mot de passe de maniĂšre interactive selon votre version. Utilisez une boĂźte de test et une adresse externe que vous contrĂŽlez.
Testez aussi la soumission sur 587 :
1
2
3
4
5
6
7
8
swaks \
--server yannig.net \
--port 587 \
--tls \
--auth LOGIN \
--auth-user utilisateur@yannig.net \
--to adresse-externe@example.net \
--from utilisateur@yannig.net
à vérifier dans les résultats :
- Le certificat TLS est valide.
- Lâauthentification Ă©choue avec un mauvais mot de passe.
- Lâenvoi sans authentification depuis
465/587est refusĂ©. - Le serveur nâest pas un relais ouvert.
- Lâadresse dâexpĂ©diteur est correctement contrĂŽlĂ©e.
- Le message reçu contient
Authentication-Resultsavec SPF, DKIM et DMARC.
Pour tester rapidement lâabsence de relais ouvert, utilisez :
1
2
3
4
5
swaks \
--server yannig.net \
--port 25 \
--from test-externe@example.net \
--to autre-adresse-externe@example.net
Ce test ne doit pas aboutir sans authentification lorsquâil sâagit dâun envoi non autorisĂ©.
6. SPF, DKIM et DMARC
SPF
1
dig TXT yannig.net +short
Il doit y avoir une politique SPF, par exemple :
1
v=spf1 mx ip4:ADRESSE_IPV4 -all
Adaptez-la aux vĂ©ritables serveurs autorisĂ©s Ă envoyer des messages. Ăvitez dâavoir plusieurs TXT SPF diffĂ©rents.
DKIM
Depuis lâinterface Stalwart, rĂ©cupĂ©rez le sĂ©lecteur et la clĂ© publique. Puis :
1
dig TXT SELECTEUR._domainkey.yannig.net +short
Envoyez ensuite un message vers une boĂźte Gmail, Outlook ou une autre boĂźte de test, puis affichez les en-tĂȘtes complets. Vous devez trouver une ligne indiquant une signature DKIM valide, par exemple :
1
dkim=pass
Stalwart gĂ©nĂšre et signe les messages sortants avec une clĂ© DKIM dont la clĂ© publique doit ĂȘtre publiĂ©e sous SELECTEUR._domainkey.yannig.net.
DMARC
1
dig TXT _dmarc.yannig.net +short
Pour commencer, une politique de surveillance peut ressembler Ă :
1
v=DMARC1; p=none; rua=mailto:dmarc@yannig.net
AprÚs observation des rapports et correction des erreurs SPF/DKIM, vous pourrez évoluer vers :
1
v=DMARC1; p=quarantine; rua=mailto:dmarc@yannig.net
Puis éventuellement :
1
v=DMARC1; p=reject; rua=mailto:dmarc@yannig.net
Ne passez pas directement Ă p=reject si vous nâavez pas vĂ©rifiĂ© tous les systĂšmes qui envoient des messages pour yannig.net.
7. Tests web recommandés
Utilisez les services suivants avec yannig.net :
- Internet.nl â test de messagerie VĂ©rifie notamment IPv6, DNSSEC, SPF, DKIM, DMARC, STARTTLS, DANE, RPKI et la sĂ©curitĂ© TLS.
- MXToolbox
Testez successivement
MX,SPF,DMARC,DKIM, les listes noires et le DNS. MXToolbox fournit des vĂ©rificateurs spĂ©cialisĂ©s pour ces enregistrements. - Mail-Tester GĂ©nĂ©rez une adresse temporaire, envoyez-lui un message depuis Stalwart et analysez le score ainsi que les rĂ©sultats SPF, DKIM, DMARC, reverse DNS et rĂ©putation. Le test doit ĂȘtre effectuĂ© avec votre vĂ©ritable serveur dâenvoi.
- DNSRobot â test SMTP
Utile pour contrĂŽler la banniĂšre SMTP, les commandes
EHLO, STARTTLS et les ports25,465et587. - Mail SSL Checker
Vérifie directement les certificats et TLS sur
465,993, ainsi que STARTTLS sur les ports compatibles.
Les rĂ©sultats dâInternet.nl sont particuliĂšrement utiles pour une vue globale, car le service produit un rapport avec un score gĂ©nĂ©ral et le dĂ©tail de chaque sous-test.[^4]
8. ContrÎles spécifiques Stalwart
Dans lâinterface WebAdmin de Stalwart, vĂ©rifiez :
- Domaine
yannig.netprésent et activé. - Compte administrateur distinct des comptes de messagerie.
- Certificat TLS associĂ© au bon nom dâhĂŽte.
- Services IMAP, SMTP et éventuellement JMAP activés uniquement sur les interfaces nécessaires.
- Authentification SMTP obligatoire pour
465et587. - Relaying sortant limité aux utilisateurs authentifiés.
- DKIM activé pour les messages sortants.
- Vérification SPF, DKIM et DMARC activée pour les messages entrants.
- Limitation de débit et protection contre les abus.
- Journaux dâauthentification et de remise surveillĂ©s.
- File dâattente SMTP vide ou sans erreurs rĂ©pĂ©tĂ©es.
- Aucun compte ou alias compromis.
Suivez les journaux pendant un test :
1
sudo journalctl -fu stalwart
Si Stalwart fonctionne dans Docker :
1
docker compose logs -f --tail=200 stalwart
ou :
1
docker logs -f --tail=200 NOM_DU_CONTENEUR_STALWART
Enfin, contrĂŽlez les rĂšgles de pare-feu :
1
2
sudo ss -lntp | grep -E ':(25|465|587|993)\b'
sudo nft list ruleset
La configuration minimale attendue est donc : 25 accessible pour les échanges SMTP entrants, 465 en TLS implicite pour les clients, 587 en STARTTLS pour la soumission, et 993 en TLS implicite pour IMAP. Le certificat doit correspondre exactement au nom utilisé par le MX et par les clients, idéalement mail.yannig.net plutÎt que le domaine nu si votre MX pointe vers ce nom.
Script vérification multi-domaines
Enregistrement MX directement vers yannig.net. est valide dans votre cas, puisque le domaine possĂšde lui-mĂȘme les enregistrements A et AAAA. Le certificat TLS prĂ©sentĂ© sur les ports 465 et 993 devra donc contenir yannig.net dans son SAN, et non obligatoirement mail.yannig.net.
Le script ci-dessous vérifie le DNS, le reverse DNS, les ports IPv4/IPv6, les certificats TLS, SMTP, IMAP, SPF, DMARC et DKIM si vous fournissez le sélecteur DKIM. Il reprend vos adresses 51.38.37.240 et 2001:41d0:305:2100::c1c.
Il faut maintenant distinguer le serveur de transport commun (yannig.net) des trois domaines signés. Le MX peut rester identique pour les trois domaines :
1
2
3
yannig.net. MX 10 yannig.net.
cinay.eu. MX 10 yannig.net.
yick.eu. MX 10 yannig.net.
Les six sĂ©lecteurs DKIM doivent ĂȘtre testĂ©s indĂ©pendamment. Pour DKIM, ed25519 et rsa sont indiquĂ©s dans le champ k= ; le terme « SHA-256 » correspond Ă lâalgorithme de signature, pas au type de clĂ© DNS. Le type Ed25519 est officiellement identifiĂ© par k=ed25519.rfc-editor
Ce script vérifie :
- les enregistrements
A,AAAAetMX; - les reverse DNS IPv4/IPv6 ;
- SPF et DMARC pour les trois domaines ;
- les deux sélecteurs DKIM de chaque domaine ;
- le type de clé
ed25519oursa; - les ports
25,465,587et993; - TLS implicite sur
465et993; - STARTTLS sur
25et587; - les capacités SMTP et IMAP ;
- la correspondance du certificat avec
yannig.net.Script complet
Enregistrez-le dans check-stalwart-multi-domain.sh :
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
#!/usr/bin/env bash
set -u
set -o pipefail
readonly MAIL_HOST="yannig.net"
readonly EXPECTED_IPV4="51.38.37.240"
readonly EXPECTED_IPV6="2001:41d0:305:2100::c1c"
readonly SMTP_PORT=25
readonly SMTPS_PORT=465
readonly SUBMISSION_PORT=587
readonly IMAPS_PORT=993
readonly REPORT_DIR="./stalwart-report-$(date +%Y%m%d-%H%M%S)"
readonly REPORT_FILE="$REPORT_DIR/report.txt"
readonly DOMAINS=(
"yannig.net"
"cinay.eu"
"yick.eu"
)
declare -A DKIM_SELECTORS=(
["yannig.net"]="v1-ed25519-20260720 v1-rsa-20260720"
["cinay.eu"]="v1-ed25519-20260723 v1-rsa-20260723"
["yick.eu"]="v1-ed25519-20260722 v1-rsa-20260722"
)
mkdir -p "$REPORT_DIR"
touch "$REPORT_FILE"
PASS=0
WARN=0
FAIL=0
GREEN=$'\033[32m'
YELLOW=$'\033[33m'
RED=$'\033[31m'
BLUE=$'\033[34m'
RESET=$'\033[0m'
log() {
local level="$1"
shift
local message="$*"
case "$level" in
PASS)
printf '%b[PASS]%b %s\n' "$GREEN" "$RESET" "$message"
printf '[PASS] %s\n' "$message" >>"$REPORT_FILE"
PASS=$((PASS + 1))
;;
WARN)
printf '%b[WARN]%b %s\n' "$YELLOW" "$RESET" "$message"
printf '[WARN] %s\n' "$message" >>"$REPORT_FILE"
WARN=$((WARN + 1))
;;
FAIL)
printf '%b[FAIL]%b %s\n' "$RED" "$RESET" "$message"
printf '[FAIL] %s\n' "$message" >>"$REPORT_FILE"
FAIL=$((FAIL + 1))
;;
INFO)
printf '%b[INFO]%b %s\n' "$BLUE" "$RESET" "$message"
printf '[INFO] %s\n' "$message" >>"$REPORT_FILE"
;;
esac
}
section() {
printf '\n===== %s =====\n' "$1" | tee -a "$REPORT_FILE"
}
require_command() {
if ! command -v "$1" >/dev/null 2>&1; then
log FAIL "Commande manquante : $1"
return 1
fi
}
dns_short() {
local type="$1"
local name="$2"
dig +short "$name" "$type" 2>/dev/null
}
check_dns_domain() {
local domain="$1"
local a aaaa mx txt spf dmarc
section "DNS $domain"
a="$(dns_short A "$domain")"
aaaa="$(dns_short AAAA "$domain")"
mx="$(dns_short MX "$domain")"
txt="$(dns_short TXT "$domain")"
spf="$(grep -i 'v=spf1' <<<"$txt" || true)"
dmarc="$(dns_short TXT "_dmarc.$domain")"
{
echo "[$domain]"
echo "A:"
echo "$a"
echo "AAAA:"
echo "$aaaa"
echo "MX:"
echo "$mx"
echo "TXT:"
echo "$txt"
echo "SPF:"
echo "$spf"
echo "DMARC:"
echo "$dmarc"
} >>"$REPORT_FILE"
if [[ "$domain" == "$MAIL_HOST" ]]; then
if grep -Fxq "$EXPECTED_IPV4" <<<"$a"; then
log PASS "$domain : A = $EXPECTED_IPV4"
else
log FAIL "$domain : A différent de $EXPECTED_IPV4"
fi
if grep -Fxq "$EXPECTED_IPV6" <<<"$aaaa"; then
log PASS "$domain : AAAA = $EXPECTED_IPV6"
else
log FAIL "$domain : AAAA différent de $EXPECTED_IPV6"
fi
fi
if grep -Eq '(^|[[:space:]])10[[:space:]]+yannig\.net\.?$|yannig\.net\.$' <<<"$mx"; then
log PASS "$domain : MX vers yannig.net"
else
log FAIL "$domain : MX inattendu : ${mx//$'\n'/ }"
fi
local spf_count
spf_count="$(grep -ci 'v=spf1' <<<"$txt" || true)"
if [[ "$spf_count" -eq 1 ]]; then
log PASS "$domain : un unique SPF détecté"
elif [[ "$spf_count" -eq 0 ]]; then
log FAIL "$domain : SPF absent"
else
log FAIL "$domain : plusieurs SPF détectés ($spf_count)"
fi
if grep -q 'v=DMARC1' <<<"$dmarc"; then
log PASS "$domain : DMARC détecté"
else
log FAIL "$domain : DMARC absent ou invalide"
fi
}
check_dkim_domain() {
local domain="$1"
local selectors="${DKIM_SELECTORS[$domain]}"
local selector record expected_type
section "DKIM $domain"
for selector in $selectors; do
record="$(dns_short TXT "${selector}._domainkey.${domain}")"
printf '[DKIM] %s._domainkey.%s\n%s\n' \
"$selector" "$domain" "$record" >>"$REPORT_FILE"
if [[ -z "$record" ]]; then
log FAIL "$domain / $selector : enregistrement DKIM absent"
continue
fi
if ! grep -q 'v=DKIM1' <<<"$record"; then
log FAIL "$domain / $selector : v=DKIM1 absent"
else
log PASS "$domain / $selector : v=DKIM1 présent"
fi
if ! grep -q 'p=[A-Za-z0-9+/=]' <<<"$record"; then
log FAIL "$domain / $selector : clé publique p= absente"
else
log PASS "$domain / $selector : clé publique présente"
fi
if [[ "$selector" == *ed25519* ]]; then
expected_type="ed25519"
elif [[ "$selector" == *rsa* ]]; then
expected_type="rsa"
else
expected_type=""
fi
if [[ -n "$expected_type" ]]; then
if grep -Eiq "k[[:space:]]*=[[:space:]]*$expected_type" <<<"$record"; then
log PASS "$domain / $selector : type k=$expected_type confirmé"
else
log WARN "$domain / $selector : le sélecteur suggÚre k=$expected_type, mais le DNS ne le confirme pas"
fi
fi
done
}
check_reverse_dns() {
section "REVERSE DNS"
local ptr4 ptr6
ptr4="$(dig -x "$EXPECTED_IPV4" PTR +short | sed 's/\.$//' | head -n1)"
ptr6="$(dig -x "$EXPECTED_IPV6" PTR +short | sed 's/\.$//' | head -n1)"
if [[ -n "$ptr4" ]]; then
log PASS "PTR IPv4 : $EXPECTED_IPV4 -> $ptr4"
if dig +short A "$ptr4" | grep -Fxq "$EXPECTED_IPV4"; then
log PASS "PTR IPv4 confirmé par résolution directe"
else
log WARN "Le PTR IPv4 ne revient pas vers $EXPECTED_IPV4"
fi
else
log FAIL "PTR IPv4 absent pour $EXPECTED_IPV4"
fi
if [[ -n "$ptr6" ]]; then
log PASS "PTR IPv6 : $EXPECTED_IPV6 -> $ptr6"
if dig +short AAAA "$ptr6" | grep -Fxq "$EXPECTED_IPV6"; then
log PASS "PTR IPv6 confirmé par résolution directe"
else
log WARN "Le PTR IPv6 ne revient pas vers $EXPECTED_IPV6"
fi
else
log WARN "PTR IPv6 absent pour $EXPECTED_IPV6"
fi
}
check_port() {
local family="$1"
local port="$2"
local label="$3"
if timeout 8 nc "$family" -zv "$MAIL_HOST" "$port" \
>>"$REPORT_FILE" 2>&1; then
log PASS "$label : $MAIL_HOST:$port accessible"
else
log FAIL "$label : $MAIL_HOST:$port inaccessible"
fi
}
check_ports() {
section "PORTS TCP"
check_port -4 "$SMTP_PORT" "IPv4 SMTP"
check_port -6 "$SMTP_PORT" "IPv6 SMTP"
check_port -4 "$SMTPS_PORT" "IPv4 SMTPS"
check_port -6 "$SMTPS_PORT" "IPv6 SMTPS"
check_port -4 "$SUBMISSION_PORT" "IPv4 Submission"
check_port -6 "$SUBMISSION_PORT" "IPv6 Submission"
check_port -4 "$IMAPS_PORT" "IPv4 IMAPS"
check_port -6 "$IMAPS_PORT" "IPv6 IMAPS"
}
check_tls() {
local family="$1"
local port="$2"
local mode="$3"
local label="$4"
local output
local family_option
family_option="$family"
if [[ "$mode" == "implicit" ]]; then
output="$(
timeout 15 openssl s_client \
"$family_option" \
-connect "$MAIL_HOST:$port" \
-servername "$MAIL_HOST" \
-verify_return_error \
-brief </dev/null 2>&1
)"
else
output="$(
timeout 15 openssl s_client \
"$family_option" \
-connect "$MAIL_HOST:$port" \
-servername "$MAIL_HOST" \
-starttls smtp \
-verify_return_error \
-brief </dev/null 2>&1
)"
fi
printf '\n[%s]\n%s\n' "$label" "$output" >>"$REPORT_FILE"
if grep -q 'Verification: OK' <<<"$output"; then
log PASS "$label : certificat validé"
elif grep -qE 'CONNECTION ESTABLISHED|CONNECTED|New, TLS' <<<"$output"; then
log WARN "$label : TLS actif, mais validation complÚte non confirmée"
else
log FAIL "$label : échec TLS"
fi
if grep -qiE 'TLSv1\.[23]' <<<"$output"; then
log PASS "$label : TLS 1.2 ou TLS 1.3 négocié"
fi
}
check_tls_all() {
section "TLS"
check_tls -4 "$SMTPS_PORT" implicit "IPv4 SMTPS 465"
check_tls -6 "$SMTPS_PORT" implicit "IPv6 SMTPS 465"
check_tls -4 "$IMAPS_PORT" implicit "IPv4 IMAPS 993"
check_tls -6 "$IMAPS_PORT" implicit "IPv6 IMAPS 993"
check_tls -4 "$SMTP_PORT" starttls "IPv4 SMTP STARTTLS 25"
check_tls -6 "$SMTP_PORT" starttls "IPv6 SMTP STARTTLS 25"
check_tls -4 "$SUBMISSION_PORT" starttls "IPv4 Submission STARTTLS 587"
check_tls -6 "$SUBMISSION_PORT" starttls "IPv6 Submission STARTTLS 587"
}
check_smtp() {
local family="$1"
local port="$2"
local label="$3"
local output
output="$(
timeout 12 openssl s_client \
"$family" \
-connect "$MAIL_HOST:$port" \
-servername "$MAIL_HOST" \
-quiet \
-crlf 2>/dev/null <<'EOF'
EHLO check.yannig.net
QUIT
EOF
)"
printf '\n[%s]\n%s\n' "$label" "$output" >>"$REPORT_FILE"
if grep -qiE '220 |250[- ]' <<<"$output"; then
log PASS "$label : réponse SMTP reçue"
else
log WARN "$label : réponse SMTP non détectée"
fi
}
check_imap() {
local family="$1"
local label="$2"
local output
output="$(
timeout 12 openssl s_client \
"$family" \
-connect "$MAIL_HOST:$IMAPS_PORT" \
-servername "$MAIL_HOST" \
-quiet \
-crlf 2>/dev/null <<'EOF'
a001 CAPABILITY
a002 LOGOUT
EOF
)"
printf '\n[%s]\n%s\n' "$label" "$output" >>"$REPORT_FILE"
if grep -qiE 'CAPABILITY|IMAP4' <<<"$output"; then
log PASS "$label : réponse IMAP reçue"
else
log FAIL "$label : réponse IMAP absente"
fi
}
check_protocols() {
section "PROTOCOLES"
check_smtp -4 "$SMTPS_PORT" "SMTP TLS IPv4 465"
check_smtp -6 "$SMTPS_PORT" "SMTP TLS IPv6 465"
check_imap -4 "IMAP TLS IPv4 993"
check_imap -6 "IMAP TLS IPv6 993"
}
check_certificate_names() {
section "CERTIFICAT"
local output san
output="$(
timeout 15 openssl s_client \
-connect "$MAIL_HOST:$SMTPS_PORT" \
-servername "$MAIL_HOST" \
-showcerts </dev/null 2>/dev/null |
openssl x509 -noout -subject -issuer -dates -ext subjectAltName 2>/dev/null
)"
printf '%s\n' "$output" >>"$REPORT_FILE"
san="$(grep -o 'DNS:[^, ]*' <<<"$output" || true)"
if grep -q "DNS:$MAIL_HOST" <<<"$san"; then
log PASS "Le certificat contient DNS:$MAIL_HOST"
else
log FAIL "Le certificat ne contient pas DNS:$MAIL_HOST"
fi
if grep -q 'notAfter' <<<"$output"; then
log INFO "Dates du certificat enregistrées dans le rapport"
fi
}
summary() {
section "RĂSUMĂ"
log INFO "Rapport : $REPORT_FILE"
log INFO "PASS=$PASS WARN=$WARN FAIL=$FAIL"
if [[ "$FAIL" -eq 0 ]]; then
log PASS "Aucune erreur bloquante détectée"
return 0
fi
log FAIL "$FAIL erreur(s) Ă corriger"
return 1
}
main() {
section "PARAMĂTRES"
log INFO "Serveur MX : $MAIL_HOST"
log INFO "IPv4 : $EXPECTED_IPV4"
log INFO "IPv6 : $EXPECTED_IPV6"
log INFO "Domaines : ${DOMAINS[*]}"
log INFO "Date : $(date --iso-8601=seconds)"
local command
for command in dig openssl nc timeout; do
require_command "$command" || exit 2
done
local domain
for domain in "${DOMAINS[@]}"; do
check_dns_domain "$domain"
check_dkim_domain "$domain"
done
check_reverse_dns
check_ports
check_tls_all
check_protocols
check_certificate_names
summary
}
main "$@"
Exécution
1
2
chmod +x check-stalwart-multi-domain.sh
./check-stalwart-multi-domain.sh
Le rapport sera généré dans un répertoire de ce type :
1
stalwart-report-20260813-063200/report.txt
Enregistrements DKIM testés
Le script interrogera automatiquement les noms DNS suivants :
1
2
3
4
5
6
7
8
v1-ed25519-20260720._domainkey.yannig.net
v1-rsa-20260720._domainkey.yannig.net
v1-ed25519-20260723._domainkey.cinay.eu
v1-rsa-20260723._domainkey.cinay.eu
v1-ed25519-20260722._domainkey.yick.eu
v1-rsa-20260722._domainkey.yick.eu
Les enregistrements attendus doivent ressembler Ă ceci :
v1-ed25519-20260720._domainkey.yannig.net. TXT "v=DKIM1; k=ed25519; p=..."
v1-rsa-20260720._domainkey.yannig.net. TXT "v=DKIM1; k=rsa; p=..."
Les champs p= contiennent uniquement les clĂ©s publiques. Les clĂ©s privĂ©es doivent rester dans Stalwart et ne doivent jamais ĂȘtre publiĂ©es dans le DNS. Le format DNS dâun enregistrement DKIM utilise le sĂ©lecteur suivi de ._domainkey, avec v=DKIM1, k= et p=.[^2]
SPF recommandé
Chaque domaine envoyant directement via le serveur yannig.net devrait autoriser les deux adresses du serveur :
yannig.net. TXT "v=spf1 ip4:51.38.37.240 ip6:2001:41d0:305:2100::c1c mx -all"
cinay.eu. TXT "v=spf1 ip4:51.38.37.240 ip6:2001:41d0:305:2100::c1c mx -all"
yick.eu. TXT "v=spf1 ip4:51.38.37.240 ip6:2001:41d0:305:2100::c1c mx -all"
Ne publiez quâun seul enregistrement v=spf1 par domaine.
Point à vérifier dans Stalwart
Lors de la rotation automatique des clés :
- les anciennes clés doivent rester publiées pendant la durée de validité des messages déjà envoyés ;
- la nouvelle clé privée doit correspondre exactement à la clé publique DNS ;
- Stalwart doit signer avec le nouveau sélecteur ;
- lâancien sĂ©lecteur ne doit ĂȘtre retirĂ© du DNS quâaprĂšs expiration des anciens messages ;
- les en-tĂȘtes des messages doivent contenir le bon couple
d=ets=.
Dans un message envoyé, vérifiez par exemple :
1
2
3
DKIM-Signature:
d=yannig.net;
s=v1-ed25519-20260720;
ou :
1
2
3
DKIM-Signature:
d=cinay.eu;
s=v1-rsa-20260723;
Le d= doit correspondre au domaine expĂ©diteur et le s= Ă lâun des sĂ©lecteurs actuellement publiĂ©s.
Niveau de SPAM ?
un moyen de tester le niveau de spam accepté par le domaine
Il faut distinguer deux notions :
- La rĂ©putation de vos domaines/IP pour les messages sortants : risque dâarriver dans le spam chez Gmail, Outlook, etc.
- Le filtrage des messages entrants par Stalwart : quantité de spam acceptée, rejetée ou classée en quarantaine.
Il nâexiste pas un score public unique indiquant « le niveau de spam acceptĂ© » par yannig.net, cinay.eu ou yick.eu.
Tester la réputation sortante
1. Mail-Tester
Utilisez Mail-Tester :
- Ouvrez le site.
- Copiez lâadresse temporaire fournie.
- Envoyez un message depuis chacun de vos domaines :
test@yannig.nettest@cinay.eutest@yick.eu
- Analysez séparément les résultats.
Cela vérifie notamment :
- SPF ;
- DKIM ;
- DMARC ;
- reverse DNS ;
- rĂ©putation de lâIP ;
- présence éventuelle dans des listes noires ;
- contenu du message ;
- score SpamAssassin.
Le test doit ĂȘtre rĂ©alisĂ© avec un vĂ©ritable message envoyĂ© par Stalwart, pas avec un simple message composĂ© localement.
Avec swaks :
1
2
3
4
5
6
7
8
swaks \
--server yannig.net \
--port 465 \
--tls \
--auth LOGIN \
--auth-user test@yannig.net \
--to ADRESSE_MAIL_TESTER \
--from test@yannig.net
Répétez avec :
1
--auth-user test@cinay.eu --from test@cinay.eu
puis :
1
--auth-user test@yick.eu --from test@yick.eu
Nâutilisez pas votre compte administrateur.
2. Vérification des listes noires
Testez les adresses suivantes :
Testez au minimum :
1
2
3
4
yannig.net
cinay.eu
yick.eu
51.38.37.240
Spamhaus prĂ©cise que la rĂ©putation dâun domaine dĂ©pend notamment de son historique dâutilisation, de son comportement dâenvoi et des signalements associĂ©s.
Attention : une IP propre ne garantit pas que les messages arriveront en boĂźte principale. Gmail et Outlook utilisent Ă©galement lâengagement des destinataires, les plaintes, le contenu, les volumes et lâhistorique.
Mesurer la réputation chez Gmail
Pour un domaine qui envoie réguliÚrement vers Gmail, utilisez Google Postmaster Tools.
Google y expose notamment :
- le taux de messages signalés comme spam ;
- les résultats SPF, DKIM et DMARC ;
- les erreurs de livraison ;
- la rĂ©putation de lâIP et du domaine, lorsque suffisamment de donnĂ©es sont disponibles.
Google indique que Postmaster Tools exploite les messages authentifiĂ©s par DKIM, ou SPF si DKIM nâest pas disponible, pour afficher les donnĂ©es de rĂ©putation.
Ajoutez et vérifiez les trois domaines :
1
2
3
yannig.net
cinay.eu
yick.eu
Le domaine doit normalement avoir un volume suffisant de messages vers des comptes Gmail personnels avant que les statistiques soient disponibles. Avec un faible trafic, lâabsence de donnĂ©es ne signifie pas que la rĂ©putation est mauvaise.
Pour un envoi important vers Gmail, Google demande une authentification correcte et recommande de maintenir le taux de plaintes trÚs bas ; les exigences spécifiques aux expéditeurs de gros volume sont détaillées dans ses directives officielles.
Tester concrĂštement le classement en spam
Créez une matrice de test avec plusieurs fournisseurs :
| Fournisseur | Adresse de destination |
|---|---|
| Gmail | compte Gmail personnel |
| Outlook | compte Outlook.com |
| Yahoo | compte Yahoo |
| Proton Mail | compte Proton Mail |
| Mail-Tester | adresse temporaire |
| Votre propre domaine | boĂźte locale de test |
Pour chaque domaine, envoyez un message identique :
1
2
3
4
5
From: test@yannig.net
To: compte-de-test@gmail.com
Subject: Test délivrabilité yannig.net
Message de test de délivrabilité.
RĂ©pĂ©tez avec cinay.eu et yick.eu, puis contrĂŽlez les en-tĂȘtes complets du message :
1
2
3
4
Authentication-Results:
spf=pass
dkim=pass
dmarc=pass
à vérifier aussi :
1
2
3
DKIM-Signature:
d=yannig.net;
s=v1-ed25519-20260720;
ou :
1
2
3
DKIM-Signature:
d=cinay.eu;
s=v1-rsa-20260723;
Un message qui arrive en spam malgrĂ© spf=pass, dkim=pass et dmarc=pass peut simplement souffrir dâune mauvaise rĂ©putation, dâun contenu douteux, dâun volume inhabituel ou dâun manque dâhistorique.
Tester le filtrage entrant de Stalwart
Pour mesurer ce que votre serveur accepte comme spam entrant, utilisez une boĂźte de test, par exemple :
1
spam-test@yannig.net
Envoyez-lui des messages de test depuis une adresse externe. Le plus pratique est dâutiliser des messages de catĂ©gories diffĂ©rentes :
- message normal ;
- message avec URL ;
- message contenant une piĂšce jointe ;
- message avec expéditeur non authentifié ;
- message avec SPF/DKIM/DMARC invalides ;
- message de test GTUBE.
Test GTUBE
GTUBE est une chaĂźne standard utilisĂ©e pour vĂ©rifier quâun moteur antispam dĂ©tecte un message de test. Ne lâenvoyez jamais Ă une vraie boĂźte utilisateur ou Ă une liste de diffusion.
Utilisez une boßte dédiée, puis envoyez le contenu suivant dans le corps du message :
1
XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X
Exemple avec swaks depuis une machine externe :
1
2
3
4
5
6
7
8
9
10
swaks \
--server yannig.net \
--port 465 \
--tls \
--auth LOGIN \
--auth-user test@yannig.net \
--to spam-test@yannig.net \
--from test@externe.example \
--header "Subject: GTUBE test - ne pas supprimer" \
--body 'XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X'
Le résultat attendu dépend de votre configuration Stalwart :
- rejet SMTP immédiat ;
- acceptation avec classement spam ;
- déplacement en quarantaine ;
- ajout dâun en-tĂȘte indiquant le score antispam ;
- acceptation normale si le filtre nâest pas activĂ©.
Surveillez les journaux pendant le test :
1
sudo journalctl -fu stalwart
Avec Docker :
1
docker compose logs -f --tail=200 stalwart
Recherchez ensuite les éléments suivants :
1
2
docker compose logs stalwart |
grep -Ei 'spam|score|quarantine|reject|gtube|dkim|spf|dmarc'
Le test GTUBE vérifie surtout que le moteur antispam réagit bien à un motif connu. Il ne mesure pas à lui seul la qualité globale du filtrage.
ContrĂŽle rapide des en-tĂȘtes entrants
Pour voir si un message a été classé par Stalwart, utilisez :
1
2
3
grep -Ei \
'Authentication-Results|X-Spam|X-Rspamd|X-Spam-Status|Subject|Received' \
message.eml
Les noms exacts des en-tĂȘtes dĂ©pendent de votre configuration. Vous pouvez notamment rechercher :
1
2
3
4
X-Spam-Status
X-Spam-Score
X-Spam-Level
Authentication-Results
Test automatisé simple
Voici un petit script qui envoie un message de contrĂŽle vers une boĂźte externe Ă lâaide de swaks. Il ne teste pas directement le classement spam, mais permet de suivre les rĂ©sultats de livraison et les en-tĂȘtes dâauthentification.
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
#!/usr/bin/env bash
set -u
SMTP_HOST="yannig.net"
SMTP_PORT=465
TEST_DESTINATION="${1:?Usage: $0 adresse-de-test@example.net}"
declare -A SENDERS=(
["yannig.net"]="test@yannig.net"
["cinay.eu"]="test@cinay.eu"
["yick.eu"]="test@yick.eu"
)
for domain in "${!SENDERS[@]}"; do
sender="${SENDERS[$domain]}"
echo
echo "===== Test $domain ====="
echo "Expéditeur : $sender"
echo "Destination : $TEST_DESTINATION"
swaks \
--server "$SMTP_HOST" \
--port "$SMTP_PORT" \
--tls \
--auth LOGIN \
--auth-user "$sender" \
--to "$TEST_DESTINATION" \
--from "$sender" \
--header "Subject: Test délivrabilité $domain" \
--header "X-Mail-Test-Domain: $domain" \
--body "Test de délivrabilité envoyé depuis $domain."
done
Exécution :
1
2
chmod +x test-deliverability.sh
./test-deliverability.sh votre-compte-gmail@gmail.com
Pour un rĂ©sultat fiable, faites plusieurs essais espacĂ©s dans le temps et observez les mĂȘmes messages dans Gmail, Outlook et Proton Mail. Le meilleur indicateur pratique pour vos trois domaines sera la combinaison suivante : SPF=pass, DKIM=pass, DMARC=pass, reverse DNS cohĂ©rent, aucune blacklist, puis placement rĂ©el en boĂźte principale chez plusieurs fournisseurs.