Fix: IMAP Sent-Ordner — echten Namen aus LIST-Antwort extrahieren (INBOX.Sent)

This commit is contained in:
rene 2026-04-30 20:03:23 +02:00
parent 31fae63658
commit 4c6dd07c31

View file

@ -10,13 +10,16 @@ from email.utils import formataddr
from datetime import datetime
from typing import List, Optional
import logging
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from auth import require_admin
from database import db
router = APIRouter()
router = APIRouter()
_log = logging.getLogger(__name__)
_SMTP_HOST = os.getenv("SMTP_HOST", "mail.your-server.de")
_SMTP_PORT = int(os.getenv("SMTP_PORT", "587"))
@ -45,29 +48,40 @@ _SENT_CANDIDATES = ["Sent", "Sent Messages", "Sent Items", "INBOX.Sent", "Gesend
def _imap_save_sent(msg_bytes: bytes, account: str):
acc = _ACCOUNTS.get(account) or _ACCOUNTS["partner"]
if not acc["user"] or not acc["pass"]:
_log.warning("IMAP: Account '%s' nicht konfiguriert, überspringe.", account)
return
try:
ctx = ssl.create_default_context()
with imaplib.IMAP4_SSL(_IMAP_HOST, _IMAP_PORT, ssl_context=ctx) as imap:
imap.login(acc["user"], acc["pass"])
# Sent-Ordner finden
_, raw_folders = imap.list()
available = [f.decode(errors="replace") for f in (raw_folders or [])]
_log.info("IMAP Ordner (%s): %s", account, available)
# Echten Ordnernamen aus LIST-Antwort extrahieren
# Format: '(\Flags) "." INBOX.Sent' → letztes Token
folder = None
_, folders = imap.list()
available = [f.decode() for f in (folders or [])]
for candidate in _SENT_CANDIDATES:
if any(candidate.lower() in f.lower() for f in available):
folder = candidate
for line in available:
name = line.rsplit('"." ', 1)[-1].strip().strip('"')
for candidate in _SENT_CANDIDATES:
if candidate.lower() in name.lower():
folder = name
break
if folder:
break
if not folder:
folder = "Sent" # Fallback: anlegen lassen
imap.append(
folder = "INBOX.Sent"
_log.info("IMAP: speichere in Ordner '%s' (%s)", folder, account)
typ, data = imap.append(
folder,
r"\Seen",
imaplib.Time2Internaldate(datetime.now().timestamp()),
msg_bytes,
)
except Exception:
pass # Nicht blockieren wenn IMAP fehlschlägt
_log.info("IMAP append: %s %s", typ, data)
except Exception as e:
_log.error("IMAP Sent-Speicherung fehlgeschlagen (%s): %s", account, e)
def _build_message(to: str, subject: str, body: str, account: str) -> MIMEMultipart: