DNS- & E-Mail-Setup

DNS-Einträge, DKIM-Signierung, SPF, DMARC und Bounce-Verarbeitung für eine zuverlässige E-Mail-Zustellung konfigurieren.

Für den produktiven E-Mail-Versand benötigt Ihre selbst gehostete Owlat-Instanz eine korrekte DNS-Konfiguration. Ohne sie weisen die meisten E-Mail-Anbieter Ihre Nachrichten ab oder verschieben sie in den Spam-Ordner.

Nur beim Versand über den eingebauten MTA

Diese Seite gilt, wenn Sie über den eingebauten MTA von Owlat versenden. Versenden Sie über Resend oder SES, folgen Sie stattdessen deren Anleitungen zur Domain-Authentifizierung; betreiben Sie einen reinen IMAP-Modus (Lesen eines externen Postfachs, Antworten über Ihren eigenen SMTP), können Sie das DNS-Setup vollständig überspringen.

Lokale Entwicklung

Das DNS-Setup wird nur für die Produktion benötigt. Für lokale Tests versucht der MTA die Zustellung mit den Standardeinstellungen — die meisten E-Mails werden von empfangenden Servern abgewiesen, Sie können aber überprüfen, dass die Pipeline durchgängig funktioniert.

Erforderliche DNS-Einträge

A-Record

Richten Sie Ihre Anwendungsdomain auf die IP-Adresse Ihres Servers:

owlat.example.com.    A    203.0.113.10

PTR / Reverse DNS

Der EHLO_HOSTNAME in Ihrer .env muss einen PTR-Record besitzen, der zur IP-Adresse Ihres Servers passt. Dieser wird im Control Panel Ihres Hosting-Anbieters gesetzt (nicht bei Ihrem DNS-Anbieter).

# Your .env
EHLO_HOSTNAME=mail.example.com

# PTR record (set in hosting provider)
203.0.113.10    PTR    mail.example.com

Die meisten empfangenden Mailserver weisen Verbindungen ab, bei denen der EHLO-Hostname nicht zum PTR-Record passt.

Owlat prüft die vollständige Kette, bevor es eine Adresse auswählt: Der PTR muss existieren, einen gültigen FQDN enthalten, vorwärts auf die sendende IP auflösen und zum EHLO-Namen passen. Das Ergebnis wird fortlaufend gespeichert und stündlich geprüft. Ein harter Fehlschlag stellt die IP unter Quarantäne, sodass eine Installation mit Provider-Standard- oder fehlendem Reverse DNS nicht stillschweigend versenden kann. Provider-Standard-PTRs, die sich vorwärts bestätigen lassen, bleiben nutzbar, erscheinen jedoch als Reputationswarnung unter Zustellgesundheit → Ausgehende IPs.

Geben Sie bei einem Pool mit mehreren IPs jeder Adresse eine eigene Identität:

EHLO_HOSTNAMES={"203.0.113.10":"mail1.example.com","203.0.113.11":"mail2.example.com"}

MTA_ALLOW_UNVERIFIED_FCRDNS=true ist eine ausdrückliche Notluke nur für Laborumgebungen, gedacht für Experimente mit privaten/lokalen IPv4-Adressen. Eine unverifizierte IPv6-Adresse lässt sie niemals zu.

MX-Record für die Bounce-Verarbeitung

Die RETURN_PATH_DOMAIN benötigt einen MX-Record, der auf Ihren Server zeigt, damit Bounce-E-Mails auf Port 25 zum MTA zurückgeleitet werden:

bounces.example.com.    MX    10 mail.example.com.

SPF

Der eingebaute MTA erzeugt standardmäßig keinen SPF-Record automatisch

Wenn Sie auf Domain hinzufügen klicken, erzeugt der eingebaute MTA Ihre DKIM- und DMARC-Einträge, gibt aber nur dann einen SPF-Eintrag aus, wenn die Umgebungsvariable MTA_SPF_INCLUDE gesetzt ist. Ist MTA_SPF_INCLUDE nicht gesetzt, wird kein SPF-Eintrag angezeigt und Sie müssen ihn wie unten beschrieben manuell hinzufügen. Die Ausrichtung von DKIM + DMARC funktioniert auch ohne SPF, doch ein fehlender oder falscher SPF-Eintrag schadet der Zustellbarkeit.

Sie haben zwei Möglichkeiten, SPF zu veröffentlichen — je nachdem, wie Sie den MTA betreiben:

Option A — einen ip4-Eintrag manuell hinzufügen (Standard). Wenn Sie MTA_SPF_INCLUDE nicht gesetzt haben, fügen Sie auf Ihrer Versanddomain einen TXT-Record hinzu, der die IP Ihres Servers direkt autorisiert:

example.com.    TXT    "v=spf1 ip4:203.0.113.10 -all"

