Feature: Gesendete Mails via IMAP in Sent-Ordner ablegen

This commit is contained in:
rene 2026-04-30 19:54:51 +02:00
parent b9ee67b8dd
commit 31fae63658

View file

@ -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)
# ------------------------------------------------------------------