[FIX] mail: send emails only once for each batch

If a list of emails is bigger than 500, the email was sent several
time to some people.
The mail_values content was not reset between each batch, so if 1200
emails are sent, 3 mail.mail records were created for the emails in
the first group.

closes odoo/odoo#93658

X-original-commit: f838a0cc36e51e0f47daeec6522df8e9832aad2c
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Martin Trigaux
2022-06-15 10:00:20 +02:00
parent d3f3f44f7a
commit ad5e6f1111
2 changed files with 40 additions and 2 deletions
+4 -2
View File
@@ -18,6 +18,7 @@ from odoo.tools import email_normalize, hmac, generate_tracking_message_id
_logger = logging.getLogger(__name__)
# TODO remove me master
GROUP_SEND_BATCH_SIZE = 500
@@ -407,7 +408,6 @@ class MailGroup(models.Model):
base_url = self.get_base_url()
body = self.env['mail.render.mixin']._replace_local_links(message.body)
access_token = self._generate_group_access_token()
mail_values = []
# Email added in a dict to be sure to send only once the email to each address
member_emails = {
@@ -415,7 +415,9 @@ class MailGroup(models.Model):
for member in self.member_ids
}
for batch_email_member in tools.split_every(GROUP_SEND_BATCH_SIZE, member_emails.items()):
batch_size = int(self.env['ir.config_parameter'].sudo().get_param('mail.session.batch.size', GROUP_SEND_BATCH_SIZE))
for batch_email_member in tools.split_every(batch_size, member_emails.items()):
mail_values = []
for email_member_normalized, email_member in batch_email_member:
if email_member_normalized == message.email_from_normalized:
# Do not send the email to their author
@@ -8,6 +8,42 @@ from odoo.tools import mute_logger
class TestMailGroupMessage(TestMailListCommon):
def test_batch_send(self):
"""Test that when someone sends an email to a large group that it is
delivered exactly to those people"""
self.test_group.write({
'access_mode': 'members',
'alias_contact': 'followers',
'moderation': False,
})
self.test_group.member_ids.unlink()
for num in range(42):
self.env['mail.group.member'].create({
'email': f'emu-{num}@example.com',
'mail_group_id': self.test_group.id,
})
self.assertEqual(len(self.test_group.member_ids), 42)
# force a batch split with a low limit
self.env['ir.config_parameter'].sudo().set_param('mail.session.batch.size', 10)
with self.mock_mail_gateway():
self.format_and_process(
GROUP_TEMPLATE, self.test_group.member_ids[0].email,
self.test_group.alias_id.display_name,
subject='Never Surrender', msg_id='<glory.to.the.hypnotoad@localhost>', target_model='mail.group')
message = self.env['mail.group.message'].search([('mail_message_id.message_id', '=', '<glory.to.the.hypnotoad@localhost>')])
self.assertEqual(message.subject, 'Never Surrender', 'Should have created a <mail.group.message>')
mails = self.env['mail.mail'].search([('mail_message_id', '=', message.mail_message_id.id)])
# 42 -1 as the sender doesn't get an email
self.assertEqual(len(mails), 41, 'Should have send one and only one email per recipient')
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.addons.mail_group.models.mail_group_message')
def test_email_duplicated(self):
""" Test gateway does not accept two times same incoming email """