Wenn Sie mehrere IPs verwenden (getrennte Pools für transaktionale Mail und Kampagnen), führen Sie alle davon auf:

example.com.    TXT    "v=spf1 ip4:203.0.113.10 ip4:203.0.113.11 -all"

Option B — den MTA einen include:-Eintrag erzeugen lassen. Setzen Sie MTA_SPF_INCLUDE im Convex-Backend auf eine Domain, deren eigener SPF-Record Ihre Versand-IPs auflistet (zum Beispiel eine gemeinsame _spf-Subdomain, die Sie pflegen). Der Ablauf „Domain hinzufügen“ gibt dann diesen Eintrag für Sie aus:

example.com.    TXT    "v=spf1 include:<MTA_SPF_INCLUDE value> ~all"

Verwenden Sie die ip4-Form (Option A), sofern Sie keine gepflegte include:-Domain betreiben — so bleiben Ihre autorisierten IPs explizit und innerhalb des Limits von 10 Lookups bei SPF (RFC 7208 §4.6.4).

Soft-Fail vs. Hard-Fail (~all vs. -all)

Solange Sie noch IPs oder Relays hinzufügen, veröffentlichen Sie ~all (Soft-Fail), damit eine Nachricht von einer noch nicht aufgeführten IP markiert und nicht abgewiesen wird. Sobald Ihr Satz autorisierter IPs stabil ist, wechseln Sie auf -all (Hard-Fail). Der Domain-Verifizierungsablauf von Owlat erzeugt standardmäßig ~all; setzen Sie SPF_QUALIFIER=-all, sobald Sie Ihrer IP-Liste vertrauen.

SPF für die Bounce-Return-Path-Domain

Diesen Schritt übersehen die meisten Self-Hoster. Der MTA versendet mit einem VERP-Bounce-Envelope (MAIL FROM: bounce+…@RETURN_PATH_DOMAIN), Empfänger bewerten SPF also gegen Ihre RETURN_PATH_DOMAIN und nicht gegen den Apex Ihrer From-Domain. Hat RETURN_PATH_DOMAIN keinen SPF-Record, scheitert der Bounce-Envelope an SPF — und da die Return-Path-Domain (bounces.example.com) nicht zu Ihrer From-Domain (example.com) ausgerichtet ist, kann SPF für Ihre From-Domain allein niemals zu DMARC beitragen. DKIM richtet sich weiterhin aus und trägt DMARC, dennoch sollten Sie den Return-Path autorisieren.

Veröffentlichen Sie auf RETURN_PATH_DOMAIN einen TXT-Record, der jede Pool-IP autorisiert:

bounces.example.com.    TXT    "v=spf1 ip4:203.0.113.10 -all"

Bei mehreren Pool-IPs führen Sie alle davon auf:

bounces.example.com.    TXT    "v=spf1 ip4:203.0.113.10 ip4:203.0.113.11 -all"

Damit SPF ausgerichtet ist (SPF also DMARC allein erfüllen kann), verwenden Sie statt einer gemeinsamen Bounce-Domain eine Return-Path-Subdomain Ihrer Versanddomain — setzen Sie z. B. RETURN_PATH_DOMAIN=bounce.example.com, damit der Return-Path dieselbe organisatorische Domain wie Ihre From-Domain nutzt und sich im Relaxed-Modus von DMARC ausrichtet. Veröffentlichen Sie den SPF-Record dann auf dieser Subdomain:

bounce.example.com.    TXT    "v=spf1 ip4:203.0.113.10 -all"
Owlat den Eintrag erzeugen lassen

Setzen Sie MTA_RETURN_PATH_DOMAIN und MTA_IP_POOLS (kommagetrennte Versand-IPs) in den Umgebungsvariablen des Convex-Backends, dann erzeugt der Domain-Verifizierungsablauf in der App den Return-Path-SPF-Record für Sie — mit dem Qualifier aus SPF_QUALIFIER.

DKIM

DKIM signiert ausgehende E-Mails mit einem kryptografischen Schlüssel, sodass Empfänger überprüfen können, dass die Nachricht nicht manipuliert wurde.

DKIM in der App erzeugen — keinen Schlüssel selbst basteln

Nutzen Sie einen DKIM-Weg: den Ablauf Domain hinzufügen in der App. Wenn Sie eine Domain hinzufügen, erzeugt der eingebaute MTA das RSA-Schlüsselpaar mit 2048 Bit für Sie, speichert den privaten Schlüssel in Redis und zeigt Ihnen den exakten DNS-TXT-Record, den Sie veröffentlichen müssen. Erzeugen Sie für dieselbe Domain nicht zusätzlich einen Schlüssel mit openssl und setzen ihn über DKIM_KEYS — der Ablauf „Domain hinzufügen“ vergibt einen eigenen Selector (s{timestamp}) und überschreibt den Redis-Schlüssel, sodass ein von Hand erzeugter s1-Schlüssel nicht mehr zu dem passt, womit der MTA signiert, und DKIM bricht.

