diff --git a/backend/services/messaging/smtp_service.py b/backend/services/messaging/smtp_service.py index 7bb2e141ae..78e08faa14 100644 --- a/backend/services/messaging/smtp_service.py +++ b/backend/services/messaging/smtp_service.py @@ -1,7 +1,10 @@ +import re import urllib.parse +from html import unescape from databases import Database from fastapi_mail import MessageSchema, MessageType +from fastapi_mail.schemas import MultipartSubtypeEnum from itsdangerous import URLSafeTimedSerializer from loguru import logger @@ -16,6 +19,22 @@ ) +def html_to_text(html_content: str) -> str: + """Convert HTML to plain text for email alternative body.""" + if not html_content: + return "" + text = re.sub( + r"<(style|script)[^>]*>.*?", "", html_content, flags=re.DOTALL | re.I + ) + text = re.sub(r"|

|||", "\n", text, flags=re.I) + text = re.sub(r"<[^>]+>", "", text) + text = unescape(text) + text = re.sub(r"[ \t]+", " ", text) + text = re.sub(r"\n ", "\n", text) + text = re.sub(r"\n{3,}", "\n\n", text) + return text.strip() + + class SMTPService: @staticmethod async def send_verification_email(to_address: str, username: str): @@ -183,11 +202,15 @@ async def _send_message( from_address = settings.MAIL_DEFAULT_SENDER if from_address is None: raise ValueError("Missing TM_EMAIL_FROM_ADDRESS environment variable") + if text_message is None: + text_message = html_to_text(html_message) msg = MessageSchema( recipients=[to_address], subject=subject, - body=html_message, - subtype=MessageType.html, + body=text_message, + alternative_body=html_message, + subtype=MessageType.plain, + multipart_subtype=MultipartSubtypeEnum.alternative, ) logger.debug(f"Sending email via SMTP {to_address}") if settings.LOG_LEVEL == "DEBUG":