Files

95 lines
3.0 KiB
Python
Raw Permalink Normal View History

"""SendGrid 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 SendGridEmailProvider(EmailProvider):
"""SendGrid API-based email provider implementation."""
# Configuration keys
SENDGRID_API_KEY = "SENDGRID_API_KEY"
SENDGRID_FROM_EMAIL = "SENDGRID_FROM_EMAIL"
FROM_ADDRESS = "FROM_ADDRESS"
API_URL = "https://api.sendgrid.com/v3/mail/send"
def send(self, message: EmailMessage) -> bool:
"""Send an email via SendGrid 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.SENDGRID_API_KEY)
default_from = current_app.config.get(self.SENDGRID_FROM_EMAIL)
fallback_from = current_app.config.get(self.FROM_ADDRESS)
if not api_key:
logger.error(
f"[SENDGRID] Cannot send — missing SENDGRID_API_KEY config. "
f"Would have sent to: {message.to} | Subject: {message.subject}"
)
return False
from_address = message.from_address or default_from or fallback_from
if not from_address:
logger.error(
f"[SENDGRID] Cannot send — missing from address (SENDGRID_FROM_EMAIL or FROM_ADDRESS). "
f"Would have sent to: {message.to} | Subject: {message.subject}"
)
return False
payload = {
"personalizations": [
{
"to": [{"email": message.to}]
}
],
"from": {"email": from_address},
"subject": message.subject,
"content": [
{
"type": "text/plain",
"value": message.body
}
]
}
if message.html_body:
payload["content"].append({
"type": "text/html",
"value": message.html_body
})
try:
response = requests.post(
self.API_URL,
json=payload,
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
)
if response.status_code == 202:
logger.info(f"[SENDGRID] Sent to {message.to} | Subject: {message.subject}")
return True
else:
logger.error(
f"[SENDGRID] Failed to send to {message.to}: "
f"status={response.status_code} body={response.text}"
)
return False
except Exception as e:
logger.error(f"[SENDGRID] Exception while sending to {message.to}: {e}")
return False