feat: Postfaecher einrichten und Zahlungs-Mails abholen (Etappe B, Teil 2)

- Verschluesselung fuer Zugangsdaten: Ein IMAP-Passwort laesst sich nicht
  hashen, Certain muss es dem Mailserver vorlegen. Es liegt deshalb mit
  Fernet verschluesselt in der Datenbank, der Schluessel wird per HKDF aus
  session_secret abgeleitet und nirgends gespeichert. Wird das Geheimnis
  getauscht, meldet Certain das verstaendlich statt mit einem Stacktrace.
- IMAP-Abruf ueber imaplib/email (Standardbibliothek). Ordnerliste,
  Verbindungstest mit klarer Fehlermeldung, Absender-Zuordnung auf Konten,
  danach als gelesen markieren oder verschieben.
- Wiedererkennung ueber die Message-ID statt der UID – die vergibt der
  Server beim Verschieben neu.
- Nichts wird stillschweigend gebucht: Eine Mail wird zum Eingangs-Eintrag.
  Fehlt das Zielkonto oder ist ein Feld unsicher, gilt sie als unklar.
- Hintergrund-Thread beim Start, nach dem Muster des EZB-Kursabrufs: ein
  langsames Postfach darf den Dienst nie blockieren.

Getestet gegen einen IMAP-Doppelgaenger, damit die Suite ohne Netz laeuft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-08-22 19:58:06 +02:00
co-authored by Claude Opus 5
parent 259013eafe
commit fc6ee2f345
9 changed files with 839 additions and 0 deletions
+1
View File
@@ -18,3 +18,4 @@ pytesseract==0.3.13
pillow==11.1.0
pytest==8.3.4
cryptography==50.0.0