ADR-005: Eigener MTA
Warum Owlat einen eigenen Mail Transfer Agent gebaut hat, statt sich ausschließlich auf E-Mail-Anbieter von Drittanbietern zu verlassen.
- Status: Angenommen
- Datum: 2025-03-20
Kontext
Owlat war für die E-Mail-Zustellung früher vollständig von AWS SES und Resend abhängig. Diese Anbieter bieten zwar zuverlässige APIs und Managed Infrastructure, bringen im großen Maßstab jedoch Einschränkungen mit sich:
- Kosten — die Preisbildung pro E-Mail skaliert linear. Versender mit hohem Volumen zahlen deutlich mehr als die Kosten einer direkten SMTP-Zustellung von dedizierten IPs.
- Kontrolle über die Zustellbarkeit — Drittanbieter verwalten die Reputation gemeinsam genutzter und dedizierter IPs stellvertretend für viele Kunden. Owlat hat keine Möglichkeit, ISP-spezifisches Throttling, IP-Warming-Zeitpläne oder engagementbasierte Sendepriorität umzusetzen.
- Bounce-Latenz — Bounce- und Beschwerdedaten treffen mit variabler Verzögerung über Anbieter-Webhooks ein, was eine schnelle Reaktion auf Reputationsprobleme erschwert.
- Rate Limits — vom Anbieter auferlegte Sendekontingente (insbesondere in der SES-Sandbox) begrenzen den Kampagnendurchsatz. Owlat kann den Backpressure pro ISP nicht eigenständig steuern.
Die wesentlichen Optionen:
- Nur SES/Resend beibehalten — operativ am einfachsten, doch die Einschränkungen bei Kosten und Kontrolle bleiben bestehen.
- Einen eigenen MTA bauen — direkte SMTP-Zustellung mit voller Kontrolle über IPs, Throttling, Warming und Bounce-Verarbeitung. Höhere Infrastrukturkomplexität, dafür deutlich geringere Kosten pro E-Mail und bessere Feinabstimmung der Zustellbarkeit.
- Einen Open-Source-MTA verwenden (Postfix, Haraka) — erspart den Bau von Grund auf, erfordert aber die Anpassung universeller Software an Owlats spezifische Anforderungen (GroupMQ-Integration, Circuit Breaker pro Organisation, Engagement-Priorität).
Entscheidung
Einen eigenen MTA als eigenständigen Dienst (apps/mta/) bauen, der E-Mail per direkter SMTP-Zustellung an die Mailserver der Empfänger versendet. Der MTA ist einer von drei auswählbaren Zustellanbietern (mta|resend|ses), gewählt über EMAIL_PROVIDER oder über das Send-Provider-Routing pro Organisation (apps/api/convex/lib/sendProviders/routing.ts, genutzt über apps/api/convex/lib/sendProviders/route.ts). Es gibt keinen impliziten Standard — ist kein Anbieter konfiguriert, löst die Route zu null auf und die Instanz ist fail-closed (versendet nichts).
Der Dienst ist seither über den ausgehenden Versand hinausgewachsen und übernimmt inzwischen auch eingehendes Routing/Weiterleiten (apps/mta/src/inbound/) sowie die Zustellbarkeitsfläche rund um SMTP — DKIM-Schlüsselverwaltung und -Rotation, MTA-STS und TLS-RPT (apps/mta/src/smtp/). Die nachstehende Sendeentscheidung bleibt der Kern dieses ADR.
Zentrale Designentscheidungen:
- Hono-HTTP-API — leichtgewichtiger, standardkonformer HTTP-Server zur Entgegennahme von Sendeanfragen aus dem Convex-Backend. Zu den Endpunkten zählen
/send,/healthund/metrics, dazu Admin-/Verwaltungsrouten (/credentials,/org-limits,/suppression,/dkim,/pool-rules,/isp-profiles,/ip-reputation,/queue,/dlq,/delivery-logs,/scan) sowie eingehendes Routing (/inbound/routes,/mailboxes). - GroupMQ + Redis — Job-Queue mit gruppenbasierter Verarbeitung. Jobs werden nach
{ipPool}:{recipientDomain}gruppiert, sodass E-Mails an denselben ISP aus demselben IP-Pool sequenziell verarbeitet werden und Rate Limits pro Domain eingehalten werden. - Dispatch-Pipeline — eine zusammengesetzte Pipeline (
apps/mta/src/dispatch/phases/) führt vor jeder Zustellung Prüfungen pro Versuch aus: Inhaltsprüfung, Suppression, Circuit Breaker pro Organisation, Rate Limits pro Organisation, auf SMTP-Antworten basierendes Throttling (smtpIntel), Domain-Backoff, Auflösung und Auswahl des IP-Pools, Slot-Belegung und Warming-Obergrenzen. Zwei verwandte Belange laufen außerhalb der Pipeline pro Sendung: Engagement-Priorität wird beim Einreihen als GroupMQ-Ordnung angewendet (apps/mta/src/routes/send.ts,apps/mta/src/queue/groups.ts), und DNSBL-Monitoring ist eine 15-minütige Hintergrundprüfung, die gelistete IPs aus dem aktiven Pool entfernt (apps/mta/src/intelligence/dnsbl.ts). - VERP-Return-Path — die Variable-Envelope-Return-Path-Kodierung korreliert Bounce-Nachrichten mit den ursprünglichen Sendungen, ohne dass eine Lookup-Tabelle gepflegt werden muss.
- Webhook-Rückkopplung — Zustellereignisse (gesendet, gebounct, beschwert) werden über authentifizierte Webhooks an das Convex-Backend zurückgemeldet und nutzen die bestehende Bounce-/Beschwerde-Verarbeitungspipeline weiter.
Konsequenzen
Ermöglicht:
- Adaptives Rate Limiting pro ISP (Gmail 100/min, Outlook 80/min, Yahoo 50/min) mit automatischem Backoff bei 4xx-Antworten
- Automatisiertes IP-Warming über 30 Tage mit adaptiver Beschleunigung/Verlangsamung anhand von Zustellbarkeitssignalen
- Engagementbasierte Sendepriorität — Kontakte mit hohem Engagement werden zuerst beliefert
- Circuit Breaker pro Organisation — pausiert den Versand automatisch, wenn Bounce-Raten Schwellenwerte überschreiten
- DNS-Blocklist-Monitoring mit automatischer Entfernung von IPs aus dem aktiven Pool
- Direkte Kosteneinsparungen im großen Maßstab (keine API-Gebühren pro E-Mail über die Infrastruktur hinaus)
- Vollständige Bounce-/Beschwerde-Verarbeitungspipeline mit DSN-Parsing und ARF-/FBL-Unterstützung
Abwägungen:
- Erfordert dedizierte IPs mit korrekten rDNS-/PTR-Records und DKIM-Schlüsselverwaltung
- Infrastrukturkomplexität: Redis für Zustand, Zugang zu SMTP-Port 25, separater containerisierter Dienst
- Operativer Aufwand: DNSBL-Listungen überwachen, IP-Warming steuern, Zustellbarkeitsprobleme untersuchen
- Alle drei Anbieter (mta, resend, ses) sind explizite Opt-in-Entscheidungen über
EMAIL_PROVIDER/ das Send-Provider-Routing pro Organisation; der MTA ist kein impliziter Standard-Zustellweg — eine nicht konfigurierte Instanz ist fail-closed und versendet nichts
Vergleich mit Alternativen
| Fähigkeit | Owlat MTA | Postal | SES/Resend |
|---|---|---|---|
| Adaptives Throttling pro ISP | Ja (10+ ISP-Profile) | Nein | Vom Anbieter verwaltet |
| IP-Warming | Ja (30 Tage, adaptiv) | Nein | Vom Anbieter verwaltet |
| Circuit Breaker pro Organisation | Ja (3 Zustände) | Nein | Nein |
| Engagementbasierte Priorität | Ja | Nein | Nein |
| DNSBL-Auto-Remediation | Ja (15-Minuten-Prüfungen) | Nein | Vom Anbieter verwaltet |
| Nachrichtenspeicherung/-suche | Nein | Ja (MySQL pro Server) | Nein |
| Web-Admin-UI | Nein | Ja (Rails-Dashboard) | Anbieterkonsole |
| Spam-Inhaltsbewertung | Ja (Prüfung pro Sendung: Pflichtfelder, DKIM-Alignment, Größe, URL-Blocklist sowie optionales Rspamd-Scoring; Malware-Scan von Anhängen über ClamAV/@owlat/email-scanner) | Ja (einsteckbare Inspektoren) | Vom Anbieter verwaltet |
| Klick-/Öffnungs-Tracking | Nein (Plattformschicht) | Ja (integriert) | Vom Anbieter verwaltet |
| Kosten im großen Maßstab | Niedrig (nur Infrastruktur) | Niedrig (selbst gehostet) | Hoch (pro E-Mail) |