Datenhaufen zu IT und Elektronik.

Schlagwort: Dovecot

Post-Quantum TLS für E-Mail — Postfix und Dovecot mit X25519MLKEM768 auf FreeBSD 15

Visualisierung hybrider Post-Quantum-TLS-Verschlüsselung für E-Mail mit X25519MLKEM768 (ML-KEM-768 + X25519) auf Postfix und Dovecot unter FreeBSD 15

Nachdem ich im letzten Beitrag OpenSSH mit hybriden Post-Quantum-Algorithmen abgesichert habe, lag die Frage nahe: Was ist eigentlich mit E-Mail? Mein FreeBSD 15 liefert Postfix 3.10.6, Dovecot 2.3.21.1 und OpenSSL 3.5.4 – und genau diese Kombination bringt alles mit, was man für quantensichere Verschlüsselung im Mailverkehr braucht. Ohne zusätzliche Pakete, ohne Patches, ohne Gefrickel.

Warum überhaupt PQC für E-Mail?

Das „Store now, decrypt later„-Szenario, das ich beim SSH-Beitrag angesprochen habe, trifft auf E-Mail mindestens genauso zu. E-Mails werden über SMTP zwischen Servern transportiert – und dieser Transport ist grundsätzlich abfangbar. Wer heute TLS-verschlüsselten Mailverkehr mitschneidet und archiviert, könnte diesen in einigen Jahren mit einem ausreichend leistungsfähigen Quantencomputer entschlüsseln. Zumindest theoretisch.

Heißt das, morgen liest jemand eure Mails? Nein. Aber wenn ihr vertrauliche Kommunikation betreibt und die heute eingesetzte Kryptografie in zehn Jahren noch standhalten soll, ist jetzt der richtige Zeitpunkt zum Handeln. Zumal der Aufwand (wie ihr gleich seht) überschaubar ist.

Was steckt hinter X25519MLKEM768?

Kurz zur Einordnung: ML-KEM (ehemals CRYSTALS-Kyber) ist der vom NIST im August 2024 standardisierte Post-Quantum-Algorithmus für den Schlüsselaustausch (FIPS 203). X25519MLKEM768 ist ein sogenannter Hybrid-Algorithmus – er kombiniert das klassische X25519 (Curve25519 ECDH) mit ML-KEM-768 zu einem gemeinsamen Schlüssel.

Der Clou dabei: Selbst wenn ML-KEM irgendwann gebrochen werden sollte, bleibt die klassische X25519-Komponente intakt. Und umgekehrt. Man muss also nicht darauf vertrauen, dass der neue Algorithmus auch wirklich hält – man bekommt das Beste aus beiden Welten.

Wer Firefox nutzt, hat das übrigens vermutlich schon in Aktion gesehen: Seit Firefox 124 wird bei TLS 1.3 standardmäßig X25519MLKEM768 für den Schlüsselaustausch verwendet. Schaut mal in die Verbindungsdetails einer HTTPS-Seite – die Chancen stehen gut, dass dort bereits ein hybrider PQC-Schlüsselaustausch stattfindet. Also, wenn der Server das anbietet, wie dieser hier *zwinker*.

Voraussetzungen prüfen

Bevor ihr konfiguriert, solltet ihr sicherstellen, dass euer OpenSSL ML-KEM überhaupt kann. Auf meinem FreeBSD 15:

$ openssl version
OpenSSL 3.5.4 30 Sep 2025 (Library: OpenSSL 3.5.4 30 Sep 2025)

Und dann die entscheidende Frage – kennt OpenSSL die benötigten KEM-Algorithmen?

$ openssl list -kem-algorithms | grep -i mlkem
  ML-KEM-512
  ML-KEM-768
  ML-KEM-1024
  X25519MLKEM768
  SecP256r1MLKEM768

Wenn X25519MLKEM768 in der Liste auftaucht, seid ihr startklar. Das ist bei OpenSSL ab Version 3.5 der Fall – der ML-KEM-Support ist im Default-Provider enthalten, es wird kein zusätzlicher OQS-Provider und kein liboqs benötigt.

Noch ein Check – sind die Algorithmen auch als TLS-Gruppen verfügbar?

$ openssl list -tls-groups | grep -i mlkem
  X25519MLKEM768
  SecP256r1MLKEM768
  SecP384r1MLKEM1024

Perfekt. Weiter geht’s.

Postfix konfigurieren

Postfix steuert die verwendeten TLS-Gruppen für den Schlüsselaustausch über den Parameter tls_eecdh_auto_curves. Dieser gilt sowohl für eingehende (smtpd) als auch für ausgehende (smtp) Verbindungen.

Vorher:

tls_eecdh_auto_curves = X25519, prime256v1, secp384r1

Nachher:

tls_eecdh_auto_curves = X25519MLKEM768, X25519, prime256v1, secp384r1

