summaryrefslogtreecommitdiff
path: root/addons/mail/models/mail_thread.py
diff options
context:
space:
mode:
authorThibault Delavallée <tde@odoo.com>2020-03-03 13:35:05 +0000
committerThibault Delavallée <tde@odoo.com>2020-03-03 16:25:00 +0000
commit68a457e17491ac90e3b806178eefc4b7150d176b (patch)
tree34e99cbb522987a0195de643da606dd3e69c45e8 /addons/mail/models/mail_thread.py
parent1380bd9123b7cc79de1552e43449ad547cf02e39 (diff)
[FW][FIX] mail: correctly check all recipients when routing on aliases
/!\ This commit is a manual forward-port of two PR targetting originally 11.0: #40442 and its fix / partial revert #41042. /!\ Purpose of this commit is to check all recipients of incoming emails when trying to determine the route to apply. Notably * an incoming email should be considered as a write to catchall only if all recipients are catchall. Catchall + a valid alias should take the alias into account; * an incoming email sent to the bounce alias should be considered as a bounce even if another valid alias is in recipients and whatever the order. Indeed it indicates an issue and bounce is considered as more important; * forward to an alias linked to another model should check all recipients and not only the first one. Otherwise reply_alias, forward_alias is considered as a reply whereas it should be considered as a forward when considering all recipients; Tests are added according to those specifications. Please see original PRs for more details about the content, the comments done on it and the various discussions. PR #46764 Task ID 2121551 X-original-commit: df00bd2d3bddf9a2b56e8554380669025e146d21
Diffstat (limited to 'addons/mail/models/mail_thread.py')
-rw-r--r--addons/mail/models/mail_thread.py30
1 files changed, 20 insertions, 10 deletions
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index 55b1c12aeef..bfa5bbe6f19 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -980,10 +980,16 @@ class MailThread(models.AbstractModel):
email_from = message_dict['email_from']
email_from_localpart = (tools.email_split(email_from) or [''])[0].split('@', 1)[0].lower()
email_to = message_dict['to']
- email_to_localpart = (tools.email_split(email_to) or [''])[0].split('@', 1)[0].lower()
+ email_to_localparts = [
+ e.split('@', 1)[0].lower()
+ for e in (tools.email_split(email_to) or [''])
+ ]
# Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
# for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
- rcpt_tos_localparts = [e.split('@')[0].lower() for e in tools.email_split(message_dict['recipients'])]
+ rcpt_tos_localparts = [
+ e.split('@')[0].lower()
+ for e in tools.email_split(message_dict['recipients'])
+ ]
# 0. Handle bounce: verify whether this is a bounced email and use it to collect bounce data and update notifications for customers
# Bounce regex: typical form of bounce is bounce_alias+128-crm.lead-34@domain
@@ -993,7 +999,7 @@ class MailThread(models.AbstractModel):
# As all MTA does not respect this RFC (googlemail is one of them),
# we also need to verify if the message come from "mailer-daemon"
# If not a bounce: reset bounce information
- if bounce_alias and bounce_alias in email_to_localpart:
+ if bounce_alias and any(email.startswith(bounce_alias) for email in email_to_localparts):
bounce_re = re.compile("%s\+(\d+)-?([\w.]+)?-?(\d+)?" % re.escape(bounce_alias), re.UNICODE)
bounce_match = bounce_re.search(email_to)
if bounce_match:
@@ -1008,15 +1014,19 @@ class MailThread(models.AbstractModel):
# if destination = alias with different model -> consider it is a forward and not a reply
# if destination = alias with same model -> check contact settings as they still apply
if reply_model and reply_thread_id:
- other_alias = self.env['mail.alias'].search([
- '&',
+ alias_count = self.env['mail.alias'].search_count([
+ '&', '&',
('alias_name', '!=', False),
- ('alias_name', '=', email_to_localpart)
+ ('alias_name', 'in', email_to_localparts),
+ ('alias_model_id.model', '!=', reply_model),
])
- if other_alias and other_alias.alias_model_id.model != reply_model:
- is_a_reply = False
+ is_a_reply = alias_count == 0
+
if is_a_reply:
- dest_aliases = self.env['mail.alias'].search([('alias_name', 'in', rcpt_tos_localparts)], limit=1)
+ dest_aliases = self.env['mail.alias'].search([
+ ('alias_name', 'in', rcpt_tos_localparts),
+ ('alias_model_id.model', '=', reply_model)
+ ], limit=1)
user_id = self._mail_find_user_for_gateway(email_from, alias=dest_aliases).id or self._uid
route = self._routing_check_route(
@@ -1037,7 +1047,7 @@ class MailThread(models.AbstractModel):
message_dict.pop('parent_id', None)
# check it does not directly contact catchall
- if catchall_alias and catchall_alias in email_to_localpart:
+ if catchall_alias and all(email_localpart == catchall_alias for email_localpart in email_to_localparts):
_logger.info('Routing mail from %s to %s with Message-Id %s: direct write to catchall, bounce', email_from, email_to, message_id)
body = self.env.ref('mail.mail_bounce_catchall').render({
'message': message,