diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py index 4dd48c2abe0..385558a9446 100644 --- a/addons/mail/mail_followers.py +++ b/addons/mail/mail_followers.py @@ -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 diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index 168bf64703c..6259887a1e5 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -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) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index baef24003a4..3b0d97c8240 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -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 #------------------------------------------------------ diff --git a/addons/mail/tests/common.py b/addons/mail/tests/common.py index ece31fd43c9..4abb2aa958c 100644 --- a/addons/mail/tests/common.py +++ b/addons/mail/tests/common.py @@ -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() diff --git a/addons/mail/tests/test_mail_group.py b/addons/mail/tests/test_mail_group.py index e343f1a429b..c523f6b2f38 100644 --- a/addons/mail/tests/test_mail_group.py +++ b/addons/mail/tests/test_mail_group.py @@ -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))])