1. Schlüssel erzeugen (in der App)

  1. Öffnen Sie Einstellungen > Technisch > Versanddomains.
  2. Klicken Sie auf Domain hinzufügen und geben Sie Ihre Domain ein.
  3. Der MTA erzeugt ein Schlüsselpaar und zeigt einen DKIM-TXT-Record unter <selector>._domainkey.example.com an, wobei <selector> der automatisch vergebene Selector ist (zum Beispiel s1718000000000).

2. DNS-TXT-Record hinzufügen

Veröffentlichen Sie den TXT-Record exakt so, wie die Oberfläche ihn anzeigt, unter dem angezeigten Selector-Host:

s1718000000000._domainkey.example.com.    TXT    "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
Länge von DNS-TXT-Records

Ist Ihr öffentlicher Schlüssel länger als 255 Zeichen, müssen Sie ihn im TXT-Record eventuell auf mehrere Zeichenketten in Anführungszeichen aufteilen. Die meisten DNS-Anbieter erledigen das automatisch.

Klicken Sie anschließend in der Oberfläche auf Verifizieren, um zu bestätigen, dass der Eintrag aktiv ist.

Schlüssel über die Umgebungsvariable DKIM_KEYS vorbelegen (optional)

DKIM_KEYS dient ausschließlich dazu, einen bestehenden DKIM-Schlüssel in einen frischen Self-Host zu migrieren (etwa beim Anbieterwechsel, wenn Sie Ihren bereits veröffentlichten s1-Record behalten wollen). Der MTA legt diese Schlüssel beim Start in Redis ab, und zwar nur, wenn für die betreffende Domain noch kein Schlüssel existiert — einen vom Ablauf „Domain hinzufügen“ erzeugten Schlüssel überschreibt er nie.

Wenn Sie DKIM_KEYS für eine Domain verwenden, klicken Sie für diese nicht zusätzlich auf Domain hinzufügen: Der Ablauf in der App ist der kanonische Weg, und das Registrieren einer Domain ohne vorhandenen Schlüssel würde einen neuen Selector erzeugen. Wählen Sie pro Domain einen Weg — den Ablauf in der App für neue Domains, DKIM_KEYS nur zur Übernahme eines bereits vorhandenen Schlüssels.

DKIM_KEYS={"example.com":{"selector":"s1","privateKey":"-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAK...\n-----END RSA PRIVATE KEY-----\n"}}

Das JSON-Format unterstützt mehrere Domains:

{
  "example.com": {
    "selector": "s1",
    "privateKey": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----\n"
  },
  "anotherdomain.com": {
    "selector": "s1",
    "privateKey": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----\n"
  }
}

DMARC

DMARC teilt empfangenden Servern mit, was zu tun ist, wenn SPF- oder DKIM-Prüfungen fehlschlagen. Fügen Sie einen TXT-Record unter _dmarc.example.com hinzu:

_dmarc.example.com.    TXT    "v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@example.com"
PolicyVerhalten
p=noneNur Beobachtung — keine Maßnahme bei Fehlschlägen (gut für die Ersteinrichtung)
p=quarantineFehlschlagende Nachrichten in den Spam-Ordner zustellen
p=rejectFehlschlagende Nachrichten vollständig abweisen (am striktesten)

Beginnen Sie mit p=none, während Sie Ihr Setup überprüfen, und wechseln Sie auf p=quarantine oder p=reject, sobald alles funktioniert.

IP-Pools

Der MTA unterstützt getrennte IP-Pools für transaktionale E-Mails und Kampagnen. Das schützt die Reputation Ihrer transaktionalen E-Mails davor, von Marketingkampagnen beeinträchtigt zu werden.

# In .env
IP_POOLS_TRANSACTIONAL=203.0.113.10
IP_POOLS_CAMPAIGN=203.0.113.11,203.0.113.12

Jede IP in einem Pool benötigt einen eigenen PTR-Record und muss in Ihrem SPF-Record enthalten sein. Führen Sie nach Änderungen am Reverse DNS owlat doctor aus. Das Kommando meldet den exakten PTR-Wert, den Owlat erwartet, sowie passgenaue Konsolenschritte für Hetzner, DigitalOcean und OVHcloud.

Optionales ausgehendes IPv6