Das war’s. Eine Zeile. X25519MLKEM768 wird als bevorzugte Gruppe an den Anfang gestellt, die klassischen Kurven bleiben als Fallback erhalten. Clients die kein ML-KEM beherrschen, verhandeln einfach X25519 oder prime256v1 – die Abwärtskompatibilität bleibt also vollständig gewahrt.

Die Änderung setzt ihr entweder direkt in /usr/local/etc/postfix/main.cf oder über:

# postconf "tls_eecdh_auto_curves = X25519MLKEM768, X25519, prime256v1, secp384r1"
# postfix reload

Wichtig: Dieser Parameter beeinflusst alle Postfix-Dienste – SMTP (Port 25), Submission (Port 587) und SMTPS (Port 465). Ihr müsst also nicht jeden Port einzeln konfigurieren.

Dovecot konfigurieren

Dovecot verwendet den Parameter ssl_curve_list um die TLS-Gruppen für IMAP-Verbindungen festzulegen. Standardmäßig ist dieser leer, was bedeutet, dass OpenSSL seine eigenen Defaults verwendet. Das kann funktionieren, muss aber nicht.

In /usr/local/etc/dovecot/conf.d/10-ssl.conf:

ssl_curve_list = X25519MLKEM768:X25519:prime256v1:secp384r1

Achtung: Dovecot verwendet Doppelpunkte als Trennzeichen (OpenSSL-Syntax), Postfix verwendet Kommas. Nicht verwechseln. Ja, passiert mir oft 😀

Danach:

# doveadm reload

Überprüfen

Jetzt wird’s spannend. Funktioniert es tatsächlich? Zum Testen verwende ich openssl s_client direkt auf dem Server; denn euer lokales Linux oder macOS hat möglicherweise noch kein OpenSSL 3.5 mit ML-KEM-Support. Mein Linux Mint 22.3 hat es leider noch nicht *schnief*

SMTP (Port 25, STARTTLS):

$ openssl s_client -connect smtp.kernel-error.de:25 -starttls smtp \
    -groups X25519MLKEM768 -brief </dev/null 2>&1 | grep -E 'Protocol|group'
Protocol version: TLSv1.3
Negotiated TLS1.3 group: X25519MLKEM768

SMTPS (Port 465):

$ openssl s_client -connect smtp.kernel-error.de:465 \
    -groups X25519MLKEM768 -brief </dev/null 2>&1 | grep -E 'Protocol|group'
Protocol version: TLSv1.3
Negotiated TLS1.3 group: X25519MLKEM768

Submission (Port 587, STARTTLS):

$ openssl s_client -connect smtp.kernel-error.de:587 -starttls smtp \
    -groups X25519MLKEM768 -brief </dev/null 2>&1 | grep -E 'Protocol|group'
Protocol version: TLSv1.3
Negotiated TLS1.3 group: X25519MLKEM768

IMAPS (Port 993):

$ openssl s_client -connect smtp.kernel-error.de:993 \
    -groups X25519MLKEM768 -brief </dev/null 2>&1 | grep -E 'Protocol|group'
Protocol version: TLSv1.3
Negotiated TLS1.3 group: X25519MLKEM768

Alle vier Ports verhandeln TLSv1.3 mit X25519MLKEM768. Die hybride Post-Quantum-Verschlüsselung ist aktiv.

Wenn ihr testen wollt, was passiert wenn ein Client kein ML-KEM unterstützt:

$ openssl s_client -connect smtp.kernel-error.de:465 \
    -groups X25519 -brief </dev/null 2>&1 | grep -E 'Protocol|group'
Protocol version: TLSv1.3
Negotiated TLS1.3 group: X25519

Fallback auf X25519 – funktioniert sauber.

Was das nicht leistet

Wie schon beim SSH-Beitrag muss ich auch hier einschränken: Wir sichern damit den Schlüsselaustausch ab, nicht die Authentifizierung. Die TLS-Zertifikate verwenden weiterhin klassische Algorithmen (RSA, ECDSA). Für Post-Quantum-Signaturen in Zertifikaten bräuchte man ML-DSA (ehemals CRYSTALS-Dilithium) – und obwohl OpenSSL 3.5 das theoretisch unterstützt, gibt es Stand heute keine öffentliche Zertifizierungsstelle, die ML-DSA-Zertifikate ausstellt. Das wird kommen, ist aber noch Zukunftsmusik. Hey, wie ECDSA bei S/MIME (oder ist das schon anders?).

Für die Praxis bedeutet das: Ein Angreifer mit einem Quantencomputer könnte theoretisch die Serverauthentifizierung angreifen (ECDSA/RSA brechen), müsste das aber in Echtzeit tun – hier greift „store now, decrypt later“ nicht, weil eine gefälschte Authentifizierung nur im Moment der Verbindung nützt. Der Schlüsselaustausch hingegen – und damit die eigentliche Vertraulichkeit der transportierten E-Mails – ist durch X25519MLKEM768 auch gegen zukünftige Quantenangriffe geschützt.

