diff --git a/addons/mail/models/mail_blacklist.py b/addons/mail/models/mail_blacklist.py index 16949dca8e8a5e1397d644f337dec50e0bf78bb3..592928c3a5f91db7f279f8a4ba89bb7de17bc424 100644 --- a/addons/mail/models/mail_blacklist.py +++ b/addons/mail/models/mail_blacklist.py @@ -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}) diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 42916d46b5c66fa9f61ad2e379898b39a351f26d..bdfd821967ccce70a955bd8c9589f53599240faa 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -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 diff --git a/addons/mass_mailing/models/mail_thread.py b/addons/mass_mailing/models/mail_thread.py index 09c6ba5362613f94734edf18c5efe39d58cf19df..93f657da3cf9e680d8e331004fbd58ae55e3768f 100644 --- a/addons/mass_mailing/models/mail_thread.py +++ b/addons/mass_mailing/models/mail_thread.py @@ -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(