84 lines
2.7 KiB
Python
84 lines
2.7 KiB
Python
|
|
"""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
|