diff --git a/addons/test_mail/tests/test_mail_mail.py b/addons/test_mail/tests/test_mail_mail.py index 76d9ca4fcd2..5979b1a3030 100644 --- a/addons/test_mail/tests/test_mail_mail.py +++ b/addons/test_mail/tests/test_mail_mail.py @@ -293,10 +293,10 @@ class TestMailMail(TestMailCommon): with self.mock_mail_gateway(): mail.send(raise_exception=False) self.assertEqual(self._mails[0]['email_from'], 'strange@example¢¡.com') - self.assertIn('Codepoint U+00A2 at position', mail.failure_reason) + self.assertEqual(mail.failure_reason, "Malformed 'Return-Path' or 'From' address: strange@example¢¡.com - It should contain one valid plain ASCII email") self.assertFalse(mail.failure_type, 'Mail: bugged from (ascii): no failure type, should be updated') self.assertEqual(mail.state, 'exception') - self.assertIn('Codepoint U+00A2 at position', notification.failure_reason) + self.assertEqual(notification.failure_reason, "Malformed 'Return-Path' or 'From' address: strange@example¢¡.com - It should contain one valid plain ASCII email") self.assertEqual(notification.failure_type, 'unknown', 'Mail: bugged from (ascii): unknown failure type, should be updated') self.assertEqual(notification.notification_status, 'exception') @@ -307,10 +307,10 @@ class TestMailMail(TestMailCommon): with self.mock_mail_gateway(): mail.send(raise_exception=False) self.assertEqual(self._mails[0]['email_from'], 'test.user@example.com') - self.assertIn('Codepoint U+00A2 at position', mail.failure_reason) + self.assertIn("Malformed 'Return-Path' or 'From' address: bounce.test@domain¢¡.com", mail.failure_reason) self.assertFalse(mail.failure_type, 'Mail: bugged catchall domain (ascii): no failure type, should be updated') self.assertEqual(mail.state, 'exception') - self.assertIn('Codepoint U+00A2 at position', notification.failure_reason) + self.assertEqual(notification.failure_reason, "Malformed 'Return-Path' or 'From' address: bounce.test@domain¢¡.com - It should contain one valid plain ASCII email") self.assertEqual(notification.failure_type, 'unknown', 'Mail: bugged catchall domain (ascii): unknown failure type, should be updated') self.assertEqual(notification.notification_status, 'exception') @@ -375,11 +375,10 @@ class TestMailMail(TestMailCommon): mail.write({'email_to': email_to}) with self.mock_mail_gateway(): mail.send(raise_exception=False) - self.assertIn('Codepoint U+00A2 at position', mail.failure_reason) + self.assertEqual(mail.failure_reason, 'Error without exception. Probably due to sending an email without computed recipients.') self.assertFalse(mail.failure_type, 'Mail: invalid (ascii) recipient partner: no failure type, should be updated') self.assertEqual(mail.state, 'exception') - self.assertIn('Codepoint U+00A2 at position', notification.failure_reason) - self.assertEqual(notification.failure_type, 'unknown', 'Mail: invalid (ascii) recipient partner: unknown failure type, should be updated') + self.assertEqual(notification.failure_type, 'mail_email_invalid') self.assertEqual(notification.notification_status, 'exception') # MailServer.send_email(): _prepare_email_message: ok To (ascii or just ok) @@ -454,11 +453,10 @@ class TestMailMail(TestMailCommon): notification.write({'res_partner_id': partner.id}) with self.mock_mail_gateway(): mail.send(raise_exception=False) - self.assertIn('Codepoint U+00A2 at position', mail.failure_reason) + self.assertEqual(mail.failure_reason, 'Error without exception. Probably due to sending an email without computed recipients.') self.assertFalse(mail.failure_type, 'Mail: invalid (ascii) recipient partner: no failure type, should be updated') self.assertEqual(mail.state, 'exception') - self.assertIn('Codepoint U+00A2 at position', notification.failure_reason) - self.assertEqual(notification.failure_type, 'unknown', 'Mail: invalid (ascii) recipient partner: unknown failure type, should be updated') + self.assertEqual(notification.failure_type, 'mail_email_invalid') self.assertEqual(notification.notification_status, 'exception') # ascii ok or just ok @@ -544,14 +542,12 @@ class TestMailMail(TestMailCommon): mail.write({'email_to': email_to}) with self.mock_mail_gateway(): mail.send(raise_exception=False) - self.assertIn('Codepoint U+00A2 at position', mail.failure_reason) + self.assertFalse(mail.failure_type, 'Mail: at least one valid recipient, mail is sent to avoid send loops and spam') - self.assertEqual(mail.state, 'exception') - self.assertIn('Codepoint U+00A2 at position', notification.failure_reason) - self.assertEqual(notification.failure_type, 'unknown') - self.assertEqual(notification.notification_status, 'exception') - self.assertIn('Codepoint U+00A2 at position', notification2.failure_reason) - self.assertEqual(notification2.failure_type, 'unknown') + self.assertEqual(mail.state, 'sent') + self.assertFalse(notification.failure_type) + self.assertEqual(notification.notification_status, 'sent') + self.assertEqual(notification2.failure_type, 'mail_email_invalid') self.assertEqual(notification2.notification_status, 'exception') @mute_logger('odoo.addons.mail.models.mail_mail') diff --git a/addons/test_mail/tests/test_performance.py b/addons/test_mail/tests/test_performance.py index a66b9b7ad11..727fb1aa6c0 100644 --- a/addons/test_mail/tests/test_performance.py +++ b/addons/test_mail/tests/test_performance.py @@ -815,7 +815,7 @@ class TestMailComplexPerformance(BaseMailPerformance): 'mail_server_id': self.mail_servers.ids[idx % len(self.mail_servers.ids)], 'recipient_ids': [(4, pid) for pid in self.partners.ids], } for idx in range(12)]) - mails[-2].write({'email_cc': False, 'email_to': 'strange@example¢¡.com'}) + mails[-2].write({'email_cc': False, 'email_to': 'strange@example¢¡.com', 'recipient_ids': [(5, 0)]}) mails[-1].write({'email_cc': False, 'email_to': 'void', 'recipient_ids': [(5, 0)]}) with self.assertQueryCount(__system__=44, employee=44): self.env['mail.mail'].sudo().browse(mails.ids).send() @@ -824,9 +824,9 @@ class TestMailComplexPerformance(BaseMailPerformance): self.assertEqual(mail.state, 'sent') self.assertTrue(mail.to_delete, 'Mail: sent mails are to be unlinked') self.assertEqual(mails[-2].state, 'exception') - self.assertFalse(mails[-2].to_delete, 'Mail: invalid recipient, not to unlink') + self.assertTrue(mails[-2].to_delete, 'Mail: mails with invalid recipient are also to be unlinked') self.assertEqual(mails[-1].state, 'exception') - self.assertFalse(mails[-2].to_delete, 'Mail: ninvalid recipient, not to unlink') + self.assertTrue(mails[-1].to_delete, 'Mail: mails with invalid recipient are also to be unlinked') @mute_logger('odoo.tests', 'odoo.addons.mail.models.mail_mail', 'odoo.models.unlink') @users('__system__', 'employee') diff --git a/odoo/addons/base/models/ir_mail_server.py b/odoo/addons/base/models/ir_mail_server.py index c66cf50dcff..d254feece3b 100644 --- a/odoo/addons/base/models/ir_mail_server.py +++ b/odoo/addons/base/models/ir_mail_server.py @@ -75,7 +75,13 @@ def extract_rfc2822_addresses(text): if not text: return [] candidates = address_pattern.findall(ustr(text)) - return [formataddr(('', c), charset='ascii') for c in candidates] + valid_addresses = [] + for c in candidates: + try: + valid_addresses.append(formataddr(('', c), charset='ascii')) + except idna.IDNAError: + pass + return valid_addresses class IrMailServer(models.Model): diff --git a/odoo/addons/base/tests/test_mail.py b/odoo/addons/base/tests/test_mail.py index 90bab7b4cef..7f968e45abe 100644 --- a/odoo/addons/base/tests/test_mail.py +++ b/odoo/addons/base/tests/test_mail.py @@ -452,6 +452,7 @@ class TestEmailTools(BaseCase): ('admin@example.com', ['admin@example.com']), ('"Admin" , Demo ', ['admin@example.com']), ('admin@éxample.com', ['admin@xn--xample-9ua.com']), + ('"admin@éxample.com" ', ['admin@xn--xample-9ua.com']), ] for (rfc2822_email, expected) in tests: