diff --git a/apps/notification/backend/business/tenant_notification_manager.py b/apps/notification/backend/business/tenant_notification_manager.py index d86142a..e458045 100644 --- a/apps/notification/backend/business/tenant_notification_manager.py +++ b/apps/notification/backend/business/tenant_notification_manager.py @@ -64,8 +64,8 @@ class TenantNotificationManager: # 4. spam detection with region email_content = { - "subject": rendered_template.get("subject_properties", {}).get("subject", ""), - "body": rendered_template.get("body_properties", {}).get("html_content", "") + "subject": rendered_template.get("subject", ""), + "body": rendered_template.get("body", "") } spam_result = await self.email_spam_protection_service.detect_spam(email_content, region) if spam_result["is_spam"]: @@ -82,8 +82,8 @@ class TenantNotificationManager: "region": region, "priority": priority, "tracking_enabled": tracking_enabled, - "content_text": rendered_template.get("body_properties", {}).get("html_content", ""), - "content_subject": rendered_template.get("subject_properties", {}).get("subject", ""), + "content_text": rendered_template.get("body", ""), + "content_subject": rendered_template.get("subject", ""), "receiver_type": "email", "validation_info": { "invalid_recipients": invalid_recipients, @@ -96,13 +96,36 @@ class TenantNotificationManager: # 6. create message for each recipient for recipient_email in valid_recipients: + # create individual properties for each recipient + individual_properties = { + "tenant_id": tenant_id, + "template_id": template_id, + "destination_emails": [recipient_email], + "sender_emails": valid_senders, + "subject_properties": rendered_template.get("subject_properties", {}), + "body_properties": rendered_template.get("body_properties", {}), + "region": region, + "priority": priority, + "tracking_enabled": tracking_enabled, + "content_text": rendered_template.get("body", ""), + "content_subject": rendered_template.get("subject", ""), + "receiver_type": "email", + "validation_info": { + "invalid_recipients": invalid_recipients, + "invalid_senders": invalid_senders, + "blacklisted_recipients": blacklisted_recipients, + "rate_limit_info": rate_limit_result, + "spam_detection_info": spam_result + } + } + # create NotificationMessage message = NotificationMessage( sender_id=tenant_id, receiver_id=recipient_email, subject=template_id, event="tenant_email", - properties=properties + properties=individual_properties ) await self.email_publisher.publish(message=message.model_dump_json()) diff --git a/apps/notification/backend/infra/rabbitmq/async_client.py b/apps/notification/backend/infra/rabbitmq/async_client.py index 0df0745..61456b7 100644 --- a/apps/notification/backend/infra/rabbitmq/async_client.py +++ b/apps/notification/backend/infra/rabbitmq/async_client.py @@ -6,7 +6,9 @@ import aio_pika class AsyncMQClient: - exchange_name_format = "freeleaps.notification.exchange.{}" + # TODO: change to freeleaps.notification.exchange.{} + # in local test, we use freeleaps.notification.exchange.local.{} to avoid repeating sending emails + exchange_name_format = "freeleaps.notification.exchange.local.{}" exchange_type = "direct" def __init__(self, channel_name: str) -> None: @@ -38,7 +40,7 @@ class AsyncMQClient: # Declare and bind queue if it's not set by a specific client self.queue = await self.channel.declare_queue( - name=None, exclusive=True, auto_delete=True, durable=False + name=f"freeleaps.notification.queue.{self.channel_name}", exclusive=False, auto_delete=False, durable=True ) await self.queue.bind( exchange=self.exchange, routing_key=self.routing_key diff --git a/apps/notification/webapi/utils/email_consumer.py b/apps/notification/webapi/utils/email_consumer.py index 18893eb..3a8a96e 100644 --- a/apps/notification/webapi/utils/email_consumer.py +++ b/apps/notification/webapi/utils/email_consumer.py @@ -12,13 +12,13 @@ class EmailMQConsumer: module_logger = ModuleLogger(sender_id="EmailMQConsumer") # examin whether it is a multi-tenant email message - if "tenant_id" in message and "template_id" in message: + if "tenant_id" in message and "template_id" in message.get("properties", {}): await module_logger.log_info( "Processing tenant email message", properties={ - "template_id": message.get("template_id"), + "template_id": message.get("properties", {}).get("template_id"), "tenant_id": message.get("tenant_id"), - "destination_count": len(message.get("destination_emails", [])) + "destination_count": len(message.get("properties", {}).get("destination_emails", [])) } ) @@ -56,12 +56,14 @@ class EmailMQConsumer: async def tenant_mail_handler(register_key: str, message: dict, args: dict): """Handle tenant email messages""" try: - tenant_id = message.get("tenant_id") - template_id = message.get("template_id") - destination_emails = message.get("destination_emails", []) - sender_emails = message.get("sender_emails", []) - subject_properties = message.get("subject_properties", {}) - body_properties = message.get("body_properties", {}) + # Get fields from message structure + tenant_id = message.get("tenant_id") or message.get("properties", {}).get("tenant_id") + template_id = message.get("properties", {}).get("template_id") + destination_emails = message.get("properties", {}).get("destination_emails", []) + sender_emails = message.get("properties", {}).get("sender_emails", []) + # Use rendered content instead of template properties + subject = message.get("properties", {}).get("content_subject", "No Subject") + html_content = message.get("properties", {}).get("content_text", "") email_handler = EmailHandler() email_ids = [] @@ -73,8 +75,8 @@ class EmailMQConsumer: template_id=template_id, recipient_email=recipient_email, sender_emails=sender_emails, - subject_properties=subject_properties, - body_properties=body_properties + subject_properties={"subject": subject}, + body_properties={"html_content": html_content} ) email_ids.append(email_id)