diff --git a/backend/routes/outreach.py b/backend/routes/outreach.py index 11f4152..ab4e7fb 100644 --- a/backend/routes/outreach.py +++ b/backend/routes/outreach.py @@ -1,5 +1,6 @@ """BAN YARO — Mailing (Admin)""" +import imaplib import os import smtplib import ssl @@ -19,6 +20,8 @@ router = APIRouter() _SMTP_HOST = os.getenv("SMTP_HOST", "mail.your-server.de") _SMTP_PORT = int(os.getenv("SMTP_PORT", "587")) +_IMAP_HOST = os.getenv("IMAP_HOST", "mail.your-server.de") +_IMAP_PORT = int(os.getenv("IMAP_PORT", "993")) _ACCOUNTS = { "partner": { @@ -35,23 +38,62 @@ _ACCOUNTS = { }, } +# Mögliche Namen für den Sent-Ordner (Hetzner/Dovecot) +_SENT_CANDIDATES = ["Sent", "Sent Messages", "Sent Items", "INBOX.Sent", "Gesendete Objekte"] + + +def _imap_save_sent(msg_bytes: bytes, account: str): + acc = _ACCOUNTS.get(account) or _ACCOUNTS["partner"] + if not acc["user"] or not acc["pass"]: + 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 + 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 + break + if not folder: + folder = "Sent" # Fallback: anlegen lassen + imap.append( + folder, + r"\Seen", + imaplib.Time2Internaldate(datetime.now().timestamp()), + msg_bytes, + ) + except Exception: + pass # Nicht blockieren wenn IMAP fehlschlägt + + +def _build_message(to: str, subject: str, body: str, account: str) -> MIMEMultipart: + acc = _ACCOUNTS.get(account) or _ACCOUNTS["partner"] + msg = MIMEMultipart("alternative") + msg["Subject"] = subject + msg["From"] = formataddr((acc["name"], acc["from"])) + msg["To"] = to + msg["Reply-To"] = acc["from"] + msg.attach(MIMEText(body, "plain", "utf-8")) + return msg + def _send_smtp(to: str, subject: str, body: str, account: str = "partner"): acc = _ACCOUNTS.get(account) or _ACCOUNTS["partner"] if not acc["user"] or not acc["pass"]: raise RuntimeError(f"SMTP-Account '{account}' nicht konfiguriert.") - msg = MIMEMultipart("alternative") - msg["Subject"] = subject - msg["From"] = formataddr((acc["name"], acc["from"])) - msg["To"] = to - msg["Reply-To"] = acc["from"] - msg.attach(MIMEText(body, "plain", "utf-8")) + msg = _build_message(to, subject, body, account) + msg_bytes = msg.as_bytes() ctx = ssl.create_default_context() with smtplib.SMTP(_SMTP_HOST, _SMTP_PORT, timeout=15) as s: s.ehlo() s.starttls(context=ctx) s.login(acc["user"], acc["pass"]) - s.sendmail(acc["from"], [to], msg.as_bytes()) + s.sendmail(acc["from"], [to], msg_bytes) + _imap_save_sent(msg_bytes, account) # ------------------------------------------------------------------