diff --git a/app/email_utils.py b/app/email_utils.py index 2e804ba5..910b3b32 100644 --- a/app/email_utils.py +++ b/app/email_utils.py @@ -528,3 +528,16 @@ def parseaddr_unicode(addr) -> (str, str): def copy(msg: Message) -> Message: """return a copy of message""" return email.message_from_bytes(msg.as_bytes()) + + +def to_bytes(msg: Message): + """replace Message.as_bytes() method by trying different policies""" + try: + return msg.as_bytes() + except UnicodeEncodeError: + LOG.warning("as_bytes fails with default policy, try SMTP policy") + try: + return msg.as_bytes(policy=email.policy.SMTP) + except UnicodeEncodeError: + LOG.warning("as_bytes fails with SMTP policy, try SMTPUTF8 policy") + return msg.as_bytes(policy=email.policy.SMTPUTF8) diff --git a/email_handler.py b/email_handler.py index 03f95a1b..3544ef54 100644 --- a/email_handler.py +++ b/email_handler.py @@ -88,7 +88,7 @@ from app.email_utils import ( parseaddr_unicode, send_email_with_rate_control, get_email_domain_part, - copy, + copy, to_bytes, ) from app.extensions import db from app.greylisting import greylisting_needed @@ -1244,7 +1244,7 @@ async def handle(envelope: Envelope, smtp: SMTP) -> str: async def get_spam_score(message: Message) -> float: - sa_input = message.as_bytes() + sa_input = to_bytes(message) # Spamassassin requires to have an ending linebreak if not sa_input.endswith(b"\n"):