"""Mailgun email provider implementation.""" import logging import requests from flask import current_app from gatehouse_app.services.email_provider import EmailMessage, EmailProvider logger = logging.getLogger(__name__) class MailgunEmailProvider(EmailProvider): """Mailgun API-based email provider implementation.""" # Configuration keys MAILGUN_API_KEY = "MAILGUN_API_KEY" MAILGUN_DOMAIN = "MAILGUN_DOMAIN" MAILGUN_API_URL = "MAILGUN_API_URL" FROM_ADDRESS = "FROM_ADDRESS" DEFAULT_API_URL = "https://api.mailgun.net/v3" def send(self, message: EmailMessage) -> bool: """Send an email via Mailgun API. Args: message: EmailMessage instance containing email details Returns: bool: True if email was sent successfully, False otherwise """ api_key = current_app.config.get(self.MAILGUN_API_KEY) domain = current_app.config.get(self.MAILGUN_DOMAIN) api_url = current_app.config.get(self.MAILGUN_API_URL, self.DEFAULT_API_URL) default_from = current_app.config.get(self.FROM_ADDRESS) missing = [k for k, v in [("MAILGUN_API_KEY", api_key), ("MAILGUN_DOMAIN", domain)] if not v] if missing: logger.error( f"[MAILGUN] Cannot send — missing config: {', '.join(missing)}. " f"Would have sent to: {message.to} | Subject: {message.subject}" ) return False from_address = message.from_address or default_from if not from_address: logger.error( f"[MAILGUN] Cannot send — missing FROM_ADDRESS. " f"Would have sent to: {message.to} | Subject: {message.subject}" ) return False url = f"{api_url}/{domain}/messages" data = { "to": message.to, "subject": message.subject, "text": message.body, "from": from_address, } if message.html_body: data["html"] = message.html_body try: response = requests.post( url, auth=("api", api_key), data=data, ) if response.status_code == 200: logger.info(f"[MAILGUN] Sent to {message.to} | Subject: {message.subject}") return True else: logger.error( f"[MAILGUN] Failed to send to {message.to}: from {from_address}" f"status={response.status_code} body={response.text}" ) return False except Exception as e: logger.error(f"[MAILGUN] Exception while sending to {message.to}: {e}") return False