
Remplacer ForwardMX : redirection d’e-mails avec Kubernetes et LDAP
TL;DR : J'ai remplacé mon abonnement ForwardMX à 10€/mois par mon propre service de forwarding de mail, avec OpenLDAP et docker-mailserver sur mon cluster Kubernetes. Il m'a fallu quelques ajustements, mais maintenant je reçois et envoie des emails depuis
@oursi.net
directement depuis Gmail, gratuitement 🎉
🧠 Contexte
Quand j'ai acheté oursi.net
, je voulais :
- Recevoir les emails en
@oursi.net
directement sur mon compte Gmail - Pouvoir envoyer des emails depuis ce domaine aussi
- Éviter de créer et gérer des boîtes mail classiques
Au départ, j'utilisais ForwardMX, qui fonctionnait bien mais coûtait presque 10€/mois. C'est beaucoup pour quelques règles de redirection. J'ai donc décidé d'auto-héberger tout ça sur mon propre cluster Kubernetes.
Mon objectif était :
- Une configuration SMTP uniquement (sans boîte mail)
- Intégration complète à Gmail
- Authentification sécurisée + conformité SPF, DKIM, DMARC
🧹 Aperçu de la stack technique
- Cluster Kubernetes K3s (auto-hébergé sur un VPS)
- OpenLDAP pour la gestion des alias et utilisateurs
- Docker-Mailserver (DMS) pour le moteur SMTP
- MetalLB au lieu de ServiceLB pour conserver les IPs réelles
- Traefik pour le routage (avec Proxy Protocol v2)
- Teleport pour exposer les outils internes comme l'interface LDAP
1. Déployer OpenLDAP avec Helm
J'utilise le chart jp-gouin/helm-openldap.
Pourquoi LDAP ?
Parce qu'en mode SMTP-only, docker-mailserver fonctionne mieux avec LDAP pour :
- Déclarer des alias mails
- Gérer l'authentification SMTP
- Définir les adresses de redirection
Mon application ArgoCD pour OpenLDAP :
1apiVersion: argoproj.io/v1alpha1 2kind: Application 3metadata: 4 name: ldap 5 namespace: argocd 6 finalizers: 7 - resources-finalizer.argocd.argoproj.io 8spec: 9 project: default 10 source: 11 repoURL: https://jp-gouin.github.io/helm-openldap/ 12 chart: openldap-stack-ha 13 targetRevision: 4.3.3 14 helm: 15 values: | 16 replicaCount: 1 17 global: 18 # Replace with your domain below 19 ldapDomain: oursi.net 20 replication: 21 # I disable replication because I don't need HA 22 enabled: false 23 24 ltb-passwd: 25 ingress: 26 enabled: false 27 28 ldap: 29 # This will restrict password update for mail forwarding users only 30 searchBase: "ou=mail,dc=oursi,dc=net" 31 32 phpldapadmin: 33 ingress: 34 enabled: false 35 36 customLdifFiles: 37 00-root.ldif: |- 38 # Root creation, adapt to your domain 39 dn: dc=oursi,dc=net 40 objectClass: dcObject 41 objectClass: organization 42 o: Oursi.net 43 44 01-mailserver-member.ldif: |- 45 # Creating the mailserver user, that will be used by postfix to connect to ldap. 46 # The userPassword will need to be updated in phpldapadmin for instance 47 dn: cn=mailserver,dc=oursi,dc=net 48 objectClass: inetOrgPerson 49 objectClass: top 50 cn: mailserver 51 sn: Postfix 52 userPassword: {SSHA}x 53 description: User for querying mail entries 54 55 02-mail-group.ldif: |- 56 # Mail group creation, that's where I will define all the users for postfix 57 dn: ou=mail,dc=oursi,dc=net 58 objectClass: organizationalUnit 59 objectClass: top 60 ou: mail 61 description: Mail organizational unit 62 63 03-benoit-user.ldif: |- 64 # A sample postfix user, 65 dn: uid=sample@oursi.net,ou=mail,dc=oursi,dc=net 66 objectClass: inetOrgPerson 67 objectClass: top 68 objectClass: postfixUser 69 uid: sample@oursi.net 70 cn: Sample User 71 givenName: Sample 72 sn: User 73 mail: sample@oursi.net 74 userPassword: {SSHA}x 75 mailacceptinggeneralid: sample@oursi.net 76 mailacceptinggeneralid: sample.user@oursi.net 77 maildrop: sample.redirect@gmail.com 78 79 # this is to grant access to mailserver to the list of users in mail 80 customAcls: |- 81 dn: olcDatabase={2}mdb,cn=config 82 changetype: modify 83 replace: olcAccess 84 olcAccess: {0}to * 85 by dn.exact=gidNumber=0+uidNumber=1001,cn=peercred,cn=external,cn=auth manage 86 by * break 87 olcAccess: {1}to dn.subtree="ou=mail,dc=oursi,dc=net" 88 by dn="cn=mailserver,dc=oursi,dc=net" read 89 by self read 90 by * break 91 olcAccess: {2}to attrs=userPassword,shadowLastChange 92 by self write 93 by dn="cn=admin,dc=oursi,dc=net" write 94 by dn="cn=mailserver,dc=oursi,dc=net" read 95 by anonymous auth 96 by * break 97 olcAccess: {3}to * 98 by dn="cn=admin,dc=oursi,dc=net" write 99 by self read 100 by * break 101 102 103 customSchemaFiles: 104 #enable memberOf ldap search functionality, users automagically track groups they belong to 105 00-memberof.ldif: |- 106 # Load memberof module 107 dn: cn=module,cn=config 108 cn: module 109 objectClass: olcModuleList 110 olcModuleLoad: memberof 111 olcModulePath: /opt/bitnami/openldap/lib/openldap 112 113 dn: olcOverlay=memberof,olcDatabase={2}mdb,cn=config 114 changetype: add 115 objectClass: olcOverlayConfig 116 objectClass: olcMemberOf 117 olcOverlay: memberof 118 olcMemberOfRefint: TRUE 119 120 01-postfix.ldif: |- 121 # Postfix creation: the users we create are also of class postfix, it allows for attributes maildrop and mailacceptinggeneralid 122 dn: cn=postfix,cn=schema,cn=config 123 cn: postfix 124 objectclass: olcSchemaConfig 125 olcattributetypes: {0}(1.3.6.1.4.1.4203.666.1.200 NAME 'mailacceptinggeneralid' DESC 'Postfix mail local address alias attribute' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024}) 126 olcattributetypes: {1}(1.3.6.1.4.1.4203.666.1.201 NAME 'maildrop' DESC 'Postfix mail final destination attribute' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024}) 127 olcobjectclasses: {0}(1.3.6.1.4.1.4203.666.1.100 NAME 'postfixUser' DESC 'Postfix mail user class' SUP top AUXILIARY MAY(mailacceptinggeneralid $ maildrop)) 128 129 destination: 130 server: https://kubernetes.default.svc 131 namespace: ldap 132 syncPolicy: 133 automated: 134 prune: true 135 selfHeal: true 136 syncOptions: 137 - CreateNamespace=true
Cela déploie aussi :
phpldapadmin
— interface web pour explorer LDAPltb-passwd
— outil web pour changer les mots de passe
Beaucoup de paramètres dans cette config, mais principalement tout est fait pour préparer les éléments principaux dont on aura besoin avec LDAP :
- l'élément racine (OrganisationalUnit)
- un utilisateur mailserver qui sera celui avec lequel Postfix va se connecter
- un groupe mail où l'on va créer nos différents utilisateurs pour la redirection
- une classe PostfixUser qui ajoute les attributs mailacceptinggeneralid et maildrop
- un exemple d'utilisateur pour nos tests
NB: je n'ai pas modifié les mots de passe admin par défaut ici, et j'ai mis un mot de passe invalide pour le compte mailserver que l'on mettra à jour un peu plus tard. En production, il faudrait changer ces mots de passe admin, je montrerai comment faire dans un prochain article.
Exposition via Teleport
Comme j'utilise Teleport, je déclare les services LDAP dans mon agent kube (voir mon article sur Teleport ici)
1- name: ldapadmin 2 uri: "http://ldap-phpldapadmin.ldap.svc.cluster.local:80" 3 public_addr: ldapadmin.teleport.oursi.net 4 rewrite: 5 redirect: 6 - ldap-phpldapadmin.ldap.svc.cluster.local 7- name: ldappwd 8 uri: "http://ldap-ltb-passwd.ldap.svc.cluster.local:80" 9 public_addr: ldappwd.teleport.oursi.net 10 rewrite: 11 redirect: 12 - ldap-ltb-passwd.ldap.svc.cluster.local
Et j'ajoute les routes HostSNI
pour exposer les services dans mon TCPIngressRoute de Traefik.
1- match: HostSNI(`ldapadmin.teleport.oursi.net`) 2 services: 3 - name: teleport 4 port: 443 5 nativeLB: true 6- match: HostSNI(`ldappwd.teleport.oursi.net`) 7 services: 8 - name: teleport 9 port: 443 10 nativeLB: true
Une fois déployé :
Rendez-vous sur phpldapadmin (via Teleport) et connectez-vous avec le compte admin par défaut (Not@SecurePassw0rd
, à changer rapidement !). Vous verrez cette interface :
Les attributs importants :
uid
: login pour l'auth SMTP (ex:sample@oursi.net
)mailacceptinggeneralid
: alias de cet utilisateurmaildrop
: destination de redirectionuserPassword
: mot de passe pour auth SMTP
C'est le moment de modifier le mot de passe de cn=mailserver avec l'interface de ldap admin.
Vous pouvez ensuite tester une connexion LDAP avec cn=mailserver,dc=oursi,dc=net
et voir si vous listez bien les utilisateurs du groupe mail
, par exemple avec la commande suivante (à executer dans un shell du pod ldap-0
par exemple) :
1ldapsearch -x -H ldap://ldap.ldap.svc.cluster.local -D "cn=mailserver,dc=oursi,dc=net" -W -b "ou=mail,dc=oursi,dc=net" "(objectClass=inetOrgPerson)"
Ca devrait vous retourner notre utilisateur de test.
2. Configuration de docker-mailserver (DMS)
La partie la plus complexe.
2.a. Migration vers MetalLB
ServiceLB
ne permet pas de conserver l'IP source car il ne fonctionne pas en couche OSI niveau 2. C'est pourtant nécessaire pour :
- Garder l'IP réelle pour les logs et la protection antispam de DMS
- Utiliser le Proxy Protocol (requis pour postfix)
J'ai donc réinstallé k3s sans ServiceLB en utilisant le même script que pour l'installation et en modification la partie 'disable' :
1--disable traefik,metrics-server,servicelb
Puis installé MetalLB via ArgoCD et ce fichier kustomize :
1# kustomization.yml 2apiVersion: kustomize.config.k8s.io/v1beta1 3kind: Kustomization 4namespace: metallb-system 5 6resources: 7 - github.com/metallb/metallb/config/native?ref=v0.15.2 8 - pool.yaml
Voilà le fichier 'pool.yaml', à adapter avec vos adresses IP disponibles.
1apiVersion: metallb.io/v1beta1 2kind: IPAddressPool 3metadata: 4 name: first-pool 5 namespace: metallb-system 6spec: 7 addresses: 8 - <your_ip> 9--- 10apiVersion: metallb.io/v1beta1 11kind: L2Advertisement 12metadata: 13 name: first-advertisement 14 namespace: metallb-system
Vérifiez que les services existant fonctionnent toujours correctement et passons à l'étape suivante.
2.b. Traefik EntryPoints + Proxy Protocol
Par défaut, Traefik écoute uniquement sur les ports 80 et 443 (entrypoints web et websecure respectivement). On ajoute de nouveaux entrypoints en modifiant notre values.yaml
et on définit le externalTrafficPolicy en mode local.
1service: 2 spec: 3 externalTrafficPolicy: Local # Preserve client IPs 4ports: 5 smtp: 6 port: 8025 # Container port 7 expose: 8 default: true # Expose through the default service 9 exposedPort: 25 # Service port 10 protocol: TCP # Port protocol (TCP/UDP) 11 tls: 12 enabled: false # TLS is not enabled for SMTP 13 submissions: 14 port: 8465 # Container port 15 expose: 16 default: true # Expose through the default service 17 exposedPort: 465 # Service port 18 protocol: TCP # Port protocol (TCP/UDP) 19 tls: 20 enabled: true 21 submission: 22 port: 8587 # Container port 23 expose: 24 default: true # Expose through the default service 25 exposedPort: 587 # Service port 26 protocol: TCP # Port protocol (TCP/UDP) 27 tls: 28 enabled: false
On ajoute aussi de nouveaux IngressRouteTCP avec le proxy protocol activé :
1apiVersion: traefik.io/v1alpha1 2kind: IngressRouteTCP 3metadata: 4 name: submissions 5 namespace: mailserver-oursi 6spec: 7 entryPoints: 8 - submissions 9 routes: 10 - match: HostSNI(`*`) 11 services: 12 - name: mailserver-docker-mailserver 13 port: subs-proxy 14 proxyProtocol: 15 version: 2 16--- 17apiVersion: traefik.io/v1alpha1 18kind: IngressRouteTCP 19metadata: 20 name: submission 21 namespace: mailserver-oursi 22spec: 23 entryPoints: 24 - submission 25 routes: 26 - match: HostSNI(`*`) 27 services: 28 - name: mailserver-docker-mailserver 29 port: sub-proxy 30 proxyProtocol: 31 version: 2 32--- 33apiVersion: traefik.io/v1alpha1 34kind: IngressRouteTCP 35metadata: 36 name: smtp 37 namespace: mailserver-oursi 38spec: 39 entryPoints: 40 - smtp 41 routes: 42 - match: HostSNI(`*`) 43 services: 44 - name: mailserver-docker-mailserver 45 port: smtp-proxy 46 proxyProtocol: 47 version: 2
On aura aussi besoin d'un certificat TLS pour 'mail.oursi.net' :
1apiVersion: cert-manager.io/v1 2kind: Certificate 3 4metadata: 5 name: mail-tls-certificate-oursi 6 7spec: 8 secretName: mail-tls-certificate-oursi 9 isCA: false 10 privateKey: 11 algorithm: RSA 12 encoding: PKCS1 13 size: 2048 14 dnsNames: [mail.oursi.net] 15 issuerRef: 16 name: letsencrypt-issuer 17 # We can reference ClusterIssuers by changing the kind here. 18 # The default value is Issuer (i.e. a locally namespaced Issuer) 19 kind: ClusterIssuer 20 # This is optional since cert-manager will default to this value however 21 # if you are using an external issuer, change this to that issuer group. 22 group: cert-manager.io
Le réseau est prêt, passons au serveur mail.
3. Déploiement de DMS avec ArgoCD
J'utilise le chart Helm officiel de docker-mailserver, via ArgoCD.
1# filepath: argocd-apps/apps/teleport.yaml 2apiVersion: argoproj.io/v1alpha1 3kind: Application 4metadata: 5 name: mailserver 6 namespace: argocd 7 finalizers: 8 - resources-finalizer.argocd.argoproj.io 9spec: 10 project: default 11 source: 12 repoURL: https://docker-mailserver.github.io/docker-mailserver-helm 13 chart: docker-mailserver 14 targetRevision: 4.2.2 15 helm: 16 values: | 17 ## Specify the name of a TLS secret that contains a certificate and private key for your email domain. 18 ## See https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets 19 certificate: mail-tls-certificate-oursi 20 21 deployment: 22 env: 23 LOG_LEVEL: info 24 OVERRIDE_HOSTNAME: mail.oursi.net 25 26 ACCOUNT_PROVISIONER: LDAP 27 LDAP_START_TLS: 'yes' 28 LDAP_SERVER_HOST: ldap://ldap.ldap.svc.cluster.local:389 29 LDAP_SEARCH_BASE: ou=mail,dc=oursi,dc=net 30 LDAP_BIND_DN: cn=mailserver,dc=oursi,dc=net 31 LDAP_BIND_PW: <mailserver password> 32 SPOOF_PROTECTION: 1 33 34 ENABLE_SASLAUTHD: 1 35 SASLAUTHD_MECHANISMS: ldap 36 SASLAUTHD_LDAP_SERVER: ldap://ldap.ldap.svc.cluster.local:389/ 37 SASLAUTHD_LDAP_START_TLS: 'yes' 38 SASLAUTHD_LDAP_BIND_DN: cn=mailserver,dc=oursi,dc=net 39 SASLAUTHD_LDAP_PASSWORD: <mailserver password> 40 SASLAUTHD_LDAP_SEARCH_BASE: ou=mail,dc=oursi,dc=net 41 SASLAUTHD_LDAP_FILTER: (&(uid=%u@%r)(objectClass=postfixUser)) 42 43 ENABLE_POP3: 44 ENABLE_CLAMAV: 0 45 SMTP_ONLY: 1 46 ENABLE_SPAMASSASSIN: 0 47 ENABLE_FETCHMAIL: 0 48 49 configMaps: 50 user-patches.sh: 51 create: true 52 path: user-patches.sh 53 data: | 54 #!/bin/bash 55 56 # NOTE: Keep in sync with upstream advice: 57 # https://github.com/docker-mailserver/docker-mailserver/blob/v15.0.0/docs/content/examples/tutorials/mailserver-behind-proxy.md?plain=1#L238-L268 58 59 # Duplicate the config for the submission(s) service ports (587 / 465) with adjustments for the PROXY ports (10587 / 10465) and `syslog_name` setting: 60 postconf -Mf submission/inet | sed -e s/^submission/10587/ -e 's/submission/submission-proxyprotocol/' >> /etc/postfix/master.cf 61 postconf -Mf submissions/inet | sed -e s/^submissions/10465/ -e 's/submissions/submissions-proxyprotocol/' >> /etc/postfix/master.cf 62 # Enable PROXY Protocol support for these new service variants: 63 postconf -P 10587/inet/smtpd_upstream_proxy_protocol=haproxy 64 postconf -P 10465/inet/smtpd_upstream_proxy_protocol=haproxy 65 66 # Create a variant for port 25 too (NOTE: Port 10025 is already assigned in DMS to Amavis): 67 postconf -Mf smtp/inet | sed -e s/^smtp/12525/ >> /etc/postfix/master.cf 68 # Enable PROXY Protocol support (different setting as port 25 is handled via postscreen), optionally configure a `syslog_name` to distinguish in logs: 69 postconf -P 12525/inet/postscreen_upstream_proxy_protocol=haproxy 12525/inet/postscreen_cache_map=proxy:btree:\$data_directory/postscreen_12525_cache 12525/inet/syslog_name=postfix/smtpd-proxyprotocol 70 # This is necessary otherwise postscreen will fail when proxy mode is enabled: 71 postconf -e "postscreen_cache_map = proxy:btree:/var/lib/postfix/postscreen_12525_cache" 72 73 # Remove the default smtpd_sasl_local_domain setting ($mydomain) because I want to use the domain from the provided username 74 # This allows me to support logins like sample@oursi.net and sample@vannesson.com both 75 sed -i /etc/postfix/main.cf \ 76 -e '/^smtpd_sasl_local_domain/d' 77 78 rm -f /etc/postfix/{ldap-groups.cf,ldap-domains.cf} 79 80 postconf \ 81 "virtual_mailbox_domains = /etc/postfix/vhost" \ 82 "virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf texthash:/etc/postfix/virtual" \ 83 "smtpd_sender_login_maps = ldap:/etc/postfix/ldap-users.cf" 84 85 sed -i /etc/postfix/ldap-users.cf \ 86 -e '/query_filter/d' \ 87 -e '/result_attribute/d' \ 88 -e '/result_format/d' 89 cat <<EOF >> /etc/postfix/ldap-users.cf 90 query_filter = (&(mailacceptinggeneralid=%s)(objectClass=postfixUser)) 91 result_attribute = uid 92 EOF 93 94 sed -i /etc/postfix/ldap-aliases.cf \ 95 -e '/domain/d' \ 96 -e '/query_filter/d' \ 97 -e '/result_attribute/d' 98 cat <<EOF >> /etc/postfix/ldap-aliases.cf 99 domain = oursi.net, vannesson.com 100 query_filter = (&(mailacceptinggeneralid=%s)(objectClass=postfixUser)) 101 result_attribute = maildrop 102 EOF 103 104 sed -i /etc/postfix/ldap-senders.cf \ 105 -e '/start_tls/d' 106 cat <<EOF >> /etc/postfix/ldap-senders.cf 107 start_tls = yes 108 EOF 109 110 echo vannesson.com >> /etc/postfix/vhost 111 112 destination: 113 server: https://kubernetes.default.svc 114 namespace: mailserver-oursi 115 syncPolicy: 116 automated: 117 prune: true 118 selfHeal: true 119 syncOptions: 120 - CreateNamespace=true
Pensez à modifier le mot de passe de mailserver avec celui que vous avez modifié plus tôt. Je vous montrerai commence stocker ce mot de passe dans un secret dans un prochain article.
Principaux points de configuration :
- Utilise le certificat TLS
mail.oursi.net
- Auth via LDAP (bind sur
cn=mailserver
) - Patch
user-patches.sh
pour activer Proxy Protocol, mettre à jour les fichiers LDAP postfix, gérer plusieurs domaines (oursi.net
,vannesson.com
)
Ce script était complexe mais essentiel. Avec ça, DMS devrait être opérationnel. Il ne reste plus qu’à finaliser la configuration DNS pour que les autres serveurs de messagerie nous identifient et nous fassent confiance.
4. Configuration DNS
✉️ Enregistrements MX
Pour oursi.net
et pour vannesson.com
, je définis :
MX 10 mail.oursi.net
Cela permettra aux autres serveurs de messagerie de savoir où se connecter pour nous délivrer les emails.
✅ SPF
Enregistrements TXT sur oursi.net
et sur mail.oursi.net
:
v=spf1 a:mail.oursi.net include:_spf.google.com -all
SPF est utilisé pour spécifier quels serveurs de messagerie sont autorisés à envoyer des emails au nom d’un domaine.
🔒 DMARC
DMARC est un protocole d’authentification des emails qui s’appuie sur SPF et DKIM pour permettre aux propriétaires de domaine de définir comment traiter les messages non authentifiés et recevoir des rapports sur l’activité email.
Enregistrement TXT pour _dmarc.oursi.net
:
v=DMARC1; p=reject; rua=mailto:dmarc@oursi.net; ruf=mailto:dmarc@oursi.net; fo=1; pct=100;
Assurez-vous que les adresses définies pour rua et ruf sont bien redirigées quelque part (en utilisant LDAP bien sûr 😊).
🖋 DKIM
Dans un shell du pod de DMS:
1setup config dkim keysize 2048 domain oursi.net
Copier le record TXT fourni et l'enregistrer pour _mail._domainkey.oursi.net
.
Ca ressemble à ça :
1v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzuBYS9ZsMLwI7lDXYzGxUTyJs8IOYUm2siwfNdHjlaWvLHKS48kiS/r99A8Lr94VI+DcRblVgykbOjJHRhu0D5jeXrHGdbljRRC6Ym6VKDsmzBOSikG6rdDFOucr+RFK9bsnV/51TiMf82TsVSHNs8LOeVkFxOP4eoBeGGM6Mj5NmxJuG9iF+jKVW08NGQ22Bd/7dL17xxKFuO5TWvuqAbYMxLa2ZP6WyaoO7b5KSWCbE76NFKwO81/sgOHeW8hqqiRpscRA5w4yRd10mvRP+cw8cqeRy1QcBRtVIlfq5dTcvIq9OJ6RCQoRtA96x/bh1vnaZPufqAYbrw3P95905QIDAQAB
Il s’agit en réalité d’une clé publique qui sera utilisée pour valider la signature des messages envoyés par Postfix.
5. Verifying the Setup
Test with:
- Sending/receiving mail to aliases
- Configure GMAIL to be able to send mails from your domain (you will have to enter your mail server address, 'mail.oursi.net' for me, alongside username and password).
Everything should route to your Gmail now 🎉
5. Vérification de la configuration
Testez :
- Réception/redirection des mails envoyés aux alias
- Envoi via Gmail (config SMTP avec
mail.oursi.net
et vos identifiants)
Tout devrait être routé vers Gmail ❤️
💌 Conclusion
J'ai maintenant :
- Redirection email gratuite
- Envoi SMTP depuis Gmail
- Adresse personnalisée avec mon domaine
- Authentification et signatures conformes SPF/DKIM/DMARC
Tout est auto-hébergé, sécurisé, et customisable — si vous en avez marre de payer pour de simples redirections, tentez l'expérience !
Amusez-vous bien !