Zwei Zeilen Konfiguration, ein Reload pro Dienst – und euer Mailserver verhandelt quantensichere Verschlüsselung. Vollständig abwärtskompatibel, ohne Einschränkungen für bestehende Clients. Es gibt eigentlich keinen Grund, das nicht zu tun. Oder fällt euch etwas ein?

Viel Spaß beim Nachbauen – und wie immer: bei Fragen, fragen.

Rspamd: Automatisches Spam/Ham-Lernen mit Dovecot und IMAPSieve

Bei jedem Spamfilter kann es vorkommen, dass Spam durchrutscht oder eine echte Nachricht fälschlicherweise als Spam eingestuft wird. Rspamd bietet über das Webinterface die Möglichkeit, trainiert zu werden. Hier kann man einfach den Quellcode jeder E-Mail kopieren und Rspamd mitteilen, ob es sich dabei um Spam (SPAM) oder um eine legitime Nachricht (HAM) handelt. Dieses Vorgehen ist jedoch ungeeignet, um den Spamfilter effektiv zu trainieren.

Dovecot and RSPAMD Logo

Wünschenswert wäre folgende Lösung: Immer wenn ein Benutzer eine E-Mail in den Ordner „Junk“ verschiebt, sollte diese E-Mail automatisch von Rspamd als Spam gelernt werden. Zusätzlich sollte jede E-Mail, die der Benutzer aus dem „Junk“-Ordner herausholt, als Ham gelernt werden.

Genau dieses Szenario möchte ich hier kurz beschreiben. Das Hostsystem ist ein FreeBSD; Linux-User müssen daher bei den Pfaden wie /usr/local aufpassen! Ebenfalls lauscht mein Rspamd-Worker nicht auf einem Unix-Socket, sondern auf der IP 127.0.0.3, da er in einer Jail-Umgebung läuft.

Beginnen wir mit der Konfiguration für Dovecot.

20-imap.conf:

protocol imap {
  mail_plugins = $mail_plugins sieve
}

90-plugin.conf:

plugin {
  sieve_plugins = sieve_imapsieve sieve_extprograms

  # From elsewhere to Spam folder or flag changed in Spam folder
  imapsieve_mailbox1_name = Junk
  imapsieve_mailbox1_causes = COPY FLAG
  imapsieve_mailbox1_before = file:/usr/local/etc/dovecot/sieve/report-spam.sieve

  # From Spam folder to elsewhere
  imapsieve_mailbox2_name = *
  imapsieve_mailbox2_from = Junk
  imapsieve_mailbox2_causes = COPY
  imapsieve_mailbox2_before = file:/usr/local/etc/dovecot/sieve/report-ham.sieve

  sieve_pipe_bin_dir = /usr/local/libexec/dovecot

  sieve_global_extensions = +vnd.dovecot.pipe
}

/usr/local/etc/dovecot/sieve/report-spam.sieve:

require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "imap4flags"];

if environment :is "imap.cause" "COPY" {
    pipe :copy "sa-learn-spam.sh";
}

# Catch replied or forwarded spam
elsif anyof (allof (hasflag "\\Answered",
                    environment :contains "imap.changedflags" "\\Answered"),
             allof (hasflag "$Forwarded",
                    environment :contains "imap.changedflags" "$Forwarded")) {
    pipe :copy "sa-learn-spam.sh";
}

/usr/local/etc/dovecot/sieve/report-ham.sieve:

require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];

if environment :matches "imap.mailbox" "*" {
  set "mailbox" "${1}";
}

if string "${mailbox}" [ "Trash", "train_ham", "train_prob", "train_spam" ] {
  stop;
}

pipe :copy "sa-learn-ham.sh";

Natürlich nicht vergessen, die beiden neuen Sieve-Skripte für Sieve zu kompilieren:

# sievec /usr/local/etc/dovecot/sieve/report-spam.sieve
# sievec /usr/local/etc/dovecot/sieve/report-ham.sieve

Es fehlen nur noch die beiden Shell-Skripte, um die Mails an Rspamd weiterleiten zu können.

/usr/local/libexec/dovecot/sa-learn-spam.sh:

#!/bin/sh
exec /usr/local/bin/rspamc -h 127.0.0.3:11334 learn_spam

/usr/local/libexec/dovecot/sa-learn-ham.sh:

#!/bin/sh
exec /usr/local/bin/rspamc -h 127.0.0.3:11334 learn_ham

Beide müssen ausführbar sein:

# chmod +x /usr/local/libexec/dovecot/sa-learn-spam.sh /usr/local/libexec/dovecot/sa-learn-ham.sh

