diff options
| author | Thibault Delavallée <tde@odoo.com> | 2020-03-03 13:35:05 +0000 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2020-03-03 16:25:00 +0000 |
| commit | 68a457e17491ac90e3b806178eefc4b7150d176b (patch) | |
| tree | 34e99cbb522987a0195de643da606dd3e69c45e8 /addons/mail/models/mail_thread.py | |
| parent | 1380bd9123b7cc79de1552e43449ad547cf02e39 (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.py | 30 |
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, |
