[FIX] mail: bounce incoming email with catchall email and other unroutable emails

How to reproduce
- Send an email to catchall@exemple.com, random@exemple.com
(Note : random@exemple.com is an email witch does not exist)
--> Issue the email is not bounced

To justify the change, this was actually the behavior a while ago, prior to odoo-dev@68a457e
The intent of that commit was to consider other possible routes, so this commit
doesn't contradict the change.

Task-3714565

closes odoo/odoo#161782

X-original-commit: df0c05afbf81ce41c9b1b4cfe93476d4ca397749
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Florent de Labarre
2024-04-15 14:09:45 +00:00
committed by Thibault Delavallée
parent 7c5a2c601d
commit 0f0a9845fc
2 changed files with 42 additions and 2 deletions
+26 -2
View File
@@ -1023,12 +1023,21 @@ class MailThread(models.AbstractModel):
@api.model
def _detect_write_to_catchall(self, msg_dict):
"""Return True if directly contacts catchall."""
catchall_aliases = self.env['mail.alias.domain'].search([]).mapped('catchall_email')
# Note: tweaked in stable to avoid doing two times same search due to bugfix
# (see odoo/odoo#161782), to clean when reaching master
if self.env.context.get("mail_catchall_aliases"):
catchall_aliases = self.env.context["mail_catchall_aliases"]
else:
catchall_aliases = self.env['mail.alias.domain'].search([]).mapped('catchall_email')
email_to_list = [
tools.email_normalize(e) or e
for e in (tools.email_split(msg_dict['to']) or [''])
]
# check it does not directly contact catchall
# check it does not directly contact catchall; either (legacy) strict aka
# all TOs belong are catchall, either (optional) any catchall in all TOs
if self.env.context.get("mail_catchall_write_any_to"):
return catchall_aliases and any(email_to in catchall_aliases for email_to in email_to_list)
return (
catchall_aliases and email_to_list and
all(email_to in catchall_aliases for email_to in email_to_list)
@@ -1166,6 +1175,9 @@ class MailThread(models.AbstractModel):
return []
# 2. Handle new incoming email by checking aliases and applying their settings
# prefetch catchall aliases as they are used several times
catchall_aliases = self.env['mail.alias.domain'].search([]).mapped('catchall_email')
self = self.with_context(mail_catchall_aliases=catchall_aliases)
if rcpt_tos_list:
# no route found for a matching reference (or reply), so parent is invalid
message_dict.pop('parent_id', None)
@@ -1213,6 +1225,18 @@ class MailThread(models.AbstractModel):
email_from, message_dict['to'], message_id, fallback_model, thread_id, custom_values, user_id)
return [route]
# 4. Recipients contain catchall and unroutable emails -> bounce
if rcpt_tos_list and self.with_context(mail_catchall_write_any_to=True)._detect_write_to_catchall(message_dict):
_logger.info(
'Routing mail from %s to %s with Message-Id %s: write to catchall + other unroutable emails, bounce',
email_from, message_dict['to'], message_id
)
body = self.env['ir.qweb']._render('mail.mail_bounce_catchall', {
'message': message,
})
self._routing_create_bounce_email(email_from, body, message, references=message_id, reply_to=self.env.company.email)
return []
# ValueError if no routes found and if no bounce occurred
raise ValueError(
'No possible route found for incoming message from %s to %s (Message-Id %s:). '
@@ -1076,6 +1076,22 @@ class TestMailgateway(MailCommon):
# No bounce email
self.assertNotSentEmail()
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.addons.mail.models.mail_mail', 'odoo.models.unlink')
def test_message_route_write_to_catchall_other_recipients_invalid(self):
""" Writing to catchall and other unroutable recipients should bounce. """
# Test: no group created, email bounced
with self.mock_mail_gateway():
record = self.format_and_process(
MAIL_TEMPLATE, self.partner_1.email_formatted,
f'"My Super Catchall" <{self.alias_catchall}@{self.alias_domain}>, Unroutable <unroutable@{self.alias_domain}>',
subject='Should Bounce')
self.assertFalse(record)
self.assertSentEmail(
self.mailer_daemon_email,
['whatever-2a840@postmaster.twitter.com'],
subject='Re: Should Bounce'
)
@mute_logger('odoo.addons.mail.models.mail_thread')
def test_message_process_bounce_alias(self):
""" Writing to bounce alias is considered as a bounce even if not multipart/report bounce structure """