Wenn ich nun eine E-Mail in den Ordner „Junk“ verschiebe, lernt Rspamd diese automatisch als Spam:

2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_controller_check_password: allow unauthorized connection from a trusted IP 127.0.0.3
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_message_parse: loaded message; id: <FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net>; queue-id: <undef>; size: 49053; checksum: <f5e2fc59515e1da33d532c6f03f6f6f0>
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_controller_learn_fin_task: <127.0.0.3> learned message as spam: FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net

Verschiebe ich eine E-Mail aus dem Ordner „Junk“ heraus, wird sie, wie gewünscht, als Ham gelernt:

2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_controller_check_password: allow unauthorized connection from a trusted IP 127.0.0.3
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_message_parse: loaded message; id: <FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net>; queue-id: <undef>; size: 49053; checksum: <f5e2fc59515e1da33d532c6f03f6f6f0>
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_controller_learn_fin_task: <127.0.0.3> learned message as ham: FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net

Fragen? Einfach fragen!

Ach, und was man nicht mehr verwenden sollte: das Antispam-Plugin – das ist „tot“.

Automatische E-Mail-Archivierung mit Dovecot IMAP einrichten

Um etwas mehr Ordnung in meinem IMAP Postfach zu halten nutzen ich ein kleines Python Skript cleanup-maildir https://www.freshports.org/mail/cleanup-maildir/. Dieses Skript läuft jede Nacht und sortiert automatisch alle E-Mails die älter sind als 365 Tage aus meinem Posteingang (inbox) sowie meinen Gesendeten E-Mails ins Archive. Dabei sortiert es die Mails automatisch in Unterordner mit dem Jahres und Monatsnamen, damit ich die E-Mails schneller finden kann.

Zum Beginn lief es nur als cronjob auf meinem Postfach, inzwischen sammelt es sich die Benutzer, den MailBox Pfad sowie die Option ob es laufen soll oder nicht (autoarchive=0|1) aus dem LDAP Server.

Den grundlegenden Aufruf des Skriptes möchte ich kurz mit euch teilen!

sudo -u vmboxuser cleanup-maildir --age=365 --archive-folder='Archive.Inbox' --maildir-root='/var/mail/vhosts/kernel-error.com/kernel-error' archive ''
sudo -u vmboxuser cleanup-maildir --age=365 --archive-folder='Archive.Sent' --maildir-root='/var/mail/vhosts/kernel-error.com/kernel-error' archive 'Sent/'

sudo -u vmboxuser lässt den Befehl als der Nutzer laufen, welcher bei mir übergreifen Zugriff auf die Postfächer hat.
–age=365 sagt, dass nur E-Mails älter 365 Tage angefasst werden sollen.
–archive-folder=’Archive.Inbox/Sent‘ gibt die Zielordner im Postfach an.
–maildir-root='[…]‘ das Postfach (Domain und Postfachname kommen normalerweise als Variable aus dem LDAP).
archive sagt dem Skript, dass archiviert werden soll. Man könnte auch löschen oder ähnliches.
ist der Default also die Inbox
‚Sent/‘ sind die gesendeten E-Mail.

 Die entstehende Ordnerstruktur im Postfach ist dann:

Screenshot der IMAP Archive Ordnerstruktur.

Tjo… Läuft seit Jahren sehr gut und räumt die Postfächer automatisch auf.

TLS 1.3 für Postfix & Dovecot: Einrichtung und Konfiguration​

TLS 1.3 ist im Mailbetrieb kein Sonderfall mehr, sondern der Normalzustand. Voraussetzung ist lediglich, dass Postfix und Dovecot gegen eine aktuelle OpenSSL-Version gelinkt sind. Sobald OpenSSL TLS 1.3 unterstützt, wird es automatisch verwendet. Eine explizite Aktivierung in der Applikation ist nicht erforderlich.

Die eigentliche Aufgabe der Konfiguration besteht daher nicht darin, TLS 1.3 „einzuschalten“, sondern darin, alte Protokollversionen sauber zu deaktivieren und für den verbleibenden TLS-1.2-Fallback eine kontrollierte Cipher-Policy zu definieren.

Illustration zu TLS 1.3 im Mailbetrieb: Symbolische Darstellung von Postfix und Dovecot mit Schloss und Schlüssel vor Server-Hintergrund, steht für verschlüsselte SMTP- und IMAP-Verbindungen mit modernen TLS-Standards.

Voraussetzungen

Postfix und Dovecot müssen gegen OpenSSL ≥ 1.1.1 gebaut sein. OpenSSL 3.x funktioniert ebenfalls ohne Einschränkungen. Welche Version tatsächlich genutzt wird, lässt sich eindeutig prüfen:

postconf -a | grep -i tls
dovecot --version
ldd $(which dovecot) | grep ssl
openssl version

