Skip to content
Snippets Groups Projects
Commit 92fe83ec authored by David Beguin's avatar David Beguin Committed by Thibault Delavallée
Browse files

[IMP] mail, mass_mailing : reset bounce on mail reception

PURPOSE

Add some improvements in mail gateway: remove private discussion, improve
bounce management, allow resetting bounce counters, improve automatic set or
reset of blacklists and ease mass mailing inheritance.

SPECIFICATIONS

The number of message bounce is incremented each time the email bounce
on a specific email address. To have a correct information, we should
reset to zero this counter if we receive a mail from this address.
Indeed, if we receive an email from an email address, this email is
active and the message bounce number (if > 0) is not relevant anymore.

Only models inheriting form blacklist are impacted by this improvement
in order to limit a bit side effect.

Also, add a check in autoblacklist rule. No need to check the stats
if message_bounce is < 5.

This commit introduces

  * ``_routing_reset_bounce`` routing method managing the bounce reset;
  * ``_message_reset_bounce`` model method that resets bounce counter
    in blacklist enabled models;

LINKS

Related to task ID : 1893155
Linked to PR #33340
parent f4524f03
No related branches found
No related tags found
No related merge requests found
......@@ -156,3 +156,9 @@ class MailBlackListMixin(models.AbstractModel):
super(MailBlackListMixin, self)._message_receive_bounce(email, partner)
for record in self:
record.message_bounce = record.message_bounce + 1
def _message_reset_bounce(self, email):
""" Override of mail.thread generic method. Purpose is to reset the
bounce counter of the record. """
super(MailBlackListMixin, self)._message_reset_bounce(email)
self.write({'message_bounce': 0})
......@@ -815,6 +815,22 @@ class MailThread(models.AbstractModel):
return (model, thread_id, route[2], route[3], route[4])
@api.model
def _routing_reset_bounce(self, email_message, message_dict):
"""Called by ``message_process`` when a new mail is received from an email address.
If the email is related to a partner, we consider that the number of message_bounce
is not relevant anymore as the email is valid - as we received an email from this
address. The model is here hardcoded because we cannot know with which model the
incomming mail match. We consider that if a mail arrives, we have to clear bounce for
each model having bounce count.
:param email_from: email address that sent the incoming email."""
valid_email = message_dict['email_from']
if valid_email:
bl_models = self.env['ir.model'].sudo().search(['&', ('is_mail_blacklist', '=', True), ('model', '!=', 'mail.thread.blacklist')])
for model in [bl_model for bl_model in bl_models if bl_model.model in self.env]: # transient test mode
self.env[model.model].sudo().search([('message_bounce', '>', 0), ('email_normalized', '=', valid_email)])._message_reset_bounce(valid_email)
@api.model
def message_route(self, message, message_dict, model=None, thread_id=None, custom_values=None):
""" Attempt to figure out the correct target model, thread_id,
......@@ -883,6 +899,7 @@ class MailThread(models.AbstractModel):
# See http://datatracker.ietf.org/doc/rfc3462/?include_text=1
# 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:
bounce_re = re.compile("%s\+(\d+)-?([\w.]+)?-?(\d+)?" % re.escape(bounce_alias), re.UNICODE)
bounce_match = bounce_re.search(email_to)
......@@ -892,6 +909,7 @@ class MailThread(models.AbstractModel):
if message.get_content_type() == 'multipart/report' or email_from_localpart == 'mailer-daemon':
self._routing_handle_bounce(message, message_dict)
return []
self._routing_reset_bounce(message, message_dict)
# 1. Handle reply
# if destination = alias with different model -> consider it is a forward and not a reply
......@@ -1149,6 +1167,16 @@ class MailThread(models.AbstractModel):
"""
pass
def _message_reset_bounce(self, email):
"""Called by ``message_process`` when an email is considered as not being
a bounce. The default behavior is to do nothing. This method is meant to
be overridden in various modules to add some specific behavior like
blacklist management.
:param string email: email for which to reset bounce information
"""
pass
def _message_parse_extract_payload_postprocess(self, message, payload_dict):
""" Perform some cleaning / postprocess in the body and attachments
extracted from the email. Note that this processing is specific to the
......
......@@ -50,13 +50,14 @@ class MailThread(models.AbstractModel):
bounced_email = message_dict['bounced_email']
bounced_msg_id = message_dict['bounced_msg_id']
bounced_partner = message_dict['bounced_partner']
if bounced_msg_id:
self.env['mailing.trace'].set_bounced(mail_message_ids=[bounced_msg_id])
if bounced_email:
three_months_ago = fields.Datetime.to_string(datetime.datetime.now() - datetime.timedelta(weeks=13))
stats = self.env['mailing.trace'].search(['&', ('bounced', '>', three_months_ago), ('email', '=ilike', bounced_email)]).mapped('bounced')
if len(stats) >= BLACKLIST_MAX_BOUNCED_LIMIT:
if len(stats) >= BLACKLIST_MAX_BOUNCED_LIMIT and (not bounced_partner or bounced_partner.message_bounce >= BLACKLIST_MAX_BOUNCED_LIMIT):
if max(stats) > min(stats) + datetime.timedelta(weeks=1):
blacklist_rec = self.env['mail.blacklist'].sudo()._add(bounced_email)
blacklist_rec._message_log(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment