Integration¶
Le service de messagerie interagit avec de nombreux composants de l'infrastructure. Ce chapitre detaille les integrations cles.
Integration IAM : LDAP et OIDC avec Keycloak¶
Provisioning des utilisateurs via LDAP¶
Keycloak expose un annuaire LDAP (ou s'interface avec FreeIPA). Stalwart interroge cet annuaire pour résoudre les comptes email :
graph LR
Stalwart["Stalwart"] -->|LDAPS:636<br/>Recherche user<br/>Verification pwd| Keycloak["Keycloak<br/>(LDAP)"]
Keycloak --> FreeIPA["FreeIPA /<br/>base users"] Configuration LDAP détaillée¶
# /opt/stalwart/config/config.toml
[directory.ldap]
type = "ldap"
url = "ldaps://iam.enterprise.internal.company.io:636"
base-dn = "dc=company,dc=io"
timeout = "10s"
[directory.ldap.bind]
dn = "cn=stalwart,ou=services,dc=company,dc=io"
secret = "%{env:LDAP_BIND_PASSWORD}%"
[directory.ldap.filter]
name = "(&(objectClass=inetOrgPerson)(uid=?))"
email = "(&(objectClass=inetOrgPerson)(|(mail=?)(mailAlias=?)))"
verify = "(&(objectClass=inetOrgPerson)(|(mail=?)(mailAlias=?)))"
expand = "(&(objectClass=groupOfNames)(mail=?))"
domains = "(&(objectClass=domain)(dc=?))"
[directory.ldap.attributes]
name = "uid"
class = "objectClass"
description = "cn"
secret = "userPassword"
email = "mail"
email-alias = "mailAlias"
quota = "mailQuota"
groups = "memberOf"
Attributs LDAP requis dans Keycloak¶
| Attribut LDAP | Type | Exemple | Usage Stalwart |
|---|---|---|---|
uid | Requis | alice | Identifiant de connexion |
mail | Requis | alice@company.io | Adresse email principale |
mailAlias | Optionnel | a.dupont@company.io | Alias email |
mailQuota | Optionnel | 5368709120 (5 Go en octets) | Quota de la boite |
memberOf | Auto | cn=dev,ou=groups,... | Appartenance aux groupes |
SSO webmail via OIDC¶
Pour permettre l'accès au webmail ou a JMAP sans re-saisie du mot de passe :
[directory.oidc]
type = "oidc"
issuer-url = "https://iam.enterprise.internal.company.io/realms/company"
client-id = "stalwart-mail"
client-secret = "%{env:OIDC_CLIENT_SECRET}%"
scope = "openid email profile"
Configuration du client OIDC dans Keycloak¶
| Parametre | Valeur |
|---|---|
| Client ID | stalwart-mail |
| Client Protocol | openid-connect |
| Access Type | confidential |
| Valid Redirect URIs | https://mail.company.io/* |
| Web Origins | https://mail.company.io |
| Standard Flow Enabled | On |
| Direct Access Grants | On (pour les clients IMAP/SMTP legacy) |
Flux d'authentification¶
sequenceDiagram
participant U as Utilisateur
participant W as Webmail/JMAP
participant S as Stalwart
participant K as Keycloak
U->>W: Acces webmail
W->>S: Redirect OIDC
S->>K: AuthZ request
K->>U: Page de login Keycloak
U->>K: Identifiants
K->>U: Code d'autorisation
S->>K: Token request
K->>S: JWT token
S->>W: Session JMAP
W->>U: Webmail charge Integration DNS via CoreDNS¶
Enregistrements MX dans les zones internes¶
Pour le routage des emails internes (entre services), ajouter les enregistrements MX dans la zone interne :
; Zone enterprise.internal.company.io
; Serveur de messagerie interne
enterprise.internal.company.io. 300 IN MX 10 mail.enterprise.internal.company.io.
mail.enterprise.internal.company.io. 300 IN A 10.20.1.30
; Autoconfig interne
autoconfig.enterprise.internal.company.io. 300 IN CNAME mail.enterprise.internal.company.io.
Split-horizon pour le mail¶
Le DNS interne résout mail.company.io vers l'IP privee, evitant le NAT hairpin :
; Vue interne (CoreDNS)
mail.company.io. 300 IN A 10.20.1.30
; Vue externe (DNS public)
mail.company.io. 300 IN A 203.0.113.10
Monitoring avec Prometheus et Grafana¶
Metriques exposees par Stalwart¶
Stalwart expose des metriques Prometheus sur le endpoint HTTP :
Metriques principales :
| Metrique | Type | Description |
|---|---|---|
mail_incoming_total | Counter | Nombre total d'emails reçus |
mail_outgoing_total | Counter | Nombre total d'emails envoyes |
mail_delivery_total | Counter | Livraisons reussies/échouées |
mail_queue_size | Gauge | Nombre d'emails en file d'attente |
mail_queue_age_seconds | Histogram | Âge des emails dans la queue |
mail_spam_total | Counter | Emails détectés comme spam |
mail_dkim_verify_total | Counter | Verifications DKIM (pass/fail) |
mail_dmarc_verify_total | Counter | Verifications DMARC (pass/fail) |
mail_tls_total | Counter | Connexions TLS (succès/echec) |
mail_auth_total | Counter | Authentifications (succès/echec) |
mail_connections_active | Gauge | Connexions SMTP/IMAP actives |
mail_storage_used_bytes | Gauge | Stockage utilise par les boites |
Configuration Prometheus¶
# prometheus.yml
scrape_configs:
- job_name: "stalwart-mail"
scrape_interval: 30s
static_configs:
- targets: ["mail.enterprise.internal.company.io:8080"]
metrics_path: /metrics
Dashboard Grafana¶
Les panneaux essentiels pour un dashboard de messagerie :
| Panneau | Metrique | Type | Seuil d'alerte |
|---|---|---|---|
| Emails reçus/min | rate(mail_incoming_total[5m]) | Graph | — |
| Emails envoyes/min | rate(mail_outgoing_total[5m]) | Graph | — |
| Taille de la queue | mail_queue_size | Gauge | > 100 (warning) |
| Taux de livraison | rate(mail_delivery_total{status="success"}[1h]) / rate(mail_delivery_total[1h]) | Gauge | < 95% (critical) |
| Ratio spam | rate(mail_spam_total[1h]) / rate(mail_incoming_total[1h]) | Gauge | > 50% (warning) |
| Echecs DKIM | rate(mail_dkim_verify_total{result="fail"}[1h]) | Graph | > 10% (warning) |
| Echecs TLS | rate(mail_tls_total{result="fail"}[1h]) | Graph | > 5% (warning) |
| Connexions actives | mail_connections_active | Gauge | > 500 (warning) |
| Stockage utilise | mail_storage_used_bytes | Gauge | > 80% capacité |
Regles d'alerte¶
# alerting-rules.yml
groups:
- name: mail-alerts
rules:
- alert: MailQueueBacklog
expr: mail_queue_size > 100
for: 15m
labels:
severity: warning
annotations:
summary: "File d'attente mail anormalement grande ({{ $value }} messages)"
- alert: MailQueueCritical
expr: mail_queue_size > 500
for: 5m
labels:
severity: critical
annotations:
summary: "File d'attente mail critique — {{ $value }} messages bloques"
- alert: MailDeliveryRateLow
expr: |
(
rate(mail_delivery_total{status="success"}[1h])
/ rate(mail_delivery_total[1h])
) < 0.95
for: 30m
labels:
severity: critical
annotations:
summary: "Taux de livraison sous 95% — probleme de deliverabilite"
- alert: MailQueueAgeTooOld
expr: histogram_quantile(0.95, mail_queue_age_seconds_bucket) > 3600
for: 10m
labels:
severity: warning
annotations:
summary: "Des emails sont en queue depuis plus d'une heure"
- alert: MailSpamRatioHigh
expr: |
rate(mail_spam_total[1h]) / rate(mail_incoming_total[1h]) > 0.5
for: 1h
labels:
severity: warning
annotations:
summary: "Plus de 50% du trafic entrant est du spam"
Integration CalDAV¶
Calendrier et contacts intégrés¶
Stalwart expose un serveur CalDAV/CardDAV natif sur le même endpoint HTTP :
| Endpoint | Protocole | Usage |
|---|---|---|
https://mail.company.io/.well-known/caldav | CalDAV | Découverte calendrier |
https://mail.company.io/.well-known/carddav | CardDAV | Découverte contacts |
https://mail.company.io/dav/ | WebDAV | Racine DAV |
Configuration des clients¶
| Client | Configuration CalDAV |
|---|---|
| Thunderbird | Auto-découverte via mail.company.io |
| Apple Calendar | Ajouter compte CalDAV mail.company.io |
| GNOME Calendar | Compte en ligne → Nextcloud/CalDAV |
| DAVx5 (Android) | URL: https://mail.company.io/.well-known/caldav |
Invitations par email (iMIP)¶
Stalwart traite automatiquement les invitations de calendrier reçues par email :
- Un email contenant un piece jointe
.ics(invitation) arrive - Stalwart détecte le format iCalendar
- L'invitation est ajoutee au calendrier CalDAV de l'utilisateur
- L'utilisateur peut accepter/refuser via son client CalDAV
- La réponse est envoyee par email a l'organisateur
Listes de diffusion¶
Configuration des listes dans Stalwart¶
Les listes de diffusion sont configurees comme des groupes dans l'annuaire LDAP ou via l'API :
# Creer une liste de diffusion
curl -X POST http://localhost:8080/api/principal \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"type": "list",
"name": "dev-team",
"emails": ["dev@company.io"],
"members": [
"alice@company.io",
"bob@company.io",
"charlie@company.io"
]
}'
Types de listes¶
| Type | Configuration | Comportement |
|---|---|---|
| Discussion | type: list | Tous les membres peuvent poster |
| Announce | type: list + ACL de soumission | Seuls les admins peuvent poster |
| Alias | type: alias | Simple redirection, pas de list headers |
En-têtes de liste¶
Stalwart ajoute automatiquement les en-têtes de liste standards :
List-Id: <dev.company.io>
List-Post: <mailto:dev@company.io>
List-Unsubscribe: <mailto:dev+unsubscribe@company.io>
List-Archive: <https://lists.company.io/dev/>
Integration LDAP pour les listes¶
Les groupes LDAP peuvent etre mappes directement en listes de diffusion :
[directory.ldap.filter]
expand = "(&(objectClass=groupOfNames)(mail=?))"
[directory.ldap.attributes]
members = "member"
Un groupe LDAP cn=dev,ou=groups,dc=company,dc=io avec l'attribut mail=dev@company.io et des member=uid=alice,... sera automatiquement traite comme une liste de diffusion par Stalwart.
Synthese¶
L'integration de Stalwart dans l'ecosysteme d'infrastructure repose sur trois axes : l'IAM (LDAP pour les comptes, OIDC pour le SSO), l'observabilité (Prometheus/Grafana avec alertes sur la queue et la deliverabilite), et les services complementaires (CalDAV pour les calendriers, listes de diffusion via groupes LDAP). Le chapitre suivant traite de la confidentialite et de la protection des données transportees par email.