# ING-02 — POP3-Server: Prüfprotokoll Datum: 2026-09-01 Host: 192.168.1.131 (Build/Test/Lint), rsync + ssh Paket: `mail/internal/pop3` ## Umsetzung Vollständiger POP3-Server (RFC 1939) von Grund auf implementiert: TCP-Listener, CRLF/Byte-Stuffing-sichere Response-Writer, Session-Zustandsmaschine (Authorization / Transaction / Update), Kommandos USER, PASS, STAT, LIST, RETR, DELE, QUIT. Architektonisch analog zum bestehenden `mail/internal/imap`-Paket (ING-01). ## Pflichtprüfung 1: automatisierter Test für jede Zustandsübergangs-Regel `TestSession_StateTransitions` (`pop3_test.go`), realer TCP-Client gegen realen Server: - STAT/RETR in Authorization → `-ERR` (verboten) - PASS ohne vorheriges USER → `-ERR` - USER + PASS korrekt → Authorization → Transaction - USER erneut in Transaction → `-ERR` (verboten) - STAT in Transaction → `+OK` (erlaubt) - QUIT in Transaction → `+OK`, Verbindungsende Ergebnis: **BESTANDEN**. ## Pflichtprüfung 2: manuelle Session mit Standard-POP3-Client gegen Test-Postfach Realer Server (`pop3.NewServer`) auf `127.0.0.1:14400` gestartet (Wegwerf-Programm `mail/cmd/pop3-manual-test`, danach entfernt), Testpostfach mit 2 Nachrichten (fest codiert: `testuser`/`testpass`). Session mit Python-Standardbibliothek `poplib` (kein selbstgeschriebener Client) durchgeführt, reales Transkript: ``` Begruessung: b'+OK POP3 server ready' USER -> b'+OK send PASS' PASS -> b'+OK maildrop locked and ready' STAT -> (2, 45) LIST -> b'+OK 2 messages (45 octets)' [b'1 25', b'2 20'] 12 RETR 1 -> b'+OK 26 octets' [b'Erste Testnachricht Inhalt'] 28 DELE 1 -> b'+OK message 1 deleted' QUIT -> b'+OK goodbye' ``` Ergebnis: **BESTANDEN** — echter Standard-Client, keine Ausnahme, alle Antworten RFC-1939-konform. ## Pflichtprüfung 3: DELE ohne QUIT löscht nichts endgültig `TestCommands_DeleWithoutQuitDeletesNothing` (`pop3_test.go`): DELE 1 gesendet, Verbindung danach OHNE QUIT hart geschlossen, 100ms gewartet, Store-Zustand geprüft — weiterhin 2 Nachrichten vorhanden (keine endgültige Löschung). Strukturell garantiert durch Code-Design: `store.Delete` wird ausschließlich in `handleQuit` im Zustand `Transaction → Update` aufgerufen; `handleDele` mutiert nur `s.deleted` (sitzungslokal). Ergebnis: **BESTANDEN**. ## Akzeptanzkriterien 1. **Jede Verbindung eigene Goroutine**: `Server.Serve` startet pro Accept eine neue Goroutine (`server.go`). Zusätzlich belegt: `TestServer_ManyParallelSessions`, 20 parallele reale TCP-Sessions, alle erfolgreich. 2. **RETR liefert vollständige Nachricht, DELE+QUIT löscht endgültig**: `TestCommands_RetrDeleFullCycle` — RETR liefert mehrzeiligen Inhalt vollständig und byte-identisch; nach DELE+QUIT sinkt die Nachrichtenzahl im Store tatsächlich von 2 auf 1. 3. **Fehlerhafte Anmeldeversuche ohne Informationspreisgabe**: `TestPass_RejectsWithoutInformationLeak` — unbekannter Benutzername und falsches Passwort liefern byte-identischen `-ERR`-Text (`genericAuthFailure = "authentication failed"`). ## Build/Vet/Lint/Test — Gesamtmodul ``` go build ./... → OK go vet ./... → OK golangci-lint run ./... → 0 issues go test ./... -p 1 (TEST_TENANT_DSN, TEST_MANTICORE_URL gesetzt) → alle Pakete ok, inkl. neuem internal/pop3 (0.109s, 5/5 Tests) ``` Keine Regression in den bestehenden ~23 Paketen. ## Ergebnis ING-02 erfüllt alle Pflichtprüfungen und Akzeptanzkriterien mit echten, ausgeführten Nachweisen. Freigeschaltet: ING-06, ING-07, ING-08, ING-10, QA-07.