[FIX] mail, mail_group: recipients of mail groups

Mailing lists (mail.group) should not send specific notification emails.
Indeed there can be a lot of recipients and customizing each email can
take time to compute. This leads to posting a message on a mail.group
being very slow.

It is now possible for a model to customize the notification email
recipients computation. The first use is to ensure that mail.group
encodes recipients using email_to instead of recipients_ids. This way
less processing is performed on notification emails.
This commit is contained in:
Thibault Delavallée 2015-11-18 18:11:52 +01:00
parent a1db9c3ac0
commit d4a1eb4435
5 changed files with 84 additions and 1 deletions

View File

@ -211,15 +211,19 @@ class mail_notification(osv.Model):
chunks = [email_pids[x:x + max_recipients] for x in xrange(0, len(email_pids), max_recipients)]
email_ids = []
for chunk in chunks:
if message.model and message.res_id and self.pool.get(message.model) and hasattr(self.pool[message.model], 'message_get_recipient_values'):
recipient_values = self.pool[message.model].message_get_recipient_values(cr, uid, message.res_id, notif_message=message, recipient_ids=chunk, context=context)
else:
recipient_values = self.pool['mail.thread'].message_get_recipient_values(cr, uid, message.res_id, notif_message=message, recipient_ids=chunk, context=context)
mail_values = {
'mail_message_id': message.id,
'auto_delete': (context or {}).get('mail_auto_delete', True),
'mail_server_id': (context or {}).get('mail_server_id', False),
'body_html': body_html,
'recipient_ids': [(4, id) for id in chunk],
'references': references,
}
mail_values.update(custom_values)
mail_values.update(recipient_values)
email_ids.append(self.pool.get('mail.mail').create(cr, uid, mail_values, context=context))
# NOTE:
# 1. for more than 50 followers, use the queue system

View File

@ -19,6 +19,8 @@
#
##############################################################################
from email.utils import formataddr
import openerp
import openerp.tools as tools
from openerp.osv import osv
@ -240,3 +242,13 @@ class mail_group(osv.Model):
headers['X-Forge-To'] = list_to
res['headers'] = repr(headers)
return res
def message_get_recipient_values(self, cr, uid, id, notif_message=None, recipient_ids=None, context=None):
group = self.browse(cr, uid, id, context=context)
# real mailing list: multiple recipients (hidden by X-Forge-To)
if group.alias_domain and group.alias_name:
return {
'email_to': ','.join(formataddr((partner.name, partner.email)) for partner in self.pool['res.partner'].browse(cr, SUPERUSER_ID, recipient_ids, context=context)),
'recipient_ids': [],
}
return super(mail_group, self).message_get_recipient_values(cr, uid, id, notif_message=notif_message, recipient_ids=recipient_ids, context=context)

View File

@ -755,6 +755,16 @@ class mail_thread(osv.AbstractModel):
res = dict()
return res
def message_get_recipient_values(self, cr, uid, id, notif_message=None, recipient_ids=None, context=None):
""" Get specific notification recipient values to store on the notification
mail_mail. Basic method just set the recipient partners as mail_mail
recipients. Inherit this method to add custom behavior like using
recipient email_to to bypass the recipint_ids heuristics in the
mail sending mechanism. """
return {
'recipient_ids': [(4, pid) for pid in recipient_ids]
}
#------------------------------------------------------
# Mail gateway
#------------------------------------------------------

View File

@ -47,9 +47,13 @@ class TestMail(common.SavepointCase):
def send_email(self, cr, uid, message, *args, **kwargs):
return message['Message-Id']
def mail_group_message_get_recipient_values(self, cr, uid, id, notif_message=None, recipient_ids=None, context=None):
return self.pool['mail.thread'].message_get_recipient_values(cr, uid, id, notif_message=notif_message, recipient_ids=recipient_ids, context=context)
cls._init_mock_build_email()
cls.registry('ir.mail_server')._patch_method('build_email', build_email)
cls.registry('ir.mail_server')._patch_method('send_email', send_email)
cls.registry('mail.group')._patch_method('message_get_recipient_values', mail_group_message_get_recipient_values)
# Usefull models
cls.ir_model = cls.registry('ir.model')
@ -133,4 +137,5 @@ class TestMail(common.SavepointCase):
# Remove mocks
cls.registry('ir.mail_server')._revert_method('build_email')
cls.registry('ir.mail_server')._revert_method('send_email')
cls.registry('mail.group')._revert_method('message_get_recipient_values')
super(TestMail, cls).tearDownClass()

View File

@ -19,6 +19,8 @@
#
##############################################################################
from email.utils import formataddr
from .common import TestMail
from openerp.exceptions import AccessError
from openerp.osv.orm import except_orm
@ -27,6 +29,20 @@ from openerp.tools import mute_logger
class TestMailGroup(TestMail):
@classmethod
def setUpClass(cls):
super(TestMailGroup, cls).setUpClass()
# for specific tests of mail group, get back to its expected behavior
cls.registry('mail.group')._revert_method('message_get_recipient_values')
@classmethod
def tearDownClass(cls):
# set master class behavior back
def mail_group_message_get_recipient_values(self, cr, uid, id, notif_message=None, recipient_ids=None, context=None):
return self.pool['mail.thread'].message_get_recipient_values(cr, uid, id, notif_message=notif_message, recipient_ids=recipient_ids, context=context)
cls.registry('mail.group')._patch_method('message_get_recipient_values', mail_group_message_get_recipient_values)
super(TestMail, cls).tearDownClass()
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_00_mail_group_access_rights(self):
""" Testing mail_group access rights and basic mail_thread features """
@ -70,3 +86,39 @@ class TestMailGroup(TestMail):
self.assertFalse(fol_ids, 'unlinked document should not have any followers left')
msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_priv_id)])
self.assertFalse(msg_ids, 'unlinked document should not have any followers left')
def test_mail_group_notification_recipients_grouped(self):
# Data: set alias_domain to see emails with alias
self.registry('ir.config_parameter').set_param(self.cr, self.uid, 'mail.catchall.domain', 'schlouby.fr')
self.mail_group.message_subscribe_users(
self.cr, self.uid,
[self.group_pigs_id],
[self.user_raoul_id, self.user_bert_id]
)
self.mail_group.message_post(self.cr, self.uid, [self.group_pigs_id], body="Test", type='comment', subtype='mt_comment')
sent_emails = self._build_email_kwargs_list
self.assertEqual(len(sent_emails), 1)
for email in sent_emails:
self.assertEqual(
set(email['email_to']),
set([self.user_raoul.email, self.user_bert.email]))
def test_mail_group_notification_recipients_separated(self):
# Remove alias, should trigger classic behavior of mail group
self.mail_group.write(self.cr, self.uid, [self.group_pigs_id], {'alias_name': False})
self.mail_group.message_subscribe_users(
self.cr, self.uid,
[self.group_pigs_id],
[self.user_raoul_id, self.user_bert_id]
)
self.mail_group.message_post(self.cr, self.uid, [self.group_pigs_id], body="Test", type='comment', subtype='mt_comment')
sent_emails = self._build_email_kwargs_list
self.assertEqual(len(sent_emails), 2)
for email in sent_emails:
self.assertIn(
email['email_to'][0],
[formataddr((self.user_raoul.name, self.user_raoul.email)), formataddr((self.user_bert.name, self.user_bert.email))])