from __future__ import annotations import smtplib from email.utils import parseaddr from django.conf import settings from django.core.mail.backends.base import BaseEmailBackend from apps.core.services.microsoft365 import ( Microsoft365OAuthError, acquire_exchange_access_token, xoauth2_b64, ) from apps.sources.services.tls import trusted_tls_context class Microsoft365OAuthEmailBackend(BaseEmailBackend): """Send mail through Exchange Online with app-only SASL XOAUTH2.""" def send_messages(self, email_messages) -> int: if not email_messages: return 0 sent = 0 try: token = acquire_exchange_access_token() username = settings.M365_MAILBOX_USER.strip() if not username: raise Microsoft365OAuthError( "M365_MAILBOX_USER is verplicht voor Microsoft 365-mailuitvoer." ) with smtplib.SMTP( settings.EMAIL_HOST or "smtp.office365.com", settings.EMAIL_PORT, timeout=settings.M365_SMTP_TIMEOUT_SECONDS, ) as client: client.ehlo() client.starttls(context=trusted_tls_context()) client.ehlo() code, _ = client.docmd("AUTH", f"XOAUTH2 {xoauth2_b64(username, token)}") if code != 235: raise Microsoft365OAuthError("Microsoft 365 SMTP OAuth geweigerd.") for message in email_messages: recipients = message.recipients() if not recipients: continue sender = parseaddr(message.from_email or settings.DEFAULT_FROM_EMAIL)[1] client.sendmail( sender or username, recipients, message.message().as_bytes(linesep="\r\n"), ) sent += 1 except Exception: if self.fail_silently: return sent raise return sent