# PROJ-4: E-Mail-Import: SMTP-Eingang (primär via BCC) ## Status: In Progress **Created:** 2026-03-12 **Last Updated:** 2026-03-12 ## Hinweis **Dies ist der primäre Eingangsweg.** archivmail enthält einen eingebetteten SMTP-Daemon, der **ausschließlich E-Mails empfängt** – kein Versand, keine Weiterleitung, kein MTA. Postfix (oder ein anderer Mailserver) wird per BCC-Mapping oder Always-BCC-Regel so konfiguriert, dass er eine Kopie jeder E-Mail an archivmails SMTP-Daemon zustellt. ``` Absender → Postfix (MTA) → Empfänger │ └── BCC/always_bcc → archivmail SMTP-Daemon (nur Empfang) │ ▼ Storage Coordinator ``` IMAP und EML/MBOX-Upload sind sekundäre/ergänzende Methoden (z.B. für Altbestände). ## Dependencies - Requires: PROJ-5 (Speicherung & Indexierung) – eingehende E-Mails werden gespeichert - Kein Login nötig für den Empfang – SMTP-Eingang läuft unabhängig vom HTTP-Server ## User Stories - Als Mailserver möchte ich E-Mails per BCC an archivmail zustellen, damit diese automatisch archiviert werden. - Als Admin möchte ich den eingebetteten SMTP-Server konfigurieren (Port, TLS, erlaubte Absender-IPs). - Als Admin möchte ich festlegen, welche Absender-IPs/Domains akzeptiert werden, damit nur der eigene Mailserver zustellen darf. - Als System möchte ich eingehende E-Mails sofort nach Empfang indexieren, damit sie innerhalb von Sekunden durchsuchbar sind. - Als Admin möchte ich den Status des SMTP-Empfängers sehen (läuft, Port, letzte empfangene E-Mail). ## Acceptance Criteria - [ ] Eingebetteter SMTP-Server lauscht auf konfigurierbarem Port (Standard: 25 oder 2525) - [ ] TLS/STARTTLS-Unterstützung für verschlüsselte Übertragung - [ ] IP-Allowlist: nur eingetragene Mailserver-IPs dürfen zustellen (Standard: nur localhost/127.0.0.1) - [ ] Optionale Domain-Allowlist als zusätzliche Prüfebene - [ ] E-Mails werden sofort nach Empfang gespeichert und indexiert - [ ] SMTP-Quittierung (250 OK) erst nach erfolgreicher Speicherung - [ ] Admin-UI zeigt: Port, TLS-Status, Anzahl empfangener E-Mails, letzte Aktivität - [ ] Fehlerhafte/abgelehnte E-Mails werden geloggt ## Edge Cases - E-Mail ohne Absender (Envelope-From leer) → annehmen aber markieren - Sehr große E-Mail (> 50 MB) → konfigurierbare Maximalgröße, Ablehnung mit 552-Fehlercode - SMTP-Server-Port bereits belegt → klare Fehlermeldung beim Start - Parallele Verbindungen (viele E-Mails gleichzeitig) → Connection-Pooling - Duplicate Message-ID → überspringen wie bei anderen Import-Methoden ## Technical Requirements - RFC 5321 (SMTP) konformer **reiner Empfänger** – kein SMTP-Versand, keine Queue, kein Relay - Kein SMTP AUTH – Zugang ausschließlich über IP-Allowlist (nur Postfix-IP eingetragen) - Maximale Nachrichtengröße konfigurierbar (Standard: 50 MB) - Startet als eigenständiger Goroutine/Service neben dem HTTP-Server - Postfix-Konfiguration (außerhalb von archivmail, Dokumentation in README): - `always_bcc = archiv@archivmail-host` in Postfix `main.cf`, oder - Sender/Recipient BCC-Maps für granulare Kontrolle --- ## Tech Design (Solution Architect) ### Systemübersicht ``` Absender → Postfix (MTA) → Empfänger (normale Zustellung) │ └── always_bcc / BCC-Map │ ▼ SMTP (Port 2525) archivmail SMTP-Daemon (nur Empfang, kein Versand) │ ▼ Storage Coordinator (PROJ-5) (speichern + indexieren) ``` ### Komponentenstruktur ``` archivmail (Go-Binary) │ ├── HTTP-Server (Web-GUI + API) │ └── SMTP-Daemon ← startet parallel zum HTTP-Server ├── TCP Acceptor ← lauscht auf Port 2525 (konfigurierbar) ├── IP Allowlist Guard ← prüft Absender-IP vor SMTP-Dialog ├── Session Handler (pro Verbindung, eigene Goroutine) │ ├── TLS/STARTTLS Handler ← optional, Zertifikat aus config.yml │ └── Size Limiter ← bricht DATA-Phase bei Überschreitung ab └── Handoff → Storage Coordinator ← übergibt E-Mail nach vollständigem Empfang ``` ### SMTP-Dialogfluss ``` Postfix │ TCP-Verbindung auf Port 2525 ▼ IP Allowlist Guard ├─ IP unbekannt → Verbindung trennen (kein SMTP-Dialog) └─ IP erlaubt → weiter │ ▼ 220 archivmail SMTP ready │ EHLO mail.firma.de 250 OK (kein AUTH angeboten – reiner Empfänger) │ MAIL FROM: 250 OK │ RCPT TO: 250 OK │ DATA 354 Start input … E-Mail-Inhalt … (max. 50 MB) . │ ├─ Zu groß → 552 Message size exceeds limit ├─ Duplikat (Message-ID) → 250 OK (still, kein Fehler – Postfix soll nicht retrying) └─ Neu → Storage Coordinator → verschlüsselt speichern + indexieren │ ▼ 250 OK ← erst nach erfolgreicher Speicherung │ QUIT ``` ### Technische Entscheidungen | Entscheidung | Begründung | |---|---| | **Reiner Empfänger, kein MTA** | archivmail ist kein Mailserver – keine ausgehende Queue, kein Relay-Risiko, kein Open-Relay | | **Kein SMTP AUTH** | Vertrauen basiert auf IP, nicht auf Passwort – Postfix und archivmail laufen im gleichen Netz | | **250 OK bei Duplikat** | Postfix würde bei Fehler die Mail in die Retry-Queue stellen – sinnlos, da Duplikat bereits archiviert | | **250 OK erst nach Speicherung** | Solange Postfix keine Bestätigung hat, behält er die Mail und versucht erneut – kein Datenverlust | | **Port 2525** | Port 25 erfordert root-Rechte; 2525 läuft als unprivilegierter `archivmail`-Systembenutzer | | **Eine Goroutine pro Session** | Viele parallele Verbindungen ohne Blocking; jede Session ist isoliert | ### Postfix-Konfiguration (Dokumentation, außerhalb von archivmail) ``` # /etc/postfix/main.cf – einfachste Variante (alle Mails) always_bcc = archiv@archivmail-host # Oder granular per Sender-BCC-Map: # sender_bcc_maps = hash:/etc/postfix/sender_bcc # empfänger@firma.de archiv@archivmail-host ``` ### Go-Abhängigkeiten | Paket | Zweck | |---|---| | `github.com/emersion/go-smtp` | Eingebetteter SMTP-Daemon (RFC 5321, nur Empfang) | | `crypto/tls` | TLS/STARTTLS (Go Stdlib) | | `net` | IP-Prüfung (Go Stdlib) | ## QA Test Results _To be added by /qa_ ## Deployment _To be added by /deploy_