Wenn hier OpenSSL 1.1.1 oder neuer auftaucht, ist TLS 1.3 verfügbar.

Postfix

Postfix verwendet TLS 1.3 automatisch, sofern der Client es anbietet. Entscheidend ist, welche Protokollversionen minimal erlaubt werden. TLS 1.0 und TLS 1.1 gelten als kryptographisch überholt und sollten nicht mehr akzeptiert werden.

Die folgende Konfiguration beschränkt Postfix auf TLS 1.2 und neuer. TLS 1.3 wird dabei bevorzugt ausgehandelt, TLS 1.2 dient nur noch als Fallback.

smtpd_tls_protocols = >=TLSv1.2
smtp_tls_protocols  = >=TLSv1.2

smtpd_tls_security_level = may
smtp_tls_security_level  = may

smtpd_tls_cert_file = /etc/letsencrypt/live/DOMAIN/fullchain.pem
smtpd_tls_key_file  = /etc/letsencrypt/live/DOMAIN/privkey.pem

Cipher-Optionen in Postfix gelten ausschließlich für TLS 1.2 und ältere Protokolle. TLS 1.3 verwendet fest definierte Cipher-Suites und ignoriert diese Einstellungen vollständig. Dennoch ist es sinnvoll, für den TLS-1.2-Fallback eine saubere Policy zu setzen.

tls_preempt_cipherlist = yes

smtpd_tls_ciphers = high
smtp_tls_ciphers  = high

Damit werden nur moderne Cipher mit Forward Secrecy genutzt, abhängig von den OpenSSL-Defaults der jeweiligen Distribution.

Session-Caching reduziert Handshake-Overhead und sollte aktiv sein:

smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database  = btree:${data_directory}/smtp_scache

Dovecot

Auch Dovecot nutzt TLS 1.3 automatisch, sofern OpenSSL es bereitstellt. Die relevante Einstellung ist die minimale Protokollversion. Alles darunter wird explizit ausgeschlossen.

ssl = required
ssl_min_protocol = TLSv1.2

Die Cipher-Liste in Dovecot betrifft ebenfalls nur TLS 1.2 und älter. TLS 1.3 wird davon nicht beeinflusst. Eine explizite, restriktive Cipher-Liste verhindert jedoch unsaubere Fallbacks bei älteren Clients.

ssl_cipher_list = \
ECDHE-ECDSA-CHACHA20-POLY1305:\
ECDHE-RSA-CHACHA20-POLY1305:\
ECDHE-ECDSA-AES256-GCM-SHA384:\
ECDHE-RSA-AES256-GCM-SHA384

ssl_prefer_server_ciphers = yes

Die Zertifikate werden wie gewohnt eingebunden:

ssl_cert = </etc/letsencrypt/live/DOMAIN/fullchain.pem
ssl_key  = </etc/letsencrypt/live/DOMAIN/privkey.pem

TLS 1.3 und Cipher-Suites

TLS 1.3 unterscheidet sich grundlegend von älteren Versionen. Die Cipher-Suites sind fest definiert und bestehen ausschließlich aus modernen AEAD-Verfahren mit integrierter Authentifizierung und Forward Secrecy. Typische Cipher sind AES-GCM und CHACHA20-POLY1305.

Postfix und Dovecot bieten keine Möglichkeit, diese Cipher direkt zu konfigurieren. Die Auswahl erfolgt intern durch OpenSSL während des Handshakes. Das ist beabsichtigt und reduziert Fehlkonfigurationen erheblich.

Wer versucht, TLS-1.3-Cipher über Applikationsoptionen zu beeinflussen, konfiguriert faktisch nur TLS 1.2.

Verifikation

Ob TLS 1.3 tatsächlich genutzt wird, lässt sich eindeutig prüfen.

SMTP mit STARTTLS:

openssl s_client -starttls smtp -connect mail.example.com:25 -tls1_3

IMAPS:

openssl s_client -connect mail.example.com:993 -tls1_3

Wird der Handshake erfolgreich aufgebaut und ein moderner AEAD-Cipher angezeigt, ist TLS 1.3 aktiv. Fällt die Verbindung auf TLS 1.2 zurück, greift die konfigurierte Cipher-Liste.

Fazit

TLS 1.3 erfordert in Postfix und Dovecot keine Sonderbehandlung. Entscheidend ist eine aktuelle OpenSSL-Version, eine klare Mindest-TLS-Policy und eine saubere Cipher-Konfiguration für den unvermeidbaren TLS-1.2-Fallback.

Alles andere erledigt der TLS-Stack selbst.

Kein Feature-Flag.
Keine Magie.
Nur korrekte Defaults, bewusst begrenzt.

Outlook Autodiscover für IMAP/SMTP: Automatische Kontoeinrichtung​

