feat: Weitergeleitete Bank-Mails erkennen und Uebergangenes zeigen
Wer Bank-Mails in ein Sammelpostfach weiterleitet, hat im From je nach Methode die eigene Adresse stehen. Geprueft werden deshalb auch Reply-To, Return-Path, Sender und X-Forwarded-For – bei automatischer Weiterleitung bleibt der Originalabsender dort erhalten. Ausserdem meldet der Abruf jetzt, welche Mails er uebergangen hat, mit Absender und Betreff. Beim Einrichten war das sonst Raten: Man sah nur "3 uebersprungen" und wusste nicht, was in den Filter gehoert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -119,6 +119,20 @@ def _text_der_mail(msg) -> tuple[str, str]:
|
||||
return betreff, ""
|
||||
|
||||
|
||||
def _absenderfeld(msg) -> str:
|
||||
"""Alles, was den ursprünglichen Absender verraten kann.
|
||||
|
||||
Leitet ein Postfach automatisch weiter, bleibt ``From`` meist der
|
||||
Originalabsender – verlassen kann man sich darauf aber nicht. Gmail und
|
||||
andere setzen zusätzlich ``X-Forwarded-For``; bei manueller Weiterleitung
|
||||
steht die eigene Adresse im ``From`` und die ursprüngliche höchstens im
|
||||
``Reply-To``. Geprüft wird deshalb alles zusammen.
|
||||
"""
|
||||
teile = [str(msg[k] or "") for k in
|
||||
("From", "Reply-To", "Return-Path", "X-Forwarded-For", "X-Original-From", "Sender")]
|
||||
return " ".join(t for t in teile if t)
|
||||
|
||||
|
||||
def _passender_absender(absender: list[MailSender], von: str, betreff: str) -> MailSender | None:
|
||||
"""Erste Zuordnung, deren Filter greifen. Ohne Filter passt sie auf alles."""
|
||||
von_klein, betreff_klein = von.lower(), betreff.lower()
|
||||
@@ -151,6 +165,9 @@ def hole_neue(db: Session, quelle: MailSource) -> dict:
|
||||
|
||||
verbindung = _verbinden(quelle)
|
||||
neu = uebersprungen = unklar = 0
|
||||
# Was durchgefallen ist, mit Absender und Betreff – sonst raet man beim
|
||||
# Einrichten, was in den Filter gehoert.
|
||||
ohne_zuordnung: list[dict] = []
|
||||
try:
|
||||
code, _ = verbindung.select(f'"{quelle.folder}"')
|
||||
if code != "OK":
|
||||
@@ -180,10 +197,15 @@ def hole_neue(db: Session, quelle: MailSource) -> dict:
|
||||
continue
|
||||
|
||||
betreff, text = _text_der_mail(msg)
|
||||
von = str(msg["From"] or "")
|
||||
von = _absenderfeld(msg)
|
||||
zuordnung = _passender_absender(absender, von, betreff)
|
||||
if zuordnung is None:
|
||||
uebersprungen += 1
|
||||
if len(ohne_zuordnung) < 5:
|
||||
ohne_zuordnung.append({
|
||||
"from": str(msg["From"] or "")[:120],
|
||||
"subject": betreff[:120],
|
||||
})
|
||||
continue
|
||||
|
||||
gesendet = None
|
||||
@@ -228,7 +250,8 @@ def hole_neue(db: Session, quelle: MailSource) -> dict:
|
||||
verbindung.logout()
|
||||
except Exception:
|
||||
pass
|
||||
return {"neu": neu, "uebersprungen": uebersprungen, "unklar": unklar}
|
||||
return {"neu": neu, "uebersprungen": uebersprungen, "unklar": unklar,
|
||||
"ohne_zuordnung": ohne_zuordnung}
|
||||
|
||||
|
||||
def _nachbereiten(verbindung: imaplib.IMAP4, quelle: MailSource, uid: bytes) -> None:
|
||||
@@ -253,4 +276,5 @@ def abruf_mit_fehlerbehandlung(db: Session, quelle: MailSource) -> dict:
|
||||
quelle.last_error = str(e)[:500]
|
||||
quelle.last_poll_at = datetime.now(timezone.utc)
|
||||
db.commit()
|
||||
return {"neu": 0, "uebersprungen": 0, "unklar": 0, "fehler": str(e)}
|
||||
return {"neu": 0, "uebersprungen": 0, "unklar": 0,
|
||||
"ohne_zuordnung": [], "fehler": str(e)}
|
||||
|
||||
Reference in New Issue
Block a user