diff --git a/mail_tracking_mass_mailing/models/mail_mail.py b/mail_tracking_mass_mailing/models/mail_mail.py index fe97fa63c4..03741f16b9 100644 --- a/mail_tracking_mass_mailing/models/mail_mail.py +++ b/mail_tracking_mass_mailing/models/mail_mail.py @@ -2,7 +2,7 @@ # Copyright 2017 Tecnativa - Vicent Cubells # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import api, models +from odoo import api, fields, models class MailMail(models.Model): @@ -22,3 +22,43 @@ def _tracking_email_prepare(self, partner, email): def _get_tracking_url(self): # Invalid this tracking image, we have other to do the same return False + + def _postprocess_sent_message( + self, success_pids, failure_reason=False, failure_type=None + ): + """Set mailing traces in error according to mail tracking state + + If an exception is caught by ir.mail_server.send_email in mail_tracking module, + the mail.tracking.email record will appear in error but the related mailing + trace would still appear as sent because this method is called without any + failure_type in mail.mail._send in the mail module (as Exception is not raised + after being caught in mail_tracking module). + + Since this method not only sets the mailing.trace state in mass_mailing module + but can also delete the mail.mail records in mail module, we need to ensure + the mailing.trace is written accordingly to the tracking here, and avoid having + the mass_mailing module set a 'sent' status if we had an exception, hence + the usage of a context key to ignore possible writes. + """ + processed_ids = [] + for mail in self: + mail_tracking = mail.mailing_trace_ids.mail_tracking_id + if mail.mailing_id and mail_tracking.state == "error": + mail_failure_type = ( + "RECIPIENT" + if mail_tracking.error_type == "no_recipient" + else "SMTP" + ) + mail.mailing_trace_ids.write( + { + "exception": fields.Datetime.now(), + "failure_type": mail_failure_type, + } + ) + processed_ids.extend(mail.mailing_trace_ids.ids) + return super( + MailMail, + self.with_context(_ignore_write_trace_postprocess_ids=processed_ids), + )._postprocess_sent_message( + success_pids, failure_reason=failure_reason, failure_type=failure_type + ) diff --git a/mail_tracking_mass_mailing/models/mailing_trace.py b/mail_tracking_mass_mailing/models/mailing_trace.py index 57ccd061a4..1d5749248a 100644 --- a/mail_tracking_mass_mailing/models/mailing_trace.py +++ b/mail_tracking_mass_mailing/models/mailing_trace.py @@ -17,3 +17,10 @@ class MailTrace(models.Model): related="mail_tracking_id.tracking_event_ids", readonly=True, ) + + def write(self, values): + """Ignore write from _postprocess_sent_message on selected ids""" + to_ignore_ids = self.env.context.get("_ignore_write_trace_postprocess_ids") + if to_ignore_ids: + self = self.browse(set(self.ids) - set(to_ignore_ids)) + return super().write(values) diff --git a/mail_tracking_mass_mailing/tests/test_mass_mailing.py b/mail_tracking_mass_mailing/tests/test_mass_mailing.py index 8963f20aec..569444bd57 100644 --- a/mail_tracking_mass_mailing/tests/test_mass_mailing.py +++ b/mail_tracking_mass_mailing/tests/test_mass_mailing.py @@ -54,6 +54,9 @@ def test_smtp_error(self): self.assertEqual("error", track.state) self.assertEqual("Warning", track.error_type) self.assertEqual("Mock test error", track.error_description) + self.assertTrue(stat.exception) + self.assertEqual(stat.state, "exception") + self.assertEqual(stat.failure_type, "SMTP") self.assertTrue(self.contact_a.email_bounced) def test_tracking_email_link(self):