Benutzer sind, wie der Name schon treffend beschreibt, Menschen welche etwas benutzen. Dieses bedeutet nicht dass sie es verstehen oder gar „montieren“ können. Sie möchten es einfach nur benutzen und dieses sollen sie auch.

Betreibt man einen Mailserver und verteilt Postfächer an seine Benutzer, kommt man extrem schnell an den Punkt dass die Benutzer ihre Postfächer nutzen wollen 😛 Sie möchten ihr neues Postfach in ihren E-Mail Client (wir sagen MUA) einbinden. Nur wie?!?

Ja klar nun kann man bebilderte Anleitungen oder besser noch Anleitungsvideos anfertigen und diese seinen Benutzer zugänglich machen. Sehr oft muss denn noch am Ende jemand das Postfach einbinden oder es wird nach einer Fehlerdiagnose festgestellt dass der Benutzer keine E-Mails versenden kann, weil er sich nicht am Postausgangsserver anmeldet. Einfacher wäre es doch, wenn sich der MUA selbst konfigurieren würde, oder? ADS Mitglieder welche von einem Exchangeserver bedient werden, kennen die Luxusversion… Kunden der großen Freemailer wie GMX, Google, Yahoo usw. kennen es ebenso. Diese geben in ihrem MUA nämlich maximal 3 Dinge an. Ihren Namen, E-Mail Adresse und das Kennwort. Also alles Dinge die ein normaler Benutzer angeben können sollte.

Wie läuft diese automatische Konfiguration nun bei Microsoft Outlook ab? Nun, da es eine ganze Latte an Möglichkeiten gibt Outlook die Konfiguration unter zu schieben, fragt Outlook diese ganz brav der Reihe nach ab. Bekommt er von einer der Stellen eine Konfiguration probiert Outlook diese aus. Klappt alles, ist die Einrichtung fertig, klappt etwas nicht, geht es in der Liste weiter. Ich fasse mal kurz zusammen:

1 – Ist der Computer Mitglied einer Domäne, wird die E-Mail Adresse vom Active Directory abgerufen.

2 – Der DNS Name des Exchangeservers wird abgerufen.

3 – SCP (Service Connection Point) Suche und Suche nach dem passenden AutoConfig Servers. Dann mit diesen Daten eine Verbindung herstellen. Fertig….

4 – Klappt dieses nicht, wird versucht im DNS einige Domainnamen aufzulösen und dort nach einer autodiscover.xml XML-Datei gesucht.
Gesucht wird dabei hier:
a. https://ads-domäne/autodiscover/autodiscover.xml
b. https://autodiscover.example.org/autodiscover/autodiscover.xml
c. http://autodiscover.ads-domäne/autodiscover.xml
d. DNS SRV-RECORD: _autodiscover._tcp.ads-domäne/examle.org

5 – Klappt dieses auch nicht, wird versucht auf dem Rechner eine XML Datei zu finden.

6 – Klappt dieses wieder nicht, es aber ein Exchange Server (Punkt 2) gefunden wurde, wird der manuelle Konfigurations-Wizard  für Exchangeserver aufgerufen.

7 – Wurde kein Exchange Server gefunden dann wir der einfache Konfigurations-Wizard aufgerufen.

Möchte man nun seinen Outlook Client automatisch alle nötigen Einstellungen für die Konfiguration seines Postfix / Dovecot-IMAP Servers finden lassen, klappt dieses wie folgt:

Wir haken einfach an punkt 4-b. ein. Wir sorgen also dafür dass es den Domainnamen autodiscover.example.org gibt oder halt ein passender SRV-RECORD vorhanden ist und dass dieser auf einen Webserver zeigt, welcher sich zuständig fühlt. Wenn wir nun noch dafür sorgen dass Outlook dort auch die XML-Datei autodiscover/autodiscover.xml abrufen kann sind wir schon ganz weit vorne 🙂

Zu beachten ist aber dass Outlook die Konfigurationsdatei nur dann abruft, wenn diese per https (SSL) zugänglich ist. Beim SRV-RECORD muss man wissen dass Outlook es als „Umleitung“ behandelt. Beim SRV-RECORD und bei allen anderen Umleitungen wird Outlook also ein kleines Fenster öffnen und den Benutzer fragen ob er wirklich dieser Umleitung zur Konfiguration folgen will oder nicht. Ist das SSL-Zertifikat für Outlook nicht gültig, wirft Outlook natürlich ebenfalls Meldungen raus.

Angenommen wir haben also die E-Mail Adresse: test@example.org