Ausgehendes IPv6 ist standardmäßig aus, weil es keinen automatischen Vorteil für die Zustellbarkeit bringt und Empfänger bei unvollständiger Identität unnachgiebig sind. Die IPv6-Bridge von Docker stellt Ihnen zudem keine öffentliche Adresse bereit. Halten Sie IPv4 funktionsfähig und aktivieren Sie IPv6 nur in dieser Reihenfolge:

  1. Weisen Sie dem MTA-Host/-Container eine stabile, öffentlich geroutete IPv6-Adresse zu und stellen Sie sicher, dass die quellgebundene SMTP-Probe sie nutzen kann.
  2. Setzen Sie den PTR dieser Adresse auf ihren nicht generischen EHLO-Hostnamen. dig -x 2001:db8::10 muss genau diesen FQDN zurückgeben.
  3. Veröffentlichen Sie einen AAAA-Record, der vom EHLO-Hostnamen zurück auf exakt diese Adresse zeigt.
  4. Fügen Sie ip6:2001:db8::10 den SPF-Records für Versand und Return-Path hinzu. Der MTA-Domain-Generator von Owlat gibt ip6: automatisch aus kanonischen IPv6-Werten in MTA_IP_POOLS aus.
  5. Erst dann setzen Sie MTA_IPV6_ENABLED=true und tragen die nackte Adresse (ohne Klammern, Port, CIDR oder Zone-ID) in IP_POOLS_* ein.

Owlat prüft dies als tatsächlichen Live-Zustand, nicht als manuelles Häkchen. Jede IPv4-Identität muss grün bleiben; IPv6-PTR/AAAA und der exakte Return-Path-SPF werden stündlich erneut geprüft. Eine bestätigte Regression stellt IPv6 unter Quarantäne und invalidiert dessen gepoolte Sockets, während geeignetes IPv4 weiterläuft.

Anbieterwege, gegen deren aktuelle Dokumentation geprüft:

  • Hetzner Cloud rDNS akzeptiert den IPv6-Interface-Identifier unter Console → Server → Networking.
  • DigitalOcean IPv6 muss auf dem Droplet aktiviert und geroutet sein; DigitalOcean dokumentiert das Anlegen eines PTR aus einem gültigen FQDN-Droplet-Namen und unterstützt PTR nur für die zuerst zugewiesene IPv6-Adresse.
  • OVHcloud Reverse DNS findet sich unter Network → Public IP Addresses → Configure reverse DNS. Vergewissern Sie sich, dass Ihr Produkt die gewählte IPv6 dort überhaupt anbietet, bevor Sie sie einem Pool hinzufügen; die zitierten Anbieteranleitungen dokumentieren keine Delegation der Reverse-Zone.
Setup mit einer einzelnen IP

Wenn Sie nur eine IP-Adresse haben, verwenden Sie sie für beide Pools. Eine Trennung der Reputation ist dann nicht möglich, aber alles funktioniert korrekt.

IP-Warming

Neue IPs haben keine Reputation

Frische IP-Adressen haben keine Versandreputation. Sofort große Volumen zu versenden löst Spamfilter aus und kann dazu führen, dass Ihre IP auf einer Blockliste landet. Steigern Sie das Volumen über 2–4 Wochen schrittweise.

Owlat erzwingt einen im Code hinterlegten adaptiven Zeitplan statt allgemeiner Wochenschätzungen. Er beginnt am Warming-Tag 1 mit 50 Nachrichten pro IP, erreicht bis Tag 25 Checkpoint-Obergrenzen und hebt die Obergrenze ab Tag 30 erst dann auf, wenn das Gesundheits-Gate für die Graduierung bestanden ist. Tage ohne Versand bringen den Zustand nicht voran; gute Signale können ihn beschleunigen, während Bounces und Deferrals ihn verlangsamen oder pausieren.

Unter Versand von einem VPS — So sehen die Warming-Wochen 1–4 aus finden Sie die exakten, testabgesicherten Checkpoints und adaptiven Schwellenwerte. Konzentrieren Sie sich zuerst auf aktuelle, ausdrückliche Opt-ins, die die Nachricht erwarten.

Überprüfung

Sobald Ihre DNS-Einträge konfiguriert sind:

  1. Überprüfung in der App — der Domain-Verifizierungsablauf von Owlat prüft SPF-, DKIM- und DMARC-Einträge automatisch. Details finden Sie unter Zustellbarkeit.
  2. Externe Tests — senden Sie eine Test-E-Mail an mail-tester.com und streben Sie eine Bewertung von 9+/10 an.
  3. Manuelle Prüfungen:
    # Verify SPF
    dig TXT example.com +short
    
    # Verify DKIM (use the selector the Add-domain flow displayed)
    dig TXT s1718000000000._domainkey.example.com +short
    
    # Verify DMARC
    dig TXT _dmarc.example.com +short
    
    # Verify PTR
    dig -x 203.0.113.10 +short
    

Details zur MTA-Architektur, zum Rate Limiting und zur Bounce-Verarbeitung finden Sie unter MTA-System.