from common.config.app_settings import app_settings from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail from common.log.module_logger import ModuleLogger from typing import List, Dict import uuid from datetime import datetime from backend.models.models import EmailSendStatusDoc from common.constants.email import EmailSendStatus class EmailHandler: def __init__(self) -> None: pass async def send_email(self, message: dict): receiver_id = message["receiver_id"] content_text = message["properties"]["content_text"] content_subject = message["properties"]["content_subject"] receiver_type = message["properties"]["receiver_type"] module_logger = ModuleLogger(sender_id="EmailHandler") if receiver_type == "email": receiver_email = receiver_id else: receiver_email = None module_logger.log_info( "unsupported receiver_type: '{}'".format(receiver_type) ) return mail = Mail( from_email=app_settings.EMAIL_FROM, to_emails=receiver_email, subject=content_subject, html_content=content_text, ) try: sg = SendGridAPIClient(app_settings.SENDGRID_API_KEY) response = sg.send(mail) await module_logger.log_info( info=f"SendGridAPIClient:response:status_code:{response.status_code} | body:{response.body}", properties=message["properties"], ) except Exception as e: await module_logger.log_exception(e) async def send_tenant_email( self, tenant_id: str, template_id: str, recipient_email: str, sender_email: str, subject_properties: Dict = {}, body_properties: Dict = {}, tracking_enabled: bool = True ): """Send tenant email using specified sender""" module_logger = ModuleLogger(sender_id="EmailHandler") try: email_id = str(uuid.uuid4()) from_email = sender_email if sender_email else app_settings.EMAIL_FROM subject = subject_properties.get("subject", "No Subject") html_content = body_properties.get("html_content", "") text_content = body_properties.get("text_content", "") email_status_doc = EmailSendStatusDoc( email_id=email_id, tenant_id=tenant_id, email_sender=sender_email, recipient_email=recipient_email, template_id=template_id, subject=subject, body=html_content, status=EmailSendStatus.SENDING ) await email_status_doc.save() # Create EmailTrackingDoc if tracking is enabled tracking_doc = None if tracking_enabled: from backend.models.models import EmailTrackingDoc tracking_doc = EmailTrackingDoc( email_id=email_id, tenant_id=tenant_id, recipient_email=recipient_email, template_id=template_id, sent_at=datetime.utcnow(), tracking_enabled=True ) await tracking_doc.save() mail = Mail( from_email=from_email, to_emails=recipient_email, subject=subject, html_content=html_content, ) # Enable SendGrid tracking if tracking is enabled if tracking_enabled: from sendgrid.helpers.mail import TrackingSettings, ClickTracking, OpenTracking tracking_settings = TrackingSettings() click_tracking = ClickTracking(True, True) # Enable click tracking open_tracking = OpenTracking(True) # Enable open tracking tracking_settings.click_tracking = click_tracking tracking_settings.open_tracking = open_tracking mail.tracking_settings = tracking_settings sg = SendGridAPIClient(app_settings.SENDGRID_API_KEY) response = sg.send(mail) email_status_doc.status = EmailSendStatus.SENT email_status_doc.sent_at = datetime.utcnow() email_status_doc.message_id = str(response.headers.get('X-Message-Id', '')) await email_status_doc.save() # Update tracking document with message_id if tracking_doc: tracking_doc.message_id = email_status_doc.message_id await tracking_doc.save() await module_logger.log_info( f"Tenant email sent successfully", properties={ "tenant_id": tenant_id, "template_id": template_id, "email_id": email_id, "recipient_email": recipient_email, "sender_email": from_email, "status_code": response.status_code } ) return email_id except Exception as e: if 'email_status_doc' in locals(): email_status_doc.status = EmailSendStatus.FAILED email_status_doc.failed_at = datetime.utcnow() email_status_doc.error_message = str(e) await email_status_doc.save() await module_logger.log_error( f"Failed to send tenant email", properties={ "tenant_id": tenant_id, "template_id": template_id, "recipient_email": recipient_email, "error": str(e) } ) raise