Outlook wird geöffnet, der Wizard geht auf und Fragt was für ein Konto wir einrichten wollen. Dann würfelt der Benutzer seinen Namen, seine E-Mail Adresse (test@example.org) und sein Kennwort in den Wizard. Nun geht Outlook seine Testliste durch und sieht das es die Domain: autodiscover.example.org (japp hier greift Outlook immer auf den Domainteil der E-Mail Adresse zurück) gibt. Nun macht Outlook einen HTTP/HTTPS-POST an die Adresse https://autodiscover.example.org/autodiscover/autodiscover.xml in diesem Post übermittelt Outlook unter anderem die vom Benutzer eingegebene E-Mail Adresse (das wird uns später noch helfen!). Als HTTPS Antwort erwartet Outlook nun die autodiscover.xml mit der zu nutzenden Konfiguration.

Alles geil, oder? Na ja fast… Outlook wird nämlich als Anmeldename per Default den Teil der E-Mail Adresse vor dem @ nutzen. In diesem Fall also test. Müssen sich Benutzer mit der kompletten E-Mail Adresse anmelden, hat man nun ein Problem. Es gibt in der XML Beschreibung zwar die Möglichkeit einen <LoginName> zu setzten. Dieser wäre aber statisch. Sprich man kann hier nicht einfach eine Variable wie %e-mailadresse% einsetzten. Nun können wir uns denn noch den POST zunutze machen. Denn hier wird dem Webserver ja die E-Mailadresse (also der Benutzername) mitgeteilt. Ein php://input könnte also die Welt retten.

Jaaaa nun klingelt es schon bei einigen, richtig? Genau… Die Datei: autodiscover/autodiscover.xml ist in Wirklichkeit die Datei: autodiscover/autodiscover.xml.php. In der Konfiguration des VirtualHosts im Apache wird nur ein Alias gesetzt: Alias /autodiscover/autodiscover.xml /var/www/autodiscover/htdocs/autodiscover.php Damit unser Apache bei der Outlookfrage nach autodiscover.xml bei einem PHP-Script landet. Dieses fischt alle nötigen Informationen ab und bereitet sie entsprechend für Outlook auf.

Perfekte Arbeit für dieses Script hat bereits David Ramsden geleistet. Sein Original ist hier zu finden: http://0wned.it/geek-bits/scripts/open-source-autodiscover-implementation-in-php/

Ich habe sein Script nur für meine Zwecke etwas angepasst.

>>Meine XML-Autodiscover Konfigurationsdatei<<

Ich hoffe dieses kann dem einen oder anderen etwas helfen diesen AutoErmittlungsdienst zu verstehen. Bei Fragen, einfach eine E-Mail schicken 🙂


So nebenbei… Der Microsoft Lync 2013 Client sammelt über den A-RECORD autodiscover.example.org den Weg zum Exchangeserver ein. So kommt dieser auch an die Interne EWS-URL und die Externe EWS-URL.

Der Lync Client benötigt also für jede SMTP-Domäne zwei DNS RECORDS:

autodiscover IN CNAME exchangeserver.example.org.
_autodiscover._tcp IN SRV 0 0 443 exchangeserver.example.org.

Ich muss beim Thema Microsoft Lync aber die Hände heben. Ich kenne hier aber jemanden an den ich Anfragen weiterleiten könnte 🙂


Mangels freier IPv4 Adressen, ist https://autodiscover.kernel-error.de/autodiscover/autodiscover.xml aktuell nur per IPv6 erreichbar. Sicher kein Problem für euch, oder? 😀

Zertifikat angepasst und per SNI passen eingebunden. So alte Clients haben dann also Pech! 😀 Als kleine Tipp für die eigenen Tests, ein kleines Tool von Microsoft selbst:

https://testconnectivity.microsoft.com

Dort müsste der Exchange ActiveSync Autodiscover alle eure Wünsche erfüllen können!


Auf mehrfachen Wunsch, hier nun noch einmal die autodiscover.php als copy & paste Version:

<?
/*
 Open Source Autodiscover implementation in PHP.
 
 Version: 1.0
 Tested with:
        - Microsoft Exchange Remote Connectivity Analyzer (1.3)
        - iOS 4.3.5
        - Outlook 2010 (SP0)
        - Android 2.3.3
 
 Allows auto configuration of ActiveSync and Outlook (or any other MUA that has
 autodiscover support).
 
 Example Apache vhost configuration (SSL is required for Autodiscover):
 
        <VirtualHost 1.2.3.4:443>
                ServerName autodiscover.domain.com
                ServerAdmin webmaster@domain.com
 
                SSLEngine on
                SSLCertificateFile      /etc/apache/ssl/certs/apache.domain.com.crt
                SSLCertificateKeyFile   /etc/apache/ssl/private/apache.domain.com.key
 
                # Force all requests to lowercase. Different MUAs, mobile devices etc
                # request the Autodiscover URL in different cases.
                RewriteEngine On
                RewriteMap lc int:tolower
                RewriteCond %{REQUEST_URI} [A-Z]
                RewriteRule (.*) ${lc:$1} [R=301,L]
 
                DocumentRoot /var/www/autodiscover/htdocs
                <Directory />
                        Options +FollowSymLinks -Indexes
                        AllowOverride Options Indexes Limit FileInfo AuthConfig
                </Directory>
 
                 Alias /autodiscover/autodiscover.xml /var/www/autodiscover/htdocs/autodiscover.php
 
                ErrorLog /var/www/autodiscover/logs/error.log
                CustomLog /var/www/autodiscover/logs/access.log combined
        </VirtualHost>
 
 
------------------------------------------------------------------------------
  Copyright (C) 2011 David Ramsden
 
  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.
 
  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:
 
  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.
 
  David Ramsden david {at} 0wned {dot} it
------------------------------------------------------------------------------
*/
// For other supported protocols and more protocol settings, see:
//  http://technet.microsoft.com/en-us/library/cc511507.aspx
 
