diff --git a/addons/test_mail/data/test_mail_data.py b/addons/test_mail/data/test_mail_data.py index adf963fcd7b..eb2b53dbf57 100644 --- a/addons/test_mail/data/test_mail_data.py +++ b/addons/test_mail/data/test_mail_data.py @@ -293,8 +293,8 @@ AAAAACwAAAAAAgACAAAEA3DJFQA7 """ MAIL_EML_ATTACHMENT = """Subject: Re: test attac -From: Anon -To: anon@gmail.com +From: {email_from} +To: {to} References: Message-ID: Date: Wed, 14 Mar 2018 14:26:58 +0100 @@ -508,8 +508,8 @@ X-ME-Sender: Received: from [1.1.1.1] (unknown [1.1.1.1]) by mail.xxxx.com (Postfix) with ESMTPA id BF5E1111D for ; Fri, 13 Apr 2018 22:11:50 -0400 (EDT) -From: "xxxx xxxx" -To: "xxxx" +From: Sylvie Lelitre +To: generic@mydomain.com Subject: Re: xxxx (Ref PO1) Date: Sat, 14 Apr 2018 02:11:42 +0000 Message-Id: @@ -674,3 +674,121 @@ o. --------=_MB48E455BD-2850-42EC-B1CA-886CDF48905E--""" + +MAIL_BOUNCE = """Return-Path: <> +X-Original-To: {to} +Delivered-To: {to} +Received: by mail2.test.ironsky (Postfix) + id 93A83A5F0D; Mon, 15 Apr 2019 15:41:06 +0200 (CEST) +Date: Mon, 15 Apr 2019 15:41:06 +0200 (CEST) +From: MAILER-DAEMON@mail2.test.ironsky (Mail Delivery System) +Subject: {subject} +To: {to} +Auto-Submitted: auto-replied +MIME-Version: 1.0 +Content-Type: multipart/report; report-type=delivery-status; + boundary="92726A5F09.1555335666/mail2.test.ironsky" +Message-Id: <20190415134106.93A83A5F0D@mail2.test.ironsky> + +This is a MIME-encapsulated message. + +--92726A5F09.1555335666/mail2.test.ironsky +Content-Description: Notification +Content-Type: text/plain; charset=us-ascii + +This is the mail system at host mail2.test.ironsky. + +I'm sorry to have to inform you that your message could not +be delivered to one or more recipients. It's attached below. + +For further assistance, please send mail to postmaster. + +If you do so, please include this problem report. You can +delete your own text from the attached returned message. + + The mail system + +<{email_from}>: host tribulant.com[23.22.38.89] said: 550 No such + person at this address. (in reply to RCPT TO command) + +--92726A5F09.1555335666/mail2.test.ironsky +Content-Description: Delivery report +Content-Type: message/delivery-status + +Reporting-MTA: dns; mail2.test.ironsky +X-Postfix-Queue-ID: 92726A5F09 +X-Postfix-Sender: rfc822; {to} +Arrival-Date: Mon, 15 Apr 2019 15:40:24 +0200 (CEST) + +Final-Recipient: rfc822; {email_from} +Original-Recipient: rfc822;{email_from} +Action: failed +Status: 5.0.0 +Remote-MTA: dns; tribulant.com +Diagnostic-Code: smtp; 550 No such person at this address. + +--92726A5F09.1555335666/mail2.test.ironsky +Content-Description: Undelivered Message +Content-Type: message/rfc822 + +Return-Path: <{to}> +Received: from [127.0.0.1] (host-212-68-194-133.dynamic.voo.be [212.68.194.133]) + (Authenticated sender: aaa) + by mail2.test.ironsky (Postfix) with ESMTPSA id 92726A5F09 + for <{email_from}>; Mon, 15 Apr 2019 15:40:24 +0200 (CEST) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=test.ironsky; s=mail; + t=1555335624; bh=x6cSjphxNDiRDMmm24lMAUKtdCFfftM8w/fdUyfoeFs=; + h=references:Subject:From:Reply-To:To:Date:From; + b=Bo0BsXAHgKiBfBtMvvO/+KaS9PuuS0+AozL4SxU05jHZcJFc7qFIPEpqkJIdbzNcQ + wq0PJYclgX7QZDOMm3VHQwcwOxBDXAbdnpfkPM9/wa+FWKfr6ikowMTHHT3CA1qNbe + h+BQVyBKIvr/LDFPSN2hQmfXWwWupm1lgUhJ07T4= +Content-Type: multipart/mixed; boundary="===============7355787381227985247==" +MIME-Version: 1.0 +Message-Id: <288877393590487.1555335624.090619087219238-openerp-32-project.task@aaa> +references: <670034078674109.1555335454.587288856506348-openerp-32-project.task@aaa> +Subject: Re: Test +From: Mitchell Admin +Reply-To: YourCompany Research & Development +To: Raoul <{email_from}> +Date: Mon, 15 Apr 2019 13:40:24 -0000 +X-Odoo-Objects: project.project-3, ,project.task-32 +X-Spam-Status: No, score=-2.0 required=5.0 tests=ALL_TRUSTED,BAYES_00, + DKIM_ADSP_NXDOMAIN,HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE + shortcircuit=no autolearn=no autolearn_force=no version=3.4.2 +X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on mail2.test.ironsky + +--===============7355787381227985247== +Content-Type: multipart/alternative; boundary="===============8588563873240298690==" +MIME-Version: 1.0 + +--===============8588563873240298690== +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: base64 + +CgpaYm91bGl1b2l1b2l6ZWYKCi0tCkFkbWluaXN0cmF0b3IKU2VudApieQpbMV0gWW91ckNvbXBh +bnkKCnVzaW5nCk9kb28gWzJdIC4KCgoKWzFdIGh0dHA6Ly93d3cuZXhhbXBsZS5jb20KWzJdIGh0 +dHBzOi8vd3d3Lm9kb28uY29tP3V0bV9zb3VyY2U9ZGImdXRtX21lZGl1bT1lbWFpbAo= + +--===============8588563873240298690== +Content-Type: text/html; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: base64 + +CjxkaXY+CgoKPGRpdj48cD5aYm91bGl1b2l1b2l6ZWY8L3A+PC9kaXY+Cgo8ZGl2IGNsYXNzPSJm +b250LXNpemU6IDEzcHg7Ij48c3BhbiBkYXRhLW8tbWFpbC1xdW90ZT0iMSI+LS0gPGJyIGRhdGEt +by1tYWlsLXF1b3RlPSIxIj4KQWRtaW5pc3RyYXRvcjwvc3Bhbj48L2Rpdj4KPHAgc3R5bGU9ImNv +bG9yOiAjNTU1NTU1OyBtYXJnaW4tdG9wOjMycHg7Ij4KICAgIFNlbnQKICAgIDxzcGFuPgogICAg +YnkKICAgIDxhIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246bm9uZTsgY29sb3I6ICM4NzVBN0I7IiBo +cmVmPSJodHRwOi8vd3d3LmV4YW1wbGUuY29tIj4KICAgICAgICA8c3Bhbj5Zb3VyQ29tcGFueTwv +c3Bhbj4KICAgIDwvYT4KICAgIAogICAgPC9zcGFuPgogICAgdXNpbmcKICAgIDxhIHRhcmdldD0i +X2JsYW5rIiBocmVmPSJodHRwczovL3d3dy5vZG9vLmNvbT91dG1fc291cmNlPWRiJmFtcDt1dG1f +bWVkaXVtPWVtYWlsIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOm5vbmU7IGNvbG9yOiAjODc1QTdC +OyI+T2RvbzwvYT4uCjwvcD4KPC9kaXY+CiAgICAgICAg + +--===============8588563873240298690==-- + +--===============7355787381227985247==-- + +--92726A5F09.1555335666/mail2.test.ironsky-- +""" diff --git a/addons/test_mail/models/test_mail_models.py b/addons/test_mail/models/test_mail_models.py index 50de0aca07d..bdf9f164da8 100644 --- a/addons/test_mail/models/test_mail_models.py +++ b/addons/test_mail/models/test_mail_models.py @@ -15,6 +15,19 @@ class MailTestSimple(models.Model): email_from = fields.Char() +class MailTestGateway(models.Model): + """ A very simple model only inheriting from mail.thread to test pure mass + mailing features and base performances. """ + _description = 'Simple Chatter Model for Mail Gateway' + _name = 'mail.test.gateway' + _inherit = ['mail.blacklist.mixin', 'mail.thread'] + _primary_email = 'email_from' + + name = fields.Char() + email_from = fields.Char() + custom_field = fields.Char() + + class MailTestStandard(models.Model): """ This model can be used in tests when automatic subscription and simple tracking is necessary. Most features are present in a simple way. """ diff --git a/addons/test_mail/security/ir.model.access.csv b/addons/test_mail/security/ir.model.access.csv index a856d7a3bac..b0d62e69a4a 100644 --- a/addons/test_mail/security/ir.model.access.csv +++ b/addons/test_mail/security/ir.model.access.csv @@ -2,6 +2,8 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_test_performance_mail,access_test_performance_mail,model_test_performance_mail,,1,1,1,1 access_mail_test_simple_portal,mail.test.simple.portal,model_mail_test_simple,base.group_portal,1,0,0,0 access_mail_test_simple_user,mail.test.simple.user,model_mail_test_simple,base.group_user,1,1,1,1 +access_mail_test_gateway_portal,mail.test.gateway.portal,model_mail_test_gateway,base.group_portal,1,0,0,0 +access_mail_test_gateway_user,mail.test.gateway.user,model_mail_test_gateway,base.group_user,1,1,1,1 access_mail_test_track_portal,mail.test.track.portal,model_mail_test_track,base.group_portal,0,0,0,0 access_mail_test_track_user,mail.test.track.user.employee,model_mail_test_track,base.group_user,1,1,1,1 access_mail_test_activity_portal,mail.test.activity.portal,model_mail_test_activity,base.group_portal,1,0,0,0 diff --git a/addons/test_mail/tests/common.py b/addons/test_mail/tests/common.py index 531bf4ea225..fd6ec9ce627 100644 --- a/addons/test_mail/tests/common.py +++ b/addons/test_mail/tests/common.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import json +import time from contextlib import contextmanager from email.utils import formataddr @@ -254,11 +255,12 @@ class MockEmails(common.SingleTransactionCase): cc='', msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>'): return template.format(to=to, subject=subject, cc=cc, extra=extra, email_from=email_from, msg_id=msg_id) - def format_and_process(self, template, to='groups@example.com, other@gmail.com', subject='Frogs', - extra='', email_from='Sylvie Lelitre ', - cc='', msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>', - model=None, target_model='mail.test.simple', target_field='name'): + def format_and_process(self, template, email_from, to, subject='Frogs', extra='', cc='', msg_id=False, + model=None, target_model='mail.test.gateway', target_field='name'): self.assertFalse(self.env[target_model].search([(target_field, '=', subject)])) + if not msg_id: + msg_id = "<%.7f-test@iron.sky>" % (time.time()) + mail = self.format(template, to=to, subject=subject, cc=cc, extra=extra, email_from=email_from, msg_id=msg_id) self.env['mail.thread'].with_context(mail_channel_noautofollow=True).message_process(model, mail) return self.env[target_model].search([(target_field, '=', subject)]) diff --git a/addons/test_mail/tests/test_mail_cc.py b/addons/test_mail/tests/test_mail_cc.py index 30c4613b02d..3e512c8798f 100644 --- a/addons/test_mail/tests/test_mail_cc.py +++ b/addons/test_mail/tests/test_mail_cc.py @@ -7,51 +7,48 @@ from odoo.tools import mute_logger, email_split_and_format from odoo.addons.test_mail.data.test_mail_data import MAIL_TEMPLATE -@tagged('cc_test') -class TestMailResend(common.BaseFunctionalTest, common.MockEmails): +@tagged('mail_thread_cc') +class TestMailCc(common.BaseFunctionalTest, common.MockEmails): + + @classmethod + def setUpClass(cls): + super(TestMailCc, cls).setUpClass() + + cls.email_from = 'Sylvie Lelitre ' + cls.alias = cls.env['mail.alias'].create({ + 'alias_name': 'cc_record', + 'alias_user_id': False, + 'alias_model_id': cls.env['ir.model']._get('mail.test.cc').id, + 'alias_contact': 'everyone'}) + + cls.env['ir.config_parameter'].set_param('mail.bounce.alias', 'bounce.test') + cls.env['ir.config_parameter'].set_param('mail.catchall.domain', 'test.com') + cls.env['ir.config_parameter'].set_param('mail.catchall.alias', 'catchall.test') @mute_logger('odoo.addons.mail.models.mail_thread') def test_message_cc_new(self): - alias = self.env['mail.alias'].create({ - 'alias_name': 'cc_record', - 'alias_user_id': False, - 'alias_model_id': self.env['ir.model']._get('mail.test.cc').id, - 'alias_contact': 'everyone'}) - record = self.format_and_process(MAIL_TEMPLATE, target_model='mail.test.cc', to='cc_record@example.com', - cc='cc1@example.com, cc2@example.com') + record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'cc_record@test.com', + cc='cc1@example.com, cc2@example.com', target_model='mail.test.cc') cc = email_split_and_format(record.email_cc) - self.assertEqual(sorted(cc), ['cc1@example.com', 'cc2@example.com'], 'cc should contains exactly 2 cc') + self.assertEqual(sorted(cc), ['cc1@example.com', 'cc2@example.com']) @mute_logger('odoo.addons.mail.models.mail_thread') def test_message_cc_update_with_old(self): record = self.env['mail.test.cc'].create({'email_cc': 'cc1 , cc2@example.com'}) - alias = self.env['mail.alias'].create({ - 'alias_name': 'cc_record', - 'alias_user_id': False, - 'alias_model_id': self.env['ir.model']._get('mail.test.cc').id, - 'alias_contact': 'everyone', - 'alias_force_thread_id': record.id}) + self.alias.write({'alias_force_thread_id': record.id}) - self.format_and_process(MAIL_TEMPLATE, subject='Re: Frogs', target_model='mail.test.cc', - msg_id='1198923581.41972151344608186799.JavaMail.diff1@agrolait.com', - to='cc_record@example.com', - cc='cc2 , cc3@example.com') + self.format_and_process(MAIL_TEMPLATE, self.email_from, 'cc_record@test.com', + cc='cc2 , cc3@example.com', target_model='mail.test.cc') cc = email_split_and_format(record.email_cc) self.assertEqual(sorted(cc), ['cc1 ', 'cc2@example.com', 'cc3@example.com'], 'new cc should have been added on record (unique)') @mute_logger('odoo.addons.mail.models.mail_thread') def test_message_cc_update_no_old(self): record = self.env['mail.test.cc'].create({}) - alias = self.env['mail.alias'].create({ - 'alias_name': 'cc_record', - 'alias_user_id': False, - 'alias_model_id': self.env['ir.model']._get('mail.test.cc').id, - 'alias_contact': 'everyone', - 'alias_force_thread_id': record.id}) - self.format_and_process(MAIL_TEMPLATE, subject='Re: Frogs', target_model='mail.test.cc', - msg_id='1198923581.41972151344608186799.JavaMail.diff1@agrolait.com', - to='cc_record@example.com', - cc='cc2 , cc3@example.com') + self.alias.write({'alias_force_thread_id': record.id}) + + self.format_and_process(MAIL_TEMPLATE, self.email_from, 'cc_record@test.com', + cc='cc2 , cc3@example.com', target_model='mail.test.cc') cc = email_split_and_format(record.email_cc) self.assertEqual(sorted(cc), ['cc2 ', 'cc3@example.com'], 'new cc should have been added on record (unique)') diff --git a/addons/test_mail/tests/test_mail_gateway.py b/addons/test_mail/tests/test_mail_gateway.py index dea415d6765..d81dd38d66d 100644 --- a/addons/test_mail/tests/test_mail_gateway.py +++ b/addons/test_mail/tests/test_mail_gateway.py @@ -5,23 +5,22 @@ import socket from email.utils import formataddr -from odoo.addons.test_mail.data.test_mail_data import \ - MAIL_TEMPLATE, MAIL_TEMPLATE_PLAINTEXT, MAIL_MULTIPART_MIXED, MAIL_MULTIPART_MIXED_TWO, \ - MAIL_MULTIPART_IMAGE, MAIL_SINGLE_BINARY, MAIL_EML_ATTACHMENT, MAIL_XHTML +from odoo.addons.test_mail.data import test_mail_data +from odoo.addons.test_mail.data.test_mail_data import MAIL_TEMPLATE from odoo.addons.test_mail.tests.common import BaseFunctionalTest, MockEmails from odoo.addons.test_mail.tests.common import mail_new_test_user from odoo.tools import mute_logger -class TestEmailParsing(BaseFunctionalTest, MockEmails): +from odoo.tests import tagged - @mute_logger('odoo.addons.mail.models.mail_thread') - def test_message_parse(self): - pass + +@tagged('mail_gateway') +class TestEmailParsing(BaseFunctionalTest, MockEmails): def test_message_parse_body(self): # test pure plaintext - plaintext = self.format(MAIL_TEMPLATE_PLAINTEXT, email_from='Sylvie Lelitre ') + plaintext = self.format(test_mail_data.MAIL_TEMPLATE_PLAINTEXT, email_from='Sylvie Lelitre ') res = self.env['mail.thread'].message_parse(plaintext) self.assertIn('Please call me as soon as possible this afternoon!', res['body']) @@ -31,7 +30,7 @@ class TestEmailParsing(BaseFunctionalTest, MockEmails): self.assertIn('

Please call me as soon as possible this afternoon!

', res['body']) # test multipart / mixed - res = self.env['mail.thread'].message_parse(MAIL_MULTIPART_MIXED) + res = self.env['mail.thread'].message_parse(test_mail_data.MAIL_MULTIPART_MIXED) self.assertNotIn( 'Should create a multipart/mixed: from gmail, *bold*, with attachment', res['body'], 'message_parse: text version should not be in body after parsing multipart/mixed') @@ -39,7 +38,7 @@ class TestEmailParsing(BaseFunctionalTest, MockEmails): '
Should create a multipart/mixed: from gmail, bold, with attachment.

', res['body'], 'message_parse: html version should be in body after parsing multipart/mixed') - res = self.env['mail.thread'].message_parse(MAIL_MULTIPART_MIXED_TWO) + res = self.env['mail.thread'].message_parse(test_mail_data.MAIL_MULTIPART_MIXED_TWO) self.assertNotIn('First and second part', res['body'], 'message_parse: text version should not be in body after parsing multipart/mixed') self.assertIn('First part', res['body'], @@ -47,56 +46,95 @@ class TestEmailParsing(BaseFunctionalTest, MockEmails): self.assertIn('Second part', res['body'], 'message_parse: second part of the html version should be in body after parsing multipart/mixed') - res = self.env['mail.thread'].message_parse(MAIL_SINGLE_BINARY) + res = self.env['mail.thread'].message_parse(test_mail_data.MAIL_SINGLE_BINARY) self.assertEqual(res['body'], '') self.assertEqual(res['attachments'][0][0], 'thetruth.pdf') + def test_message_parse_eml(self): + # Test that the parsing of mail with embedded emails as eml(msg) which generates empty attachments, can be processed. + self.env['mail.thread'].message_parse(self.format(test_mail_data.MAIL_EML_ATTACHMENT, email_from='Sylvie Lelitre ', to='generic@test.com')) + + def test_message_parse_plaintext(self): + """ Incoming email in plaintext should be stored as html """ + res = self.env['mail.thread'].message_parse(self.format(test_mail_data.MAIL_TEMPLATE_PLAINTEXT, email_from='Sylvie Lelitre ', to='generic@test.com')) + self.assertIn('
\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n
', res['body']) + + def test_message_parse_xhtml(self): + # Test that the parsing of XHTML mails does not fail + self.env['mail.thread'].message_parse(test_mail_data.MAIL_XHTML) + + +@tagged('mail_gateway') class TestMailgateway(BaseFunctionalTest, MockEmails): @classmethod def setUpClass(cls): super(TestMailgateway, cls).setUpClass() - mail_test_simple_model = cls.env['ir.model']._get('mail.test.simple') + cls.test_model = cls.env['ir.model']._get('mail.test.gateway') + cls.email_from = 'Sylvie Lelitre ' - cls.partner_1 = cls.env['res.partner'].with_context(BaseFunctionalTest._test_context).create({ + cls.test_record = cls.env['mail.test.gateway'].with_context(cls._test_context).create({ + 'name': 'Test', + 'email_from': 'ignasse@example.com', + }).with_context({}) + + cls.partner_1 = cls.env['res.partner'].with_context(cls._test_context).create({ 'name': 'Valid Lelitre', 'email': 'valid.lelitre@agrolait.com', }) - # groups@.. will cause the creation of new mail.test.simple + # groups@.. will cause the creation of new mail.test.gateway cls.alias = cls.env['mail.alias'].create({ 'alias_name': 'groups', 'alias_user_id': False, - 'alias_model_id': mail_test_simple_model.id, + 'alias_model_id': cls.test_model.id, 'alias_contact': 'everyone'}) # Set a first message on public group to test update and hierarchy cls.fake_email = cls.env['mail.message'].create({ - 'model': 'mail.test.simple', + 'model': 'mail.test.gateway', 'res_id': cls.test_record.id, 'subject': 'Public Discussion', 'message_type': 'email', + 'subtype_id': cls.env.ref('mail.mt_comment').id, 'author_id': cls.partner_1.id, - 'message_id': '<123456-openerp-%s-mail.test.simple@%s>' % (cls.test_record.id, socket.gethostname()), + 'message_id': '<123456-openerp-%s-mail.test.gateway@%s>' % (cls.test_record.id, socket.gethostname()), }) - @mute_logger('odoo.addons.mail.models.mail_thread') - def test_message_parse_eml(self): - """ Test that the parsing of mail with embedded emails as eml(msg) which generates empty attachments, can be processed. - """ - self.env['mail.thread'].message_process('mail.channel', MAIL_EML_ATTACHMENT) + cls.env['ir.config_parameter'].set_param('mail.bounce.alias', 'bounce.test') + cls.env['ir.config_parameter'].set_param('mail.catchall.domain', 'test.com') + cls.env['ir.config_parameter'].set_param('mail.catchall.alias', 'catchall.test') - @mute_logger('odoo.addons.mail.models.mail_thread') - def test_message_parse_xhtml(self): - """ Test that the parsing of mail with embedded emails as eml(msg) which generates empty attachments, can be processed. - """ - self.env['mail.thread'].message_process('mail.channel', MAIL_XHTML) + # -------------------------------------------------- + # Base low-level tests + # -------------------------------------------------- + + @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') + def test_message_process_alias_basic(self): + """ Test details of created message going through mailgateway """ + record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'groups@test.com', subject='Specific') + + # Test: one group created by mailgateway administrator as user_id is not set + self.assertEqual(len(record), 1, 'message_process: a new mail.test should have been created') + res = record.get_metadata()[0].get('create_uid') or [None] + self.assertEqual(res[0], self.env.uid) + + # Test: one message that is the incoming email + self.assertEqual(len(record.message_ids), 1) + msg = record.message_ids[0] + self.assertEqual(msg.subject, 'Specific') + self.assertIn('Please call me as soon as possible this afternoon!', msg.body) + self.assertEqual(msg.message_type, 'email') + self.assertEqual(msg.subtype_id, self.env.ref('mail.mt_comment')) @mute_logger('odoo.addons.mail.models.mail_thread') def test_message_process_cid(self): - record = self.format_and_process(MAIL_MULTIPART_IMAGE, to='groups@example.com') + record = self.format_and_process(test_mail_data.MAIL_MULTIPART_IMAGE, self.email_from, 'groups@test.com') message = record.message_ids[0] for attachment in message.attachment_ids: self.assertIn('/web/image/%s' % attachment.id, message.body) + self.assertEqual( + set(message.attachment_ids.mapped('name')), + set(['rosaçée.gif', 'verte!µ.gif', 'orangée.gif'])) def test_message_process_followers(self): pass @@ -113,24 +151,6 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): # self.assertEqual(self.test_public.message_channel_ids, self.env['mail.test'], # 'message_process: after reply, group should have 2 followers (0 channels)') - @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') - def test_message_process_alias_basic(self): - """ Test details of created message going through mailgateway """ - record = self.format_and_process(MAIL_TEMPLATE, subject='Specific') - - # Test: one group created by mailgateway administrator as user_id is not set - self.assertEqual(len(record), 1, 'message_process: a new mail.test should have been created') - res = record.get_metadata()[0].get('create_uid') or [None] - self.assertEqual(res[0], self.env.uid) - - # Test: one message that is the incoming email - self.assertEqual(len(record.message_ids), 1) - msg = record.message_ids[0] - self.assertEqual(msg.subject, 'Specific') - self.assertIn('Please call me as soon as possible this afternoon!', msg.body) - self.assertEqual(msg.message_type, 'email') - self.assertEqual(msg.subtype_id, self.env.ref('mail.mt_comment')) - # -------------------------------------------------- # Author recognition # -------------------------------------------------- @@ -138,24 +158,53 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') def test_message_process_email_email_from(self): """ Incoming email: not recognized author: email_from, no author_id, no followers """ - email_from = 'Sylvie Lelitre ' - - record = self.format_and_process(MAIL_TEMPLATE, email_from=email_from) + record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'groups@test.com') self.assertFalse(record.message_ids[0].author_id, 'message_process: unrecognized email -> no author_id') - self.assertEqual(record.message_ids[0].email_from, email_from) + self.assertEqual(record.message_ids[0].email_from, self.email_from) self.assertEqual(len(record.message_partner_ids), 0, 'message_process: newly create group should not have any follower') @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') def test_message_process_email_author(self): """ Incoming email: recognized author: email_from, author_id, added as follower """ - record = self.format_and_process(MAIL_TEMPLATE, email_from=formataddr((self.partner_1.name, self.partner_1.email))) + record = self.format_and_process(MAIL_TEMPLATE, self.partner_1.email_formatted, 'groups@test.com', subject='Test1') self.assertEqual(record.message_ids[0].author_id, self.partner_1, 'message_process: recognized email -> author_id') - self.assertEqual(record.message_ids[0].email_from, formataddr((self.partner_1.name, self.partner_1.email))) + self.assertEqual(record.message_ids[0].email_from, self.partner_1.email_formatted) self.assertEqual(len(self._mails), 0, 'No notification / bounce should be sent') + # Email recognized if partner has a formatted email + self.partner_1.write({'email': {'Valid Lelitre <%s>' % self.partner_1.email}}) + record = self.format_and_process(MAIL_TEMPLATE, self.partner_1.email, 'groups@test.com', subject='Test2') + + self.assertEqual(record.message_ids[0].author_id, self.partner_1, + 'message_process: recognized email -> author_id') + self.assertEqual(record.message_ids[0].email_from, self.partner_1.email) + self.assertEqual(len(self._mails), 0, 'No notification / bounce should be sent') + + @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') + def test_message_process_partner_find(self): + """ Finding the partner based on email, based on partner / user / follower """ + self.alias.write({'alias_force_thread_id': self.test_record.id}) + from_1 = self.env['res.partner'].create({'name': 'Brice Denisse', 'email': 'from.test@example.com'}) + + self.format_and_process(MAIL_TEMPLATE, from_1.email_formatted, 'groups@test.com') + self.assertEqual(self.test_record.message_ids[0].author_id, from_1) + self.test_record.message_unsubscribe([from_1.id]) + + from_2 = mail_new_test_user(self.env, login='B', groups='base.group_user', name='User Denisse', email='from.test@example.com') + + self.format_and_process(MAIL_TEMPLATE, from_1.email_formatted, 'groups@test.com') + self.assertEqual(self.test_record.message_ids[0].author_id, from_2.partner_id) + self.test_record.message_unsubscribe([from_2.partner_id.id]) + + from_3 = self.env['res.partner'].create({'name': 'FOllower Denisse', 'email': 'from.test@example.com'}) + self.test_record.message_subscribe([from_3.id]) + + self.format_and_process(MAIL_TEMPLATE, from_1.email_formatted, 'groups@test.com') + self.assertEqual(self.test_record.message_ids[0].author_id, from_3) + # -------------------------------------------------- # Alias configuration # -------------------------------------------------- @@ -165,7 +214,7 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): """ Test alias ownership """ self.alias.write({'alias_user_id': self.user_employee.id}) - record = self.format_and_process(MAIL_TEMPLATE) + record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'groups@test.com') self.assertEqual(len(record), 1) res = record.get_metadata()[0].get('create_uid') or [None] self.assertEqual(res[0], self.user_employee.id) @@ -175,20 +224,18 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): """ Incoming email: everyone: new record + message_new """ self.alias.write({'alias_contact': 'everyone'}) - record = self.format_and_process(MAIL_TEMPLATE, subject='Specific') + record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'groups@test.com', subject='Specific') self.assertEqual(len(record), 1) self.assertEqual(len(record.message_ids), 1) @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models.unlink', 'odoo.addons.mail.models.mail_mail') def test_message_process_alias_partners_bounce(self): """ Incoming email from an unknown partner on a Partners only alias -> bounce + test bounce email """ - self.env['ir.config_parameter'].set_param('mail.bounce.alias', 'bounce.test') - self.env['ir.config_parameter'].set_param('mail.catchall.domain', 'test.com') self.alias.write({'alias_contact': 'partners'}) # Test: no group created, email bounced - record = self.format_and_process(MAIL_TEMPLATE, subject='Should Bounce') - self.assertTrue(len(record) == 0) + record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'groups@test.com', subject='Should Bounce') + self.assertFalse(record) self.assertEqual(len(self._mails), 1, 'message_process: incoming email on Partners alias should send a bounce email') # Test bounce email @@ -201,28 +248,34 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): """ Incoming email from unknown partner / not follower partner on a Followers only alias -> bounce """ self.alias.write({ 'alias_contact': 'followers', - 'alias_parent_model_id': self.env['ir.model']._get('mail.test.simple').id, + 'alias_parent_model_id': self.env['ir.model']._get('mail.test.gateway').id, 'alias_parent_thread_id': self.test_record.id, }) # Test: unknown on followers alias -> bounce - record = self.format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com') - self.assertEqual(len(record), 0, 'message_process: should have bounced') + record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'groups@test.com', subject='Should Bounce') + self.assertFalse(record, 'message_process: should have bounced') self.assertEqual(len(self._mails), 1, 'message_process: incoming email on Followers alias should send a bounce email') + self.assertEqual(self._mails[0].get('subject'), 'Re: Should Bounce') + self.assertEqual(self._mails[0].get('email_to')[0], 'whatever-2a840@postmaster.twitter.com') + self.assertEqual(self._mails[0].get('email_from'), formataddr(('MAILER-DAEMON', 'bounce.test@test.com'))) # Test: partner on followers alias -> bounce self._init_mock_build_email() - record = self.format_and_process(MAIL_TEMPLATE, email_from=formataddr((self.partner_1.name, self.partner_1.email))) - self.assertTrue(len(record) == 0, 'message_process: should have bounced') + record = self.format_and_process(MAIL_TEMPLATE, self.partner_1.email_formatted, 'groups@test.com', subject='Should Bounce') + self.assertFalse(record, 'message_process: should have bounced') self.assertEqual(len(self._mails), 1, 'message_process: incoming email on Followers alias should send a bounce email') + self.assertEqual(self._mails[0].get('subject'), 'Re: Should Bounce') + self.assertEqual(self._mails[0].get('email_to')[0], 'whatever-2a840@postmaster.twitter.com') + self.assertEqual(self._mails[0].get('email_from'), formataddr(('MAILER-DAEMON', 'bounce.test@test.com'))) @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') def test_message_process_alias_partner(self): """ Incoming email from a known partner on a Partners alias -> ok (+ test on alias.user_id) """ self.alias.write({'alias_contact': 'partners'}) - record = self.format_and_process(MAIL_TEMPLATE, email_from=formataddr((self.partner_1.name, self.partner_1.email))) + record = self.format_and_process(MAIL_TEMPLATE, self.partner_1.email_formatted, 'groups@test.com') # Test: one group created by alias user self.assertEqual(len(record), 1) @@ -233,11 +286,11 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): """ Incoming email from a parent document follower on a Followers only alias -> ok """ self.alias.write({ 'alias_contact': 'followers', - 'alias_parent_model_id': self.env['ir.model']._get('mail.test.simple').id, + 'alias_parent_model_id': self.env['ir.model']._get('mail.test.gateway').id, 'alias_parent_thread_id': self.test_record.id, }) self.test_record.message_subscribe(partner_ids=[self.partner_1.id]) - record = self.format_and_process(MAIL_TEMPLATE, email_from=formataddr((self.partner_1.name, self.partner_1.email))) + record = self.format_and_process(MAIL_TEMPLATE, self.partner_1.email_formatted, 'groups@test.com') # Test: one group created by Raoul (or Sylvie maybe, if we implement it) self.assertEqual(len(record), 1) @@ -249,32 +302,26 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): self.test_record.message_subscribe(partner_ids=[self.partner_1.id]) record = self.format_and_process( - MAIL_TEMPLATE, email_from='valid.other@gmail.com', - msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>', - to='groups@example.com>', subject='Re: cats') + MAIL_TEMPLATE, self.email_from, 'groups@test.com>', + msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>', subject='Re: cats') # Test: no new group + new message - self.assertEqual(len(record), 0, 'message_process: alias update should not create new records') + self.assertFalse(record, 'message_process: alias update should not create new records') self.assertEqual(len(self.test_record.message_ids), 2) # Test: sent emails: 1 (Sylvie copy of the incoming email) - self.assertEqual(len(self._mails), 1, - 'message_process: one email should have been generated') - self.assertEqual(formataddr((self.partner_1.name, self.partner_1.email)), self._mails[0].get('email_to')[0], - 'message_process: email should be sent to Sylvie') + self.assertEmails(False, self.partner_1, email_from=self.email_from) # -------------------------------------------------- # Email Management # -------------------------------------------------- + @mute_logger('odoo.addons.mail.models.mail_thread') def test_message_process_write_to_catchall(self): """ Writing directly to catchall should bounce """ - self.env['ir.config_parameter'].set_param('mail.bounce.alias', 'bounce.test') - self.env['ir.config_parameter'].set_param('mail.catchall.alias', 'catchall.test') - self.env['ir.config_parameter'].set_param('mail.catchall.domain', 'test.com') # Test: no group created, email bounced - record = self.format_and_process(MAIL_TEMPLATE, to='catchall.test@test.com', subject='Should Bounce') - self.assertTrue(len(record) == 0) + record = self.format_and_process(MAIL_TEMPLATE, self.partner_1.email_formatted, '"My Super Catchall" ', subject='Should Bounce') + self.assertFalse(record) self.assertEqual(len(self._mails), 1, 'message_process: writing directly to catchall should bounce') # Test bounce email @@ -282,6 +329,44 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): self.assertEqual(self._mails[0].get('email_to')[0], 'whatever-2a840@postmaster.twitter.com') self.assertEqual(self._mails[0].get('email_from'), formataddr(('MAILER-DAEMON', 'bounce.test@test.com'))) + @mute_logger('odoo.addons.mail.models.mail_thread') + def test_message_process_bounce(self): + """ Writing to bounce alias is considered as a bounce """ + self.assertEqual(self.partner_1.message_bounce, 0) + + bounced_mail_id = 4442 + bounce_email_to = '%s+%s-%s-%s@%s' % ('bounce.test', bounced_mail_id, self.test_record._name, self.test_record.id, 'test.com') + record = self.format_and_process(test_mail_data.MAIL_BOUNCE, self.partner_1.email_formatted, bounce_email_to, subject='Undelivered Mail Returned to Sender') + self.assertFalse(record) + # self.assertEqual(self.partner_1.message_bounce, 1) # TDE FIXME: smart test crashing in current master + + @mute_logger('odoo.addons.mail.models.mail_thread') + def test_message_process_bounce_whatever_from(self): + """ Writing to bounce alias is considered as a bounce """ + self.assertEqual(self.partner_1.message_bounce, 0) + + bounced_mail_id = 4442 + bounce_email_to = '%s+%s-%s-%s@%s' % ('bounce.test', bounced_mail_id, self.test_record._name, self.test_record.id, 'test.com') + record = self.format_and_process(test_mail_data.MAIL_BOUNCE, 'Whatever ', bounce_email_to, subject='Undelivered Mail Returned to Sender') + self.assertFalse(record) + # self.assertEqual(self.partner_1.message_bounce, 1) # TDE FIXME: smart test crashing in current master + + @mute_logger('odoo.addons.mail.models.mail_thread') + def test_message_process_bounce_multipart_report(self): + """ Multipart/report emails should be considered as bounce """ + self.assertEqual(self.partner_1.message_bounce, 0) + record = self.format_and_process(test_mail_data.MAIL_BOUNCE, 'Whatever ', 'groups@test.com', subject='Undelivered Mail Returned to Sender') + self.assertFalse(record) + # self.assertEqual(self.partner_1.message_bounce, 1) # TDE FIXME: smart test crashing in current master + + @mute_logger('odoo.addons.mail.models.mail_thread') + def test_message_process_bounce_mailer_demon(self): + """ Multipart/report emails should be considered as bounce """ + self.assertEqual(self.partner_1.message_bounce, 0) + record = self.format_and_process(MAIL_TEMPLATE, 'MAILER-DAEMON@example.com', 'groups@test.com', subject='Undelivered Mail Returned to Sender') + self.assertFalse(record) + # self.assertEqual(self.partner_1.message_bounce, 1) # TDE FIXME: smart test crashing in current master + # -------------------------------------------------- # Thread formation # -------------------------------------------------- @@ -289,26 +374,24 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') def test_message_process_in_reply_to(self): """ Incoming email using in-rely-to should go into the right destination even with a wrong destination """ + init_msg_count = len(self.test_record.message_ids) self.format_and_process( - MAIL_TEMPLATE, email_from='valid.other@gmail.com', - msg_id='<1198923581.41972151344608186800.JavaMail.diff1@agrolait.com>', - to='erroneous@example.com>', subject='Re: news', - extra='In-Reply-To:\r\n\t%s\n' % self.fake_email.message_id) + MAIL_TEMPLATE, 'valid.other@gmail.com', 'erroneous@test.com>', + subject='Re: news', extra='In-Reply-To:\r\n\t%s\n' % self.fake_email.message_id) - self.assertEqual(len(self.test_record.message_ids), 2, 'message_process: group should contain one new message') - self.assertEqual(len(self.fake_email.child_ids), 1, 'message_process: new message should be children of the existing one') + self.assertEqual(len(self.test_record.message_ids), init_msg_count + 1) + self.assertEqual(self.fake_email.child_ids, self.test_record.message_ids[0]) @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') def test_message_process_references(self): """ Incoming email using references should go into the right destination even with a wrong destination """ init_msg_count = len(self.test_record.message_ids) self.format_and_process( - MAIL_TEMPLATE, to='erroneous@example.com', - extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id, - msg_id='<1198923581.41972151344608186800.JavaMail.4@agrolait.com>') + MAIL_TEMPLATE, self.email_from, 'erroneous@test.com', + extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id) self.assertEqual(len(self.test_record.message_ids), init_msg_count + 1) - self.assertEqual(len(self.fake_email.child_ids), 1) + self.assertEqual(self.fake_email.child_ids, self.test_record.message_ids[0]) @mute_logger('odoo.addons.mail.models.mail_thread') def test_message_process_references_external(self): @@ -319,28 +402,25 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): }) init_msg_count = len(self.test_record.message_ids) self.format_and_process( - MAIL_TEMPLATE, to='erroneous@example.com', - extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id, - msg_id='<1198923581.41972151344608186800.JavaMail.4@agrolait.com>') + MAIL_TEMPLATE, self.email_from, 'erroneous@test.com', + extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id) self.assertEqual(len(self.test_record.message_ids), init_msg_count + 1) - self.assertEqual(len(self.fake_email.child_ids), 1) + self.assertEqual(self.fake_email.child_ids, self.test_record.message_ids[0]) @mute_logger('odoo.addons.mail.models.mail_thread') def test_message_process_references_forward(self): """ Incoming email using references but with alias forward should not go into references destination """ - new_alias_2 = self.env['mail.alias'].create({ - 'alias_name': 'test', + self.env['mail.alias'].create({ + 'alias_name': 'test.alias', 'alias_user_id': False, 'alias_model_id': self.env['ir.model']._get('mail.test').id, 'alias_contact': 'everyone', }) init_msg_count = len(self.test_record.message_ids) res_test = self.format_and_process( - MAIL_TEMPLATE, to='test@example.com', - subject='My Dear Forward', - extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id, - msg_id='<1198923581.41972151344608186800.JavaMail.4@agrolait.com>', + MAIL_TEMPLATE, self.email_from, 'test.alias@test.com', + subject='My Dear Forward', extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id, target_model='mail.test') self.assertEqual(len(self.test_record.message_ids), init_msg_count) @@ -349,27 +429,97 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): self.assertEqual(len(res_test.message_ids), 1) @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') - def test_message_process_references_forward_cc(self): - """ Incoming email using references but with alias forward should not go into references destination """ - self.format_and_process( - MAIL_TEMPLATE, to='erroneous@example.com', cc='test@example.com', - subject='My Dear Forward', - extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id, - msg_id='<1198923581.41972151344608186800.JavaMail.4@agrolait.com>', - target_model='mail.test.simple') + def test_message_process_references_forward_same_model(self): + """ Incoming email using references but with alias forward on same model should be considered as a reply """ + self.env['mail.alias'].create({ + 'alias_name': 'test.alias', + 'alias_user_id': False, + 'alias_model_id': self.env['ir.model']._get('mail.test.gateway').id, + 'alias_contact': 'everyone', + }) + init_msg_count = len(self.test_record.message_ids) + res_test = self.format_and_process( + MAIL_TEMPLATE, self.email_from, 'test.alias@test.com', + subject='My Dear Forward', extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id, + target_model='mail.test') - self.assertEqual(len(self.test_record.message_ids), 2, 'message_process: group should contain one new message') - self.assertEqual(len(self.fake_email.child_ids), 1, 'message_process: new message should be children of the existing one') + self.assertEqual(len(self.test_record.message_ids), init_msg_count + 1) + self.assertEqual(len(self.fake_email.child_ids), 1) + self.assertFalse(res_test) @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') - def test_message_process_model_res_id(self): + def test_message_process_references_forward_cc(self): + """ Incoming email using references but with alias forward in CC should be considered as a repy (To > Cc) """ + self.env['mail.alias'].create({ + 'alias_name': 'test.alias', + 'alias_user_id': False, + 'alias_model_id': self.env['ir.model']._get('mail.test').id, + 'alias_contact': 'everyone', + }) + init_msg_count = len(self.test_record.message_ids) + res_test = self.format_and_process( + MAIL_TEMPLATE, self.email_from, 'catchall.test@test.com', cc='test.alias@test.com', + subject='My Dear Forward', extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id, + target_model='mail.test') + + self.assertEqual(len(self.test_record.message_ids), init_msg_count + 1) + self.assertEqual(len(self.fake_email.child_ids), 1) + self.assertFalse(res_test) + + @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models', 'odoo.addons.mail.models.mail_mail') + def test_message_process_reply_to_new_thread(self): + """ Test replies not being considered as replies but use destination information instead (aka, mass post + specific reply to using aliases) """ + first_record = self.env['mail.test.simple'].sudo(self.user_employee).create({'name': 'Replies to Record'}) + record_msg = first_record.message_post( + subject='Discussion', + no_auto_thread=False, + subtype='mail.mt_comment', + ) + self.assertEqual(record_msg.reply_to, formataddr(('%s %s' % (self.user_employee.company_id.name, first_record.name), '%s@%s' % ('catchall.test', 'test.com')))) + mail_msg = first_record.message_post( + subject='Replies to Record', + reply_to='groups@test.com', + no_auto_thread=True, + subtype='mail.mt_comment', + ) + self.assertEqual(mail_msg.reply_to, 'groups@test.com') + + # reply to mail but should be considered as a new mail for alias + msgID = '' + res_test = self.format_and_process( + MAIL_TEMPLATE, self.email_from, record_msg.reply_to, cc='', + subject='Re: Replies to Record', extra='In-Reply-To: %s' % record_msg.message_id, + msg_id=msgID, target_model='mail.test.simple') + incoming_msg = self.env['mail.message'].search([('message_id', '=', msgID)]) + self.assertFalse(res_test) + self.assertEqual(incoming_msg.model, 'mail.test.simple') + self.assertEqual(incoming_msg.parent_id, first_record.message_ids[-1]) + self.assertTrue(incoming_msg.res_id == first_record.id) + + # reply to mail but should be considered as a new mail for alias + msgID = '' + res_test = self.format_and_process( + MAIL_TEMPLATE, self.email_from, mail_msg.reply_to, cc='', + subject='Re: Replies to Record', extra='In-Reply-To: %s' % mail_msg.message_id, + msg_id=msgID, target_model='mail.test.gateway') + incoming_msg = self.env['mail.message'].search([('message_id', '=', msgID)]) + self.assertEqual(len(res_test), 1) + self.assertEqual(res_test.name, 'Re: Replies to Record') + self.assertEqual(incoming_msg.model, 'mail.test.gateway') + self.assertFalse(incoming_msg.parent_id) + self.assertTrue(incoming_msg.res_id == res_test.id) + + # -------------------------------------------------- + # Thread formation: mail gateway corner cases + # -------------------------------------------------- + + @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') + def test_message_process_extra_model_res_id(self): """ Incoming email with ref holding model / res_id but that does not match any message in the thread: must raise since OpenERP saas-3 """ self.assertRaises(ValueError, self.format_and_process, MAIL_TEMPLATE, - email_from=formataddr((self.partner_1.name, self.partner_1.email)), - to='noone@example.com', subject='spam', - extra='In-Reply-To: <12321321-openerp-%d-mail.test.simple@%s>' % (self.test_record.id, socket.gethostname()), - msg_id='<1198923581.41972151344608186802.JavaMail.diff1@agrolait.com>') + self.partner_1.email_formatted, 'noone@test.com', subject='spam', + extra='In-Reply-To: <12321321-openerp-%d-mail.test.gateway@%s>' % (self.test_record.id, socket.gethostname())) # when 6.1 messages are present, compat mode is available # Odoo 10 update: compat mode has been removed and should not work anymore @@ -377,20 +527,9 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): # Do: compat mode accepts partial-matching emails self.assertRaises( ValueError, - self.format_and_process, - MAIL_TEMPLATE, email_from=formataddr((self.partner_1.name, self.partner_1.email)), - msg_id='<1.2.JavaMail.new@agrolait.com>', - to='noone@example.com>', subject='spam', - extra='In-Reply-To: <12321321-openerp-%d-mail.test.simple@%s>' % (self.test_record.id, socket.gethostname())) - - # 3''. 6.1 compat mode should not work if hostname does not match! - # Odoo 10 update: compat mode has been removed and should not work anymore and does not depend from hostname - self.assertRaises(ValueError, - self.format_and_process, - MAIL_TEMPLATE, email_from=formataddr((self.partner_1.name, self.partner_1.email)), - msg_id='<1.3.JavaMail.new@agrolait.com>', - to='noone@example.com>', subject='spam', - extra='In-Reply-To: <12321321-openerp-%d-mail.test@neighbor.com>' % self.test_record.id) + self.format_and_process, MAIL_TEMPLATE, + self.partner_1.email_formatted, 'noone@test.com>', subject='spam', + extra='In-Reply-To: <12321321-openerp-%d-mail.test.gateway@%s>' % (self.test_record.id, socket.gethostname())) # Test created messages self.assertEqual(len(self.test_record.message_ids), 1) @@ -402,86 +541,47 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): self.alias.write({'alias_force_thread_id': self.test_record.id,}) # Post a base message - record = self.format_and_process( - MAIL_TEMPLATE, email_from='valid.other@gmail.com', subject='Re: super cats', - msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>') + record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'groups@test.com', subject='Re: super cats', msg_id='<123?456.diff1@agrolait.com>') + self.assertFalse(record) + self.assertEqual(len(self.test_record.message_ids), 2) # Do: due to some issue, same email goes back into the mailgateway record = self.format_and_process( - MAIL_TEMPLATE, email_from='other4@gmail.com', subject='Re: news', - msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>', - extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>\n') + MAIL_TEMPLATE, self.email_from, 'groups@test.com', subject='Re: news', + msg_id='<123?456.diff1@agrolait.com>', extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>\n') + self.assertFalse(record) + self.assertEqual(len(self.test_record.message_ids), 2) - # Test: no group 'Re: news' created, still only 1 Frogs group - self.assertEqual(len(record), 0) - - # Test: no new message - self.assertEqual(len(self.test_record.message_ids), 2, 'message_process: message with already existing message_id should not have been duplicated') # Test: message_id is still unique - no_of_msg = self.env['mail.message'].search_count([('message_id', 'ilike', '<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>')]) + no_of_msg = self.env['mail.message'].search_count([('message_id', 'ilike', '<123?456.diff1@agrolait.com>')]) self.assertEqual(no_of_msg, 1, 'message_process: message with already existing message_id should not have been duplicated') - @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') - def test_message_process_partner_find(self): - """ Finding the partner based on email, based on partner / user / follower """ - self.alias.write({'alias_force_thread_id': self.test_record.id}) - from_1 = self.env['res.partner'].create({'name': 'Brice Denisse', 'email': 'from.test@example.com'}) - - self.format_and_process(MAIL_TEMPLATE, msg_id='<1>', email_from='Brice Denisse ') - self.assertEqual(self.test_record.message_ids[0].author_id, from_1) - self.test_record.message_unsubscribe([from_1.id]) - - from_2 = mail_new_test_user(self.env, login='B', groups='base.group_user', name='Brice Denisse', email='from.test@example.com') - - self.format_and_process(MAIL_TEMPLATE, msg_id='<2>', email_from='Brice Denisse ') - self.assertEqual(self.test_record.message_ids[0].author_id, from_2.partner_id) - self.test_record.message_unsubscribe([from_2.partner_id.id]) - - from_3 = self.env['res.partner'].create({'name': 'Brice Denisse', 'email': 'from.test@example.com'}) - self.test_record.message_subscribe([from_3.id]) - - self.format_and_process(MAIL_TEMPLATE, msg_id='<3>', email_from='Brice Denisse ') - self.assertEqual(self.test_record.message_ids[0].author_id, from_3) - @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') def test_message_process_crash_wrong_model(self): """ Incoming email with model that does not accepts incoming emails must raise """ self.assertRaises(ValueError, self.format_and_process, - MAIL_TEMPLATE, - to='noone@example.com', subject='spam', extra='', model='res.country', - msg_id='<1198923581.41972151344608186760.JavaMail.new4@agrolait.com>') + MAIL_TEMPLATE, self.email_from, 'noone@test.com', + subject='spam', extra='', model='res.country') @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') def test_message_process_crash_no_data(self): """ Incoming email without model and without alias must raise """ self.assertRaises(ValueError, self.format_and_process, - MAIL_TEMPLATE, - to='noone@example.com', subject='spam', extra='', - msg_id='<1198923581.41972151344608186760.JavaMail.new5@agrolait.com>') + MAIL_TEMPLATE, self.email_from, 'noone@test.com', + subject='spam', extra='') @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') def test_message_process_fallback(self): """ Incoming email with model that accepting incoming emails as fallback """ record = self.format_and_process( - MAIL_TEMPLATE, to='noone@example.com', subject='Spammy', extra='', model='mail.test.simple', - msg_id='<1198923581.41972151344608186760.JavaMail.new6@agrolait.com>') + MAIL_TEMPLATE, self.email_from, 'noone@test.com', + subject='Spammy', extra='', model='mail.test.gateway') self.assertEqual(len(record), 1) - self.assertEqual(record._name, 'mail.test.simple') - - @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') - def test_message_process_plain_text(self): - """ Incoming email in plaintext should be stored as html """ - record = self.format_and_process( - MAIL_TEMPLATE_PLAINTEXT, to='groups@example.com', subject='Frogs Return', extra='', - msg_id='') - self.assertEqual(len(record), 1, 'message_process: a new mail.test should have been created') - msg = record.message_ids[0] - # signature recognition -> Sylvie should be in a span - self.assertIn('
\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n
', msg.body, - 'message_process: plaintext incoming email incorrectly parsed') + self.assertEqual(record.name, 'Spammy') + self.assertEqual(record._name, 'mail.test.gateway') @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models', 'odoo.addons.mail.models.mail_mail') def test_private_discussion(self): @@ -505,9 +605,7 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): self.assertIn('openerp-private', msg.message_id.split('@')[0], 'message_post: private discussion: message-id should contain the private keyword') # Do: Bert replies through mailgateway (is a customer) - self.format_and_process( - MAIL_TEMPLATE, to='not_important@mydomain.com', email_from='valid.lelitre@agrolait.com', - extra='In-Reply-To: %s' % msg.message_id, msg_id='') + self.format_and_process(MAIL_TEMPLATE, 'valid.lelitre@agrolait.com', 'not_important@mydomain.com', extra='In-Reply-To: %s' % msg.message_id) # Test: last mail_message created msg2 = self.env['mail.message'].search([], limit=1) @@ -526,27 +624,3 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): 'message_post: private discussion: incorrect recipients when replying') self.assertEqual(msg.needaction_partner_ids, self.user_employee.partner_id | self.partner_2, 'message_post: private discussion: incorrect notified recipients when replying') - - @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models', 'odoo.addons.mail.models.mail_mail') - def test_forward_parent_id(self): - msg = self.test_record.sudo(self.user_employee).message_post(no_auto_thread=True, subtype='mail.mt_comment') - self.assertNotIn(msg.model, msg.message_id.split('@')[0]) - self.assertNotIn('-%d-' % msg.res_id, msg.message_id.split('@')[0]) - self.assertIn('reply_to', msg.message_id.split('@')[0]) - - # forward it to a new thread AND an existing thread - fw_msg_id = '' - fw_message = MAIL_TEMPLATE.format(to='groups@example.com', - cc='', - subject='FW: Re: 1', - email_from='b.t@example.com', - extra='In-Reply-To: %s' % msg.message_id, - msg_id=fw_msg_id) - self.env['mail.thread'].message_process(None, fw_message) - msg_fw = self.env['mail.message'].search([('message_id', '=', fw_msg_id)]) - self.assertEqual(len(msg_fw), 1) - new_record = self.env['mail.test.simple'].search([('name', "=", msg_fw.subject)]) - self.assertEqual(len(new_record), 1) - self.assertEqual(msg_fw.model, 'mail.test.simple') - self.assertFalse(msg_fw.parent_id) - self.assertTrue(msg_fw.res_id == new_record.id) diff --git a/addons/test_mail/tests/test_message_compose.py b/addons/test_mail/tests/test_message_compose.py index 859dfa2a715..2397023db24 100644 --- a/addons/test_mail/tests/test_message_compose.py +++ b/addons/test_mail/tests/test_message_compose.py @@ -182,11 +182,10 @@ class TestMessagePost(BaseFunctionalTest, MockEmails, TestRecipients): self.assertEqual(msg.needaction_partner_ids, self.env['res.partner']) self.format_and_process( - MAIL_TEMPLATE_PLAINTEXT, - email_from=self.user_admin.email, + MAIL_TEMPLATE_PLAINTEXT, self.user_admin.email, 'not_my_businesss@example.com', msg_id='<1198923581.41972151344608186800.JavaMail.diff1@agrolait.com>', - to='not_my_businesss@example.com', - extra='In-Reply-To:\r\n\t%s\n' % msg.message_id) + extra='In-Reply-To:\r\n\t%s\n' % msg.message_id, + target_model='mail.test.simple') reply = self.test_record.message_ids - msg self.assertTrue(reply) self.assertEqual(reply.subtype_id, self.env.ref('mail.mt_note'))