// Get contents of request made to Autodiscover.
$request = file_get_contents("php://input");
preg_match("/\<EMailAddress\>(.*?)\<\/EMailAddress\>/", $request, $email_address);



 
/*** Begin Configuration ***/
// ActiveSync URL.
$_CONFIG['MobileSync']['Url'] = "https://www.kernel-error.de/Microsoft-Server-ActiveSync";


 
// IMAP configuration settings.
$_CONFIG['IMAP']['Server'] = "imap.kernel-error.de";
$_CONFIG['IMAP']['Port'] = "993";
$_CONFIG['IMAP']['SSL'] = "on";
$_CONFIG['IMAP']['SPA'] = "off";
$_CONFIG['IMAP']['AuthRequired'] = "on";
$_CONFIG['IMAP']['LoginName'] = $email_address[1];
 
// SMTP configuration settings.
$_CONFIG['SMTP']['Server'] = "smtp.kernel-error.de";
$_CONFIG['SMTP']['Port'] = "465";
$_CONFIG['SMTP']['SSL'] = "on";
$_CONFIG['SMTP']['SPA'] = "off";
$_CONFIG['SMTP']['AuthRequired'] = "on";
$_CONFIG['SMTP']['LoginName'] = $email_address[1];
/*** End Configuration ***/
 

 
// XML document heading.
header("Content-Type: text/xml");
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
 
// Get the schema from the request.
preg_match("/\<AcceptableResponseSchema\>(.*?)\<\/AcceptableResponseSchema\>/", $request, $schema);
// Determine the type of device requesting Autodiscover.
if (preg_match("/\/mobilesync\//", $schema[1]))
{
        // Mobile device.
        preg_match("/\<EMailAddress\>(.*?)\<\/EMailAddress\>/", $request, $email_address);
        ?>
                <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
                        <Response xmlns="<? echo $schema[1]; ?>">
                                <Culture>en:en</Culture>
                                <User>
                                        <DisplayName><? echo $email_address[1]; ?></DisplayName>
                                        <EMailAddress><? echo $email_address[1]; ?></EMailAddress>
                                </User>
                                <Action>
                                        <Settings>
                                                <Server>
                                                        <Type>MobileSync</Type>
                                                        <Url><? echo $_CONFIG['MobileSync']['Url']; ?></Url>
                                                        <Name><? echo $_CONFIG['MobileSync']['Url']; ?></Name>
                                                </Server>
                                        </Settings>
                                </Action>
                        </Response>
                </Autodiscover>
        <?
}
else if (preg_match("/\/outlook\//", $schema[1]))
{
        // MUA (mail client).
        ?>
                <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
                        <Response xmlns="<? echo $schema[1]; ?>">
                                <Account>
                                        <AccountType>email</AccountType>
                                        <Action>settings</Action>
                                <?
                                        // Loop through each configured protocol.
                                        while(list($protocol, $settings) = each($_CONFIG))
                                        {
                                                // Skip ActiveSync protocol.
                                                if ($protocol == "MobileSync") continue;
                                        ?>
                                                <Protocol>
                                                        <Type><? echo $protocol; ?></Type>
                                        <?
                                                // Loop through each setting for this protocol.
                                                while(list($setting, $value) = each($settings))
                                                {
                                                        echo "\t\t\t\t\t\t\t<$setting>$value</$setting>\n";
                                                }
                                        ?>
                                                </Protocol>
                                        <?
                                        }
                                ?>
                                </Account>
                        </Response>
                </Autodiscover>
        <?
}
else
{
        // Unknown.
        list($usec, $sec) = explode(' ', microtime());
        ?>
                <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
                        <Response>
                                <Error Time="<? echo date('H:i:s', $sec) . substr($usec, 0, strlen($usec) - 2); ?>" Id="2477272013">
                                        <ErrorCode>600</ErrorCode>
                                        <Message>Invalid Request</Message>
                                        <DebugData />
                                </Error>
                        </Response>
                </Autodiscover>
        <?
}
?>

© 2026 -=Kernel-Error=-RSS

Theme von Anders NorénHoch ↑