[IMP] base, mail: improve and add tests about ir mail server
Prepares the move of ICP to mail before replacing them by dynamic alias domains. Improve test coverage, notably for edge cases. Continue to make tests more explicit after odoo/odoo#131492. Some tests are also merged to lessen number of different tests when possible, notably when only a test parameter differs (like giving an SMTP session or not). Clean ICP and mail servers setup in test classes allowing to remove some unnecessary extra initialization. Cleanup a mock in mail. Task-3453347 (Mail: Move Mail ICP from Base to Mail) Prepares Task-36879 (Mail: Support MultiCompany Aliases) Part-of: odoo/odoo#130750
This commit is contained in:
@@ -29,7 +29,7 @@ class TestAccountComposerPerformance(AccountTestInvoicingCommon, MailCommon):
|
||||
'body_html': '<p>TemplateBody for <t t-out="object.name"></t><t t-out="object.invoice_user_id.signature or \'\'"></t></p>',
|
||||
'description': 'Sent to customers with their invoices in attachment',
|
||||
'email_from': "{{ (object.invoice_user_id.email_formatted or user.email_formatted) }}",
|
||||
'mail_server_id': cls.mail_server_global.id,
|
||||
'mail_server_id': cls.mail_server_default.id,
|
||||
'model_id': cls.env['ir.model']._get_id('account.move'),
|
||||
'name': "Invoice: Test Sending",
|
||||
'partner_to': "{{ object.partner_id.id }}",
|
||||
@@ -124,9 +124,6 @@ class TestAccountComposerPerformance(AccountTestInvoicingCommon, MailCommon):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
# setup mail gateway to simulate complete reply-to computation
|
||||
self._init_mail_gateway()
|
||||
|
||||
# patch registry to simulate a ready environment
|
||||
self.patch(self.env.registry, 'ready', True)
|
||||
self.flush_tracking()
|
||||
@@ -200,7 +197,7 @@ class TestAccountComposerPerformance(AccountTestInvoicingCommon, MailCommon):
|
||||
'auto_delete': True,
|
||||
'email_from': self.user_account_other.email_formatted,
|
||||
'is_notification': True, # should keep logs by default
|
||||
'mail_server_id': self.mail_server_global,
|
||||
'mail_server_id': self.mail_server_default,
|
||||
'subject': _exp_subject,
|
||||
'reply_to': formataddr((
|
||||
f'{move.company_id.name} {_exp_move_name}',
|
||||
@@ -286,7 +283,7 @@ class TestAccountComposerPerformance(AccountTestInvoicingCommon, MailCommon):
|
||||
'auto_delete': True,
|
||||
'email_from': self.user_account_other.email_formatted,
|
||||
'is_notification': True, # should keep logs by default
|
||||
'mail_server_id': self.mail_server_global,
|
||||
'mail_server_id': self.mail_server_default,
|
||||
'subject': f'{self.env.user.company_id.name} Invoice (Ref {test_move.name})',
|
||||
'reply_to': formataddr((
|
||||
f'{test_move.company_id.name} {test_move.display_name}',
|
||||
@@ -373,7 +370,7 @@ class TestAccountComposerPerformance(AccountTestInvoicingCommon, MailCommon):
|
||||
'auto_delete': True,
|
||||
'email_from': self.user_account_other.email_formatted,
|
||||
'is_notification': True, # should keep logs by default
|
||||
'mail_server_id': self.mail_server_global,
|
||||
'mail_server_id': self.mail_server_default,
|
||||
'subject': f'SpanishSubject for {test_move.name}', # translated version
|
||||
'reply_to': formataddr((
|
||||
f'{test_move.company_id.name} {test_move.display_name}',
|
||||
|
||||
+14
-24
@@ -52,10 +52,15 @@ class MockEmail(common.BaseCase, MockSmtplibCase):
|
||||
self.mail_unlink_sent = mail_unlink_sent
|
||||
self._init_mail_mock()
|
||||
|
||||
def _ir_mail_server_build_email(model, *args, **kwargs):
|
||||
self._mails.append(kwargs)
|
||||
self._mails_args.append(args)
|
||||
return build_email_origin(model, *args, **kwargs)
|
||||
def _ir_mail_server_build_email(model, email_from, email_to, subject, body, **kwargs):
|
||||
self._mails.append({
|
||||
'email_from': email_from,
|
||||
'email_to': email_to,
|
||||
'subject': subject,
|
||||
'body': body,
|
||||
**kwargs,
|
||||
})
|
||||
return build_email_origin(model, email_from, email_to, subject, body, **kwargs)
|
||||
|
||||
def _mail_mail_create(model, *args, **kwargs):
|
||||
res = mail_create_origin(model, *args, **kwargs)
|
||||
@@ -79,40 +84,25 @@ class MockEmail(common.BaseCase, MockSmtplibCase):
|
||||
|
||||
def _init_mail_mock(self):
|
||||
self._mails = []
|
||||
self._mails_args = []
|
||||
self._new_mails = self.env['mail.mail'].sudo()
|
||||
|
||||
@classmethod
|
||||
def _init_mail_gateway(cls):
|
||||
super()._init_mail_gateway()
|
||||
cls.alias_domain = 'test.mycompany.com'
|
||||
cls.alias_catchall = 'catchall.test'
|
||||
cls.alias_bounce = 'bounce.test'
|
||||
cls.default_from = 'notifications'
|
||||
cls.default_from = 'notifications.test'
|
||||
cls.default_from_filter = False
|
||||
cls.env['ir.config_parameter'].set_param('mail.bounce.alias', cls.alias_bounce)
|
||||
cls.env['ir.config_parameter'].set_param('mail.catchall.domain', cls.alias_domain)
|
||||
cls.env['ir.config_parameter'].set_param('mail.catchall.alias', cls.alias_catchall)
|
||||
cls.env['ir.config_parameter'].set_param('mail.default.from', cls.default_from)
|
||||
cls.env['ir.config_parameter'].sudo().set_param('mail.default.from_filter', cls.default_from_filter)
|
||||
|
||||
# mailer daemon email preformatting
|
||||
cls.mailer_daemon_email = formataddr(('MAILER-DAEMON', '%s@%s' % (cls.alias_bounce, cls.alias_domain)))
|
||||
|
||||
@classmethod
|
||||
def _init_outgoing_gateway(cls):
|
||||
cls.env['ir.mail_server'].search([]).unlink()
|
||||
cls.mail_server_domain, cls.mail_server_global = cls.env['ir.mail_server'].create([
|
||||
{'from_filter': cls.alias_domain,
|
||||
'name': 'Domain Based Server',
|
||||
'smtp_encryption': 'none',
|
||||
'smtp_host': 'smtp_host',
|
||||
},
|
||||
{'from_filter': False,
|
||||
'name': 'No FromFilter Server',
|
||||
'smtp_encryption': 'none',
|
||||
'smtp_host': 'smtp_host',
|
||||
}
|
||||
])
|
||||
cls.mail_servers = cls.mail_server_domain + cls.mail_server_global
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# GATEWAY TOOLS
|
||||
# ------------------------------------------------------------
|
||||
@@ -1106,7 +1096,7 @@ class MailCommon(common.TransactionCase, MailCase):
|
||||
|
||||
# give default values for all email aliases and domain
|
||||
cls._init_mail_gateway()
|
||||
cls._init_outgoing_gateway()
|
||||
cls._init_mail_servers()
|
||||
|
||||
# by default avoid rendering restriction complexity
|
||||
cls.env['ir.config_parameter'].set_param('mail.restrict.template.rendering', False)
|
||||
|
||||
@@ -768,14 +768,14 @@ class TestComposerInternals(TestMailComposer):
|
||||
# 1. check without template + template update
|
||||
composer = self.env['mail.compose.message'].with_context(ctx).create({
|
||||
'body': '<p>Test Body <t t-out="record.name>/></p>',
|
||||
'mail_server_id': self.mail_server_global.id,
|
||||
'mail_server_id': self.mail_server_default.id,
|
||||
'scheduled_date': '{{ datetime.datetime(2023, 1, 10, 10, 0, 0) }}',
|
||||
'subject': 'My amazing subject for {{ record.name }}',
|
||||
})
|
||||
|
||||
# creation values are taken
|
||||
self.assertEqual(composer.body, '<p>Test Body <t t-out="record.name>/></p>')
|
||||
self.assertEqual(composer.mail_server_id, self.mail_server_global)
|
||||
self.assertEqual(composer.mail_server_id, self.mail_server_default)
|
||||
if composition_mode == 'comment' and not batch:
|
||||
self.assertEqual(composer.record_name, self.test_record.name)
|
||||
else:
|
||||
@@ -804,13 +804,13 @@ class TestComposerInternals(TestMailComposer):
|
||||
# manual values is kept over template
|
||||
composer.write({
|
||||
'body': '<p>Back to my amazing body <t t-out="record.name>/></p>',
|
||||
'mail_server_id': self.mail_server_global.id,
|
||||
'mail_server_id': self.mail_server_default.id,
|
||||
'record_name': 'Manual update',
|
||||
'scheduled_date': '{{ datetime.datetime(2023, 1, 10, 10, 0, 0) }}',
|
||||
'subject': 'Back to my amazing subject for {{ record.name }}',
|
||||
})
|
||||
self.assertEqual(composer.body, '<p>Back to my amazing body <t t-out="record.name>/></p>')
|
||||
self.assertEqual(composer.mail_server_id, self.mail_server_global)
|
||||
self.assertEqual(composer.mail_server_id, self.mail_server_default)
|
||||
self.assertEqual(composer.record_name, 'Manual update')
|
||||
self.assertEqual(composer.scheduled_date, '{{ datetime.datetime(2023, 1, 10, 10, 0, 0) }}')
|
||||
self.assertEqual(composer.subject, 'Back to my amazing subject for {{ record.name }}')
|
||||
@@ -821,13 +821,13 @@ class TestComposerInternals(TestMailComposer):
|
||||
|
||||
if composition_mode == 'comment' and not batch:
|
||||
self.assertEqual(composer.body, '<p>Back to my amazing body <t t-out="record.name>/></p>')
|
||||
self.assertEqual(composer.mail_server_id, self.mail_server_global)
|
||||
self.assertEqual(composer.mail_server_id, self.mail_server_default)
|
||||
self.assertEqual(composer.record_name, 'Manual update')
|
||||
self.assertEqual(composer.scheduled_date, '{{ datetime.datetime(2023, 1, 10, 10, 0, 0) }}')
|
||||
self.assertEqual(composer.subject, 'Back to my amazing subject for {{ record.name }}')
|
||||
else:
|
||||
self.assertEqual(composer.body, '<p>Back to my amazing body <t t-out="record.name>/></p>')
|
||||
self.assertEqual(composer.mail_server_id, self.mail_server_global)
|
||||
self.assertEqual(composer.mail_server_id, self.mail_server_default)
|
||||
self.assertEqual(composer.record_name, 'Manual update')
|
||||
self.assertEqual(composer.scheduled_date, '{{ datetime.datetime(2023, 1, 10, 10, 0, 0) }}')
|
||||
self.assertEqual(composer.subject, 'Back to my amazing subject for {{ record.name }}')
|
||||
|
||||
@@ -26,7 +26,6 @@ class TestMailMail(MailCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestMailMail, cls).setUpClass()
|
||||
cls._init_mail_servers()
|
||||
|
||||
cls.test_record = cls.env['mail.test.gateway'].with_context(cls._test_context).create({
|
||||
'name': 'Test',
|
||||
@@ -359,9 +358,6 @@ class TestMailMail(MailCommon):
|
||||
managed and stored at mail and notification level. """
|
||||
mail, notification = self.test_mail, self.test_notification
|
||||
|
||||
self.env['ir.config_parameter'].set_param('mail.catchall.domain', self.alias_domain)
|
||||
self.env['ir.config_parameter'].set_param('mail.default.from', self.default_from)
|
||||
|
||||
# MailServer.send_email(): _prepare_email_message: missing To
|
||||
for email_to in self.emails_falsy:
|
||||
self._reset_data()
|
||||
@@ -660,9 +656,8 @@ class TestMailMailServer(MailCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls._init_mail_servers()
|
||||
|
||||
cls.server_domain_2 = cls.env['ir.mail_server'].create({
|
||||
cls.mail_server_domain_2 = cls.env['ir.mail_server'].create({
|
||||
'from_filter': 'test_2.com',
|
||||
'name': 'Server 2',
|
||||
'smtp_host': 'test_2.com',
|
||||
@@ -676,7 +671,7 @@ class TestMailMailServer(MailCommon):
|
||||
"""
|
||||
self.assertEqual(
|
||||
self.env['ir.mail_server']._get_default_from_address(),
|
||||
f'notifications@{self.alias_domain}'
|
||||
f'{self.default_from}@{self.alias_domain}'
|
||||
)
|
||||
|
||||
mail_values = {
|
||||
@@ -696,19 +691,19 @@ class TestMailMailServer(MailCommon):
|
||||
# Should use the test_2 mail server
|
||||
# Once with "user_1@test_2.com" as login
|
||||
# Once with "user_2@test_2.com" as login
|
||||
mails |= self.env['mail.mail'].create([{
|
||||
mails += self.env['mail.mail'].create([{
|
||||
**mail_values,
|
||||
'email_from': 'user_1@test_2.com',
|
||||
} for _ in range(5)]) | self.env['mail.mail'].create([{
|
||||
} for _ in range(5)]) + self.env['mail.mail'].create([{
|
||||
**mail_values,
|
||||
'email_from': 'user_2@test_2.com',
|
||||
} for _ in range(5)])
|
||||
|
||||
# Mail server is forced
|
||||
mails |= self.env['mail.mail'].create([{
|
||||
mails += self.env['mail.mail'].create([{
|
||||
**mail_values,
|
||||
'email_from': 'user_1@test_2.com',
|
||||
'mail_server_id': self.server_domain.id,
|
||||
'mail_server_id': self.mail_server_domain.id,
|
||||
} for _ in range(5)])
|
||||
|
||||
with self.mock_smtplib_connection():
|
||||
@@ -722,21 +717,21 @@ class TestMailMailServer(MailCommon):
|
||||
self.assertEqual(self.connect_mocked.call_count, 4, 'Must be called once per batch which share the same mail server and the same smtp from')
|
||||
self.connect_mocked.assert_has_calls(
|
||||
calls=[
|
||||
call(smtp_from=f'notifications@{self.alias_domain}', mail_server_id=self.server_notification.id),
|
||||
call(smtp_from='user_1@test_2.com', mail_server_id=self.server_domain_2.id),
|
||||
call(smtp_from='user_2@test_2.com', mail_server_id=self.server_domain_2.id),
|
||||
call(smtp_from='user_1@test_2.com', mail_server_id=self.server_domain.id),
|
||||
call(smtp_from=f'{self.default_from}@{self.alias_domain}', mail_server_id=self.mail_server_notification.id),
|
||||
call(smtp_from='user_1@test_2.com', mail_server_id=self.mail_server_domain_2.id),
|
||||
call(smtp_from='user_2@test_2.com', mail_server_id=self.mail_server_domain_2.id),
|
||||
call(smtp_from='user_1@test_2.com', mail_server_id=self.mail_server_domain.id),
|
||||
],
|
||||
any_order=True,
|
||||
)
|
||||
|
||||
self.assertSMTPEmailsSent(message_from=f'"test" <notifications@{self.alias_domain}>',
|
||||
emails_count=5, from_filter=self.server_notification.from_filter)
|
||||
self.assertSMTPEmailsSent(message_from=f'"test_2" <notifications@{self.alias_domain}>',
|
||||
emails_count=5, from_filter=self.server_notification.from_filter)
|
||||
self.assertSMTPEmailsSent(message_from='user_1@test_2.com', emails_count=5, from_filter=self.server_domain_2.from_filter)
|
||||
self.assertSMTPEmailsSent(message_from='user_2@test_2.com', emails_count=5, from_filter=self.server_domain_2.from_filter)
|
||||
self.assertSMTPEmailsSent(message_from='user_1@test_2.com', emails_count=5, from_filter=self.server_domain.from_filter)
|
||||
self.assertSMTPEmailsSent(message_from=f'"test" <{self.default_from}@{self.alias_domain}>',
|
||||
emails_count=5, from_filter=self.mail_server_notification.from_filter)
|
||||
self.assertSMTPEmailsSent(message_from=f'"test_2" <{self.default_from}@{self.alias_domain}>',
|
||||
emails_count=5, from_filter=self.mail_server_notification.from_filter)
|
||||
self.assertSMTPEmailsSent(message_from='user_1@test_2.com', emails_count=5, mail_server=self.mail_server_domain_2)
|
||||
self.assertSMTPEmailsSent(message_from='user_2@test_2.com', emails_count=5, mail_server=self.mail_server_domain_2)
|
||||
self.assertSMTPEmailsSent(message_from='user_1@test_2.com', emails_count=5, mail_server=self.mail_server_domain)
|
||||
|
||||
|
||||
@tagged('mail_mail')
|
||||
|
||||
@@ -14,7 +14,6 @@ class TestMassMailingServer(TestMassMailCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestMassMailingServer, cls).setUpClass()
|
||||
cls._init_mail_servers()
|
||||
cls.recipients = cls._create_mailing_test_records(model='mailing.test.optout', count=8)
|
||||
|
||||
def test_mass_mailing_server_archived_usage_protection(self):
|
||||
@@ -98,23 +97,23 @@ class TestMassMailingServer(TestMassMailCommon):
|
||||
'body_html': 'Body for <t t-out="object.name" />',
|
||||
'email_from': 'unknow_email@unknow_domain.com',
|
||||
'mailing_model_id': self.env['ir.model']._get_id('mailing.test.optout'),
|
||||
'mail_server_id': self.server_notification.id,
|
||||
'mail_server_id': self.mail_server_notification.id,
|
||||
}])
|
||||
with self.mock_smtplib_connection():
|
||||
mailings.action_send_mail()
|
||||
self.assertEqual(self.find_mail_server_mocked.call_count, 3, 'Must be called only once per mail from except when forced')
|
||||
|
||||
for (expected_smtp_from, expected_msg_from, expected_from_filter) in [
|
||||
('specific_user@test.mycompany.com', 'specific_user@test.mycompany.com', self.server_user.from_filter),
|
||||
(f'{self.alias_bounce}@{self.alias_domain}', 'unknown_name@test.mycompany.com', self.server_domain.from_filter),
|
||||
for (expected_smtp_from, expected_msg_from, expected_mail_server) in [
|
||||
('specific_user@test.mycompany.com', 'specific_user@test.mycompany.com', self.mail_server_user),
|
||||
(f'{self.alias_bounce}@{self.alias_domain}', 'unknown_name@test.mycompany.com', self.mail_server_domain),
|
||||
# We do not have a mail server for this address email, so fall back to the "notifications@domain" email.
|
||||
('notifications@test.mycompany.com', '"Testing" <notifications@test.mycompany.com>', self.server_notification.from_filter),
|
||||
(f'{self.default_from}@{self.alias_domain}', f'"Testing" <{self.default_from}@{self.alias_domain}>', self.mail_server_notification),
|
||||
# forced sever
|
||||
('unknow_email@unknow_domain.com', 'unknow_email@unknow_domain.com', self.server_notification.from_filter),
|
||||
('unknow_email@unknow_domain.com', 'unknow_email@unknow_domain.com', self.mail_server_notification),
|
||||
]:
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from=expected_smtp_from,
|
||||
message_from=expected_msg_from,
|
||||
from_filter=expected_from_filter,
|
||||
mail_server=expected_mail_server,
|
||||
emails_count=8,
|
||||
)
|
||||
|
||||
@@ -341,11 +341,11 @@ class MockSmtplibCase:
|
||||
|
||||
def _build_email(self, mail_from, return_path=None, **kwargs):
|
||||
return self.env['ir.mail_server'].build_email(
|
||||
body=kwargs.pop('body', 'body'),
|
||||
email_from=mail_from,
|
||||
email_to='dest@example-é.com',
|
||||
mail_from,
|
||||
kwargs.pop('email_to', 'dest@example-é.com'),
|
||||
kwargs.pop('subject', 'subject'),
|
||||
kwargs.pop('body', 'body'),
|
||||
headers={'Return-Path': return_path} if return_path else None,
|
||||
subject='subject',
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@@ -354,19 +354,26 @@ class MockSmtplibCase:
|
||||
self.env['ir.mail_server'].send_email(msg, smtp_session=smtp_session)
|
||||
return smtp_session.messages.pop()
|
||||
|
||||
def assertSMTPEmailsSent(self, smtp_from=None, smtp_to_list=None, message_from=None, from_filter=None, emails_count=1):
|
||||
"""Check that the given email has been sent.
|
||||
|
||||
If one of the parameter is None, it's just ignored and not used to retrieve the email.
|
||||
def assertSMTPEmailsSent(self, smtp_from=None, smtp_to_list=None, message_from=None,
|
||||
mail_server=None, from_filter=None,
|
||||
emails_count=1):
|
||||
"""Check that the given email has been sent. If one of the parameter is
|
||||
None it is just ignored and not used to retrieve the email.
|
||||
|
||||
:param smtp_from: FROM used for the authentication to the mail server
|
||||
:param smtp_to_list: List of destination email address
|
||||
:param message_from: FROM used in the SMTP headers
|
||||
:param from_filter: from_filter of the <ir.mail_server> used to send the email
|
||||
Can use a lambda to check the value
|
||||
:arap mail_server: used to compare the 'from_filter' as an alternative
|
||||
to using the from_filter parameter
|
||||
:param from_filter: from_filter of the <ir.mail_server> used to send the
|
||||
email. False means 'match everything';'
|
||||
:param emails_count: the number of emails which should match the condition
|
||||
:return: True if at least one email has been found with those parameters
|
||||
"""
|
||||
if from_filter is not None and mail_server:
|
||||
raise ValueError('Invalid usage: use either from_filter either mail_server')
|
||||
if from_filter is None and mail_server is not None:
|
||||
from_filter = mail_server.from_filter
|
||||
matching_emails = filter(
|
||||
lambda email:
|
||||
(smtp_from is None or smtp_from == email['smtp_from'])
|
||||
@@ -391,10 +398,10 @@ class MockSmtplibCase:
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _init_mail_config(cls):
|
||||
def _init_mail_gateway(cls):
|
||||
cls.alias_bounce = 'bounce.test'
|
||||
cls.alias_domain = 'test.mycompany.com'
|
||||
cls.default_from = 'notifications'
|
||||
cls.default_from = 'notifications.test'
|
||||
cls.default_from_filter = False
|
||||
cls.env['ir.config_parameter'].sudo().set_param('mail.catchall.domain', cls.alias_domain)
|
||||
cls.env['ir.config_parameter'].sudo().set_param('mail.default.from', cls.default_from)
|
||||
@@ -409,12 +416,7 @@ class MockSmtplibCase:
|
||||
'smtp_host': 'smtp_host',
|
||||
'smtp_encryption': 'none',
|
||||
}
|
||||
(
|
||||
cls.server_domain,
|
||||
cls.server_user,
|
||||
cls.server_notification,
|
||||
cls.server_default,
|
||||
) = cls.env['ir.mail_server'].create([
|
||||
cls.mail_servers = cls.env['ir.mail_server'].create([
|
||||
{
|
||||
'name': 'Domain based server',
|
||||
'from_filter': 'test.mycompany.com',
|
||||
@@ -425,7 +427,7 @@ class MockSmtplibCase:
|
||||
** ir_mail_server_values,
|
||||
}, {
|
||||
'name': 'Server Notifications',
|
||||
'from_filter': 'notifications@test.mycompany.com',
|
||||
'from_filter': 'notifications.test@test.mycompany.com',
|
||||
** ir_mail_server_values,
|
||||
}, {
|
||||
'name': 'Server No From Filter',
|
||||
@@ -433,3 +435,7 @@ class MockSmtplibCase:
|
||||
** ir_mail_server_values,
|
||||
},
|
||||
])
|
||||
(
|
||||
cls.mail_server_domain, cls.mail_server_user,
|
||||
cls.mail_server_notification, cls.mail_server_default
|
||||
) = cls.mail_servers
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
|
||||
import email.message
|
||||
import email.policy
|
||||
import itertools
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from odoo import tools
|
||||
from odoo.addons.base.tests import test_mail_examples
|
||||
from odoo.addons.base.tests.common import MockSmtplibCase
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests import tagged, users
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tools import mute_logger
|
||||
from odoo.tools import config
|
||||
@@ -43,10 +42,14 @@ class EmailConfigCase(TransactionCase):
|
||||
for (icp_from, icp_domain), expected_from in zip(
|
||||
[
|
||||
('icp', 'test.mycompany.com'),
|
||||
('icp', False),
|
||||
('icp@another.company.com', 'test.mycompany.com'),
|
||||
('icp@another.company.com', False),
|
||||
(False, 'test.mycompany.com'),
|
||||
], [
|
||||
"icp@test.mycompany.com",
|
||||
"settings@example.com",
|
||||
"icp@another.company.com",
|
||||
"icp@another.company.com",
|
||||
"settings@example.com",
|
||||
],
|
||||
@@ -67,7 +70,7 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls._init_mail_config()
|
||||
cls._init_mail_gateway()
|
||||
cls._init_mail_servers()
|
||||
|
||||
cls.default_bounce_address = f'{cls.alias_bounce}@{cls.alias_domain}'
|
||||
@@ -124,35 +127,7 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
"There should be 3 headers MIME-Version: one on the enveloppe, "
|
||||
"one on the html part, one on the text part")
|
||||
|
||||
def test_mail_server_match_from_filter(self):
|
||||
""" Test the from_filter field on the "ir.mail_server". """
|
||||
# Should match
|
||||
tests = [
|
||||
('admin@mail.example.com', 'mail.example.com'),
|
||||
('admin@mail.example.com', 'mail.EXAMPLE.com'),
|
||||
('admin@mail.example.com', 'admin@mail.example.com'),
|
||||
('admin@mail.example.com', False),
|
||||
('"fake@test.mycompany.com" <admin@mail.example.com>', 'mail.example.com'),
|
||||
('"fake@test.mycompany.com" <ADMIN@mail.example.com>', 'mail.example.com'),
|
||||
('"fake@test.mycompany.com" <ADMIN@mail.example.com>', 'test.mycompany.com, mail.example.com, test2.com'),
|
||||
]
|
||||
for email, from_filter in tests:
|
||||
self.assertTrue(self.env['ir.mail_server']._match_from_filter(email, from_filter))
|
||||
|
||||
# Should not match
|
||||
tests = [
|
||||
('admin@mail.example.com', 'test@mail.example.com'),
|
||||
('admin@mail.example.com', 'test.mycompany.com'),
|
||||
('admin@mail.example.com', 'mail.éxample.com'),
|
||||
('admin@mmail.example.com', 'mail.example.com'),
|
||||
('admin@mail.example.com', 'mmail.example.com'),
|
||||
('"admin@mail.example.com" <fake@test.mycompany.com>', 'mail.example.com'),
|
||||
('"fake@test.mycompany.com" <ADMIN@mail.example.com>', 'test.mycompany.com, wrong.mail.example.com, test3.com'),
|
||||
]
|
||||
for email, from_filter in tests:
|
||||
self.assertFalse(self.env['ir.mail_server']._match_from_filter(email, from_filter))
|
||||
|
||||
def test_mail_body(self):
|
||||
def test_content_mail_body(self):
|
||||
bodies = [
|
||||
'content',
|
||||
'<p>content</p>',
|
||||
@@ -187,6 +162,34 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
body_alternative = body_alternative.strip('\n')
|
||||
self.assertEqual(body_alternative, expected)
|
||||
|
||||
def test_mail_server_match_from_filter(self):
|
||||
""" Test the from_filter field on the "ir.mail_server". """
|
||||
# Should match
|
||||
tests = [
|
||||
('admin@mail.example.com', 'mail.example.com'),
|
||||
('admin@mail.example.com', 'mail.EXAMPLE.com'),
|
||||
('admin@mail.example.com', 'admin@mail.example.com'),
|
||||
('admin@mail.example.com', False),
|
||||
('"fake@test.mycompany.com" <admin@mail.example.com>', 'mail.example.com'),
|
||||
('"fake@test.mycompany.com" <ADMIN@mail.example.com>', 'mail.example.com'),
|
||||
('"fake@test.mycompany.com" <ADMIN@mail.example.com>', 'test.mycompany.com, mail.example.com, test2.com'),
|
||||
]
|
||||
for email, from_filter in tests:
|
||||
self.assertTrue(self.env['ir.mail_server']._match_from_filter(email, from_filter))
|
||||
|
||||
# Should not match
|
||||
tests = [
|
||||
('admin@mail.example.com', 'test@mail.example.com'),
|
||||
('admin@mail.example.com', 'test.mycompany.com'),
|
||||
('admin@mail.example.com', 'mail.éxample.com'),
|
||||
('admin@mmail.example.com', 'mail.example.com'),
|
||||
('admin@mail.example.com', 'mmail.example.com'),
|
||||
('"admin@mail.example.com" <fake@test.mycompany.com>', 'mail.example.com'),
|
||||
('"fake@test.mycompany.com" <ADMIN@mail.example.com>', 'test.mycompany.com, wrong.mail.example.com, test3.com'),
|
||||
]
|
||||
for email, from_filter in tests:
|
||||
self.assertFalse(self.env['ir.mail_server']._match_from_filter(email, from_filter))
|
||||
|
||||
@mute_logger('odoo.models.unlink')
|
||||
def test_mail_server_priorities(self):
|
||||
""" Test if we choose the right mail server to send an email.
|
||||
@@ -207,41 +210,40 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
self.assertTrue(self.env['ir.mail_server']._get_default_from_address(), 'Notifications email must be set for testing')
|
||||
self.assertTrue(self.env['ir.mail_server']._get_default_bounce_address(), 'Bounce email must be set for testing')
|
||||
# this mail server can not be used for a specific email address and 2 domain names
|
||||
self.server_user.from_filter = "domain1.com, specific_user@test.mycompany.com, domain2.com"
|
||||
self.mail_server_user.from_filter = "domain1.com, specific_user@test.mycompany.com, domain2.com"
|
||||
|
||||
for email_from, (expected_mail_server, expected_email_from) in zip(
|
||||
[
|
||||
# matches user-specific server
|
||||
'specific_user@test.mycompany.com',
|
||||
# matches user-specific server (with formatting') -> should extract
|
||||
# email from full name, must keep the given email_from
|
||||
'"Name name@strange.name" <specific_user@test.mycompany.com>',
|
||||
'specific_user@test.mycompany.com',
|
||||
# case check
|
||||
'SPECIFIC_USER@test.mycompany.com',
|
||||
'specific_user@test.MYCOMPANY.com',
|
||||
# matches domain-based server: domain is case insensitive
|
||||
'unknown_email@test.mycompany.com',
|
||||
'unknown_email@TEST.MYCOMPANY.COM',
|
||||
'"Unknown" <unknown_email@test.mycompany.com>',
|
||||
# fallback on notification email
|
||||
'"Test" <test@unknown_domain.com>',
|
||||
# server_user multiple from filter check
|
||||
'"Test" <specific_user@test.mycompany.com>',
|
||||
# mail_server_user multiple from_filter check: can be used for a
|
||||
# specific email and 2 domain names -> check other domains in filter
|
||||
'"Example" <test@domain2.com>',
|
||||
'"Example" <test@domain1.com>',
|
||||
'"Test" <not_specific_user@test.mycompany.com>',
|
||||
], [
|
||||
(self.server_user, 'specific_user@test.mycompany.com'),
|
||||
# must extract email from full name, must keep the given email from
|
||||
(self.server_user, '"Name name@strange.name" <specific_user@test.mycompany.com>'),
|
||||
# should not be case sensitive
|
||||
(self.server_user, 'specific_user@test.mycompany.com'),
|
||||
(self.server_domain, 'unknown_email@test.mycompany.com'),
|
||||
# cover a different condition that the "email case insensitive" test: domain is case insensitive
|
||||
(self.server_domain, 'unknown_email@TEST.MYCOMPANY.COM'),
|
||||
# should take the notification email
|
||||
(self.server_notification, 'notifications@test.mycompany.com'),
|
||||
# server_user multipl from_filter check: can be used for a sepcific emial and 2 domain names
|
||||
# 1. entire email matches, server should be used
|
||||
(self.server_user, '"Test" <specific_user@test.mycompany.com>'),
|
||||
# 2. domain matches, server should be used
|
||||
(self.server_user, '"Example" <test@domain2.com>'),
|
||||
# 3. other domain matches, server shold be used
|
||||
(self.server_user, '"Example" <test@domain1.com>'),
|
||||
# check that we take the domain server and not the "user specific" server
|
||||
(self.server_domain, '"Test" <not_specific_user@test.mycompany.com>'),
|
||||
(self.mail_server_user, 'specific_user@test.mycompany.com'),
|
||||
(self.mail_server_user, '"Name name@strange.name" <specific_user@test.mycompany.com>'),
|
||||
(self.mail_server_user, 'SPECIFIC_USER@test.mycompany.com'),
|
||||
(self.mail_server_user, 'specific_user@test.MYCOMPANY.com'),
|
||||
(self.mail_server_domain, 'unknown_email@test.mycompany.com'),
|
||||
(self.mail_server_domain, 'unknown_email@TEST.MYCOMPANY.COM'),
|
||||
(self.mail_server_domain, '"Unknown" <unknown_email@test.mycompany.com>'),
|
||||
(self.mail_server_notification, 'notifications.test@test.mycompany.com'),
|
||||
# mail_server_user multiple from_filter check
|
||||
(self.mail_server_user, '"Example" <test@domain2.com>'),
|
||||
(self.mail_server_user, '"Example" <test@domain1.com>'),
|
||||
],
|
||||
):
|
||||
with self.subTest(email_from=email_from):
|
||||
@@ -256,70 +258,76 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
the FROM otherwise we cannot send any email. """
|
||||
self.env['ir.config_parameter'].sudo().set_param('mail.catchall.domain', False)
|
||||
self.env['ir.config_parameter'].sudo().set_param('mail.default.from', False)
|
||||
for email_from, (expected_mail_server, expected_from_filter, expected_email_from) in zip(
|
||||
|
||||
for email_from, (expected_mail_server, expected_email_from) in zip(
|
||||
[
|
||||
'test@unknown_domain.com',
|
||||
'specific_user@test.mycompany.com',
|
||||
'unknown_email@test.mycompany.com',
|
||||
# no notification set, must be forced to spoof the FROM
|
||||
'"Test" <test@unknown_domain.com>',
|
||||
], [
|
||||
(self.server_default, False, 'test@unknown_domain.com'),
|
||||
(self.mail_server_user, 'specific_user@test.mycompany.com'),
|
||||
(self.mail_server_domain, 'unknown_email@test.mycompany.com'),
|
||||
(self.mail_server_default, '"Test" <test@unknown_domain.com>'),
|
||||
],
|
||||
):
|
||||
with self.subTest(email_from=email_from):
|
||||
mail_server, mail_from = self.env['ir.mail_server']._find_mail_server(email_from='test@unknown_domain.com')
|
||||
self.assertEqual(mail_server.from_filter, expected_from_filter, 'No notifications email set, must be forced to spoof the FROM')
|
||||
mail_server, mail_from = self.env['ir.mail_server']._find_mail_server(email_from=email_from)
|
||||
self.assertEqual(mail_server, expected_mail_server)
|
||||
self.assertEqual(mail_from, expected_email_from)
|
||||
|
||||
@mute_logger('odoo.models.unlink')
|
||||
def test_mail_server_send_email(self):
|
||||
""" Test main 'send_email' usage: check mail_server choice based on from
|
||||
filters, encapsulation, spoofing. """
|
||||
IrMailServer = self.env['ir.mail_server']
|
||||
|
||||
for (mail_from, (expected_smtp_from, expected_msg_from, expected_from_filter)), provide_smtp in itertools.product(
|
||||
zip(
|
||||
[
|
||||
'specific_user@test.mycompany.com',
|
||||
'"Name" <test@unknown_domain.com>',
|
||||
'test@unknown_domain.com',
|
||||
'unknown_name@test.mycompany.com'
|
||||
], [
|
||||
# A mail server is configured for the email
|
||||
('specific_user@test.mycompany.com', 'specific_user@test.mycompany.com', 'specific_user@test.mycompany.com'),
|
||||
# No mail server are configured for the email address, so it will use the
|
||||
# notifications email instead and encapsulate the old email
|
||||
('notifications@test.mycompany.com', '"Name" <notifications@test.mycompany.com>', 'notifications@test.mycompany.com'),
|
||||
# same situation, but the original email has no name part
|
||||
('notifications@test.mycompany.com', '"test" <notifications@test.mycompany.com>', 'notifications@test.mycompany.com'),
|
||||
# A mail server is configured for the entire domain name, so we can use the bounce
|
||||
# email address because the mail server supports it
|
||||
(self.default_bounce_address, 'unknown_name@test.mycompany.com', 'test.mycompany.com'),
|
||||
],
|
||||
),
|
||||
[False, True], # provide SMTP session or not: should not impact sending
|
||||
for mail_from, (expected_smtp_from, expected_msg_from, expected_mail_server) in zip(
|
||||
[
|
||||
'specific_user@test.mycompany.com',
|
||||
'"Name" <test@unknown_domain.com>',
|
||||
'test@unknown_domain.com',
|
||||
'"Name" <unknown_name@test.mycompany.com>'
|
||||
], [
|
||||
# A mail server is configured for the email
|
||||
('specific_user@test.mycompany.com', 'specific_user@test.mycompany.com', self.mail_server_user),
|
||||
# No mail server are configured for the email address, so it will use the
|
||||
# notifications email instead and encapsulate the old email
|
||||
('notifications.test@test.mycompany.com', '"Name" <notifications.test@test.mycompany.com>', self.mail_server_notification),
|
||||
# same situation, but the original email has no name part
|
||||
('notifications.test@test.mycompany.com', '"test" <notifications.test@test.mycompany.com>', self.mail_server_notification),
|
||||
# A mail server is configured for the entire domain name, so we can use the bounce
|
||||
# email address because the mail server supports it
|
||||
(self.default_bounce_address, '"Name" <unknown_name@test.mycompany.com>', self.mail_server_domain),
|
||||
]
|
||||
):
|
||||
with self.subTest(mail_from=mail_from):
|
||||
with self.mock_smtplib_connection():
|
||||
if provide_smtp:
|
||||
smtp_session = IrMailServer.connect(smtp_from=mail_from)
|
||||
message = self._build_email(mail_from=mail_from)
|
||||
IrMailServer.send_email(message, smtp_session=smtp_session)
|
||||
else:
|
||||
message = self._build_email(mail_from=mail_from)
|
||||
IrMailServer.send_email(message)
|
||||
# test with and without providing an SMTP session, which should not impact test
|
||||
for provide_smtp in [False, True]:
|
||||
with self.subTest(mail_from=mail_from, provide_smtp=provide_smtp):
|
||||
with self.mock_smtplib_connection():
|
||||
if provide_smtp:
|
||||
smtp_session = IrMailServer.connect(smtp_from=mail_from)
|
||||
message = self._build_email(mail_from=mail_from)
|
||||
IrMailServer.send_email(message, smtp_session=smtp_session)
|
||||
else:
|
||||
message = self._build_email(mail_from=mail_from)
|
||||
IrMailServer.send_email(message)
|
||||
|
||||
self.connect_mocked.assert_called_once()
|
||||
self.assertEqual(len(self.emails), 1)
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from=expected_smtp_from,
|
||||
message_from=expected_msg_from,
|
||||
from_filter=expected_from_filter,
|
||||
)
|
||||
self.connect_mocked.assert_called_once()
|
||||
self.assertEqual(len(self.emails), 1)
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from=expected_smtp_from,
|
||||
message_from=expected_msg_from,
|
||||
mail_server=expected_mail_server,
|
||||
)
|
||||
|
||||
# remove the notification server
|
||||
# so <notifications@test.mycompany.com> will use the <test.mycompany.com> mail server
|
||||
# so <notifications.test@test.mycompany.com> will use the <test.mycompany.com> mail server
|
||||
# The mail server configured for the notifications email has been removed
|
||||
# but we can still use the mail server configured for test.mycompany.com
|
||||
# and so we will be able to use the bounce address
|
||||
# because we use the mail server for "test.mycompany.com"
|
||||
self.server_notification.unlink()
|
||||
self.mail_server_notification.unlink()
|
||||
for provide_smtp in [False, True]:
|
||||
with self.mock_smtplib_connection():
|
||||
if provide_smtp:
|
||||
@@ -334,13 +342,13 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
self.assertEqual(len(self.emails), 1)
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from=self.default_bounce_address,
|
||||
message_from='"Name" <notifications@test.mycompany.com>',
|
||||
from_filter='test.mycompany.com',
|
||||
message_from='"Name" <notifications.test@test.mycompany.com>',
|
||||
mail_server=self.mail_server_domain,
|
||||
)
|
||||
|
||||
@mute_logger('odoo.models.unlink')
|
||||
def test_mail_server_send_email_IDNA(self):
|
||||
# Test that the mail from / recipient envelop are encoded using IDNA
|
||||
""" Test that the mail from / recipient envelop are encoded using IDNA """
|
||||
self.env['ir.config_parameter'].sudo().set_param('mail.catchall.domain', 'ééééééé.com')
|
||||
with self.mock_smtplib_connection():
|
||||
message = self._build_email(mail_from='test@ééééééé.com')
|
||||
@@ -356,21 +364,30 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
|
||||
@mute_logger('odoo.models.unlink')
|
||||
def test_mail_server_send_email_default_from(self):
|
||||
# Test the case when the "mail.default.from" contains a full email address and not just the local part
|
||||
# the domain of this default email address can be different than the catchall domain
|
||||
self.env['ir.config_parameter'].sudo().set_param('mail.default.from', 'test@custom_domain.com')
|
||||
_custom_server = self.env['ir.mail_server'].create({
|
||||
""" Test the case when the "mail.default.from" contains a full email address
|
||||
and not just the local part the domain of this default email address can be
|
||||
different than the catchall domain """
|
||||
other_default_from = 'notifications.other.test@custom_domain.com'
|
||||
self.env['ir.config_parameter'].sudo().set_param('mail.default.from', other_default_from)
|
||||
custom_server = self.env['ir.mail_server'].create({
|
||||
'from_filter': 'custom_domain.com',
|
||||
'name': 'Custom Domain Server',
|
||||
'smtp_host': 'smtp_host',
|
||||
'smtp_encryption': 'none',
|
||||
})
|
||||
|
||||
for mail_from, (expected_smtp_from, expected_msg_from, expected_from_filter) in zip(
|
||||
for mail_from, (expected_smtp_from, expected_msg_from, expected_mail_server) in zip(
|
||||
[
|
||||
'"Name" <test@unknown_domain.com>',
|
||||
# custom server domain
|
||||
'"Custom Server Name" <customer.test@custom_domain.com>',
|
||||
# unknown domain
|
||||
'"Name" <customer.test@unknown_domain.com>',
|
||||
# notification server domain
|
||||
'"Name" <unknown_name@test.mycompany.com>'
|
||||
], [
|
||||
('test@custom_domain.com', '"Name" <test@custom_domain.com>', 'custom_domain.com'),
|
||||
('customer.test@custom_domain.com', '"Custom Server Name" <customer.test@custom_domain.com>', custom_server),
|
||||
(other_default_from, '"Name" <notifications.other.test@custom_domain.com>', custom_server),
|
||||
(self.default_bounce_address, '"Name" <unknown_name@test.mycompany.com>', self.mail_server_domain),
|
||||
],
|
||||
):
|
||||
with self.subTest(mail_from=mail_from):
|
||||
@@ -382,116 +399,85 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
smtp_from=expected_smtp_from,
|
||||
smtp_to_list=['dest@xn--example--i1a.com'],
|
||||
message_from=expected_msg_from,
|
||||
from_filter=expected_from_filter,
|
||||
mail_server=expected_mail_server,
|
||||
)
|
||||
|
||||
@mute_logger('odoo.models.unlink')
|
||||
@patch.dict(config.options, {"from_filter": "test.mycompany.com", "smtp_server": "example.com"})
|
||||
def test_mail_server_config_bin(self):
|
||||
"""Test the configuration provided in the odoo-bin arguments.
|
||||
|
||||
This config is used when no mail server exists.
|
||||
"""
|
||||
IrMailServer = self.env['ir.mail_server']
|
||||
|
||||
# Remove all mail server so we will use the odoo-bin arguments
|
||||
self.env['ir.mail_server'].search([]).unlink()
|
||||
self.assertFalse(self.env['ir.mail_server'].search([]))
|
||||
|
||||
for email_from, (expected_smtp_from, expected_msg_from) in zip(
|
||||
[
|
||||
# inside "from_filter" domain
|
||||
'specific_user@test.mycompany.com',
|
||||
# outside "from_filter" domain
|
||||
'test@unknown_domain.com',
|
||||
], [
|
||||
(self.default_bounce_address, 'specific_user@test.mycompany.com'),
|
||||
# outside "from_filter" domain: we will use notifications emails in the
|
||||
# headers, and bounce address in the envelope because the "from_filter"
|
||||
# allows to use the entire domain
|
||||
(self.default_bounce_address, '"test" <notifications@test.mycompany.com>'),
|
||||
]
|
||||
):
|
||||
with self.subTest(email_from=email_from):
|
||||
with self.mock_smtplib_connection():
|
||||
message = self._build_email(mail_from=email_from)
|
||||
IrMailServer.send_email(message)
|
||||
|
||||
self.connect_mocked.assert_called_once()
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from=expected_smtp_from,
|
||||
message_from=expected_msg_from,
|
||||
from_filter='test.mycompany.com',
|
||||
)
|
||||
|
||||
@mute_logger('odoo.models.unlink')
|
||||
@patch.dict(config.options, {'from_filter': 'test.mycompany.com', 'smtp_server': 'example.com'})
|
||||
def test_mail_server_config_bin_default_from_filter(self):
|
||||
"""Test that the config parameter "mail.default.from_filter" overwrites
|
||||
the odoo-bin argument "--from-filter" """
|
||||
self.env['ir.config_parameter'].sudo().set_param('mail.default.from_filter', 'example.com')
|
||||
|
||||
IrMailServer = self.env['ir.mail_server']
|
||||
|
||||
# Remove all mail server so we will use the odoo-bin arguments
|
||||
IrMailServer.search([]).unlink()
|
||||
self.assertFalse(IrMailServer.search([]))
|
||||
|
||||
# Use an email in the domain of the config parameter "mail.default.from_filter"
|
||||
with self.mock_smtplib_connection():
|
||||
message = self._build_email(mail_from='specific_user@example.com')
|
||||
IrMailServer.send_email(message)
|
||||
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from='specific_user@example.com',
|
||||
message_from='specific_user@example.com',
|
||||
from_filter='example.com',
|
||||
)
|
||||
|
||||
@mute_logger('odoo.models.unlink')
|
||||
@patch.dict(config.options, {
|
||||
"from_filter": "dummy@example.com, test.mycompany.com, dummy2@example.com",
|
||||
"smtp_server": "example.com",
|
||||
})
|
||||
def test_mail_server_config_bin_smtp_session(self):
|
||||
"""Test the configuration provided in the odoo-bin arguments.
|
||||
def test_mail_server_config_bin(self):
|
||||
""" Test the configuration provided in the odoo-bin arguments. This config
|
||||
is used when no mail server exists. Test with and without giving a
|
||||
pre-configured SMTP session, should not impact results.
|
||||
|
||||
This config is used when no mail server exists.
|
||||
Use a pre-configured SMTP session.
|
||||
Also check "mail.default.from_filter" parameter usage that should overwrite
|
||||
odoo-bin argument "--from-filter".
|
||||
"""
|
||||
IrMailServer = self.env['ir.mail_server']
|
||||
|
||||
# Remove all mail server so we will use the odoo-bin arguments
|
||||
self.env['ir.mail_server'].search([]).unlink()
|
||||
self.assertFalse(self.env['ir.mail_server'].search([]))
|
||||
IrMailServer.search([]).unlink()
|
||||
self.assertFalse(IrMailServer.search([]))
|
||||
|
||||
for email_from, (expected_smtp_from, expected_msg_from) in zip(
|
||||
for mail_from, (expected_smtp_from, expected_msg_from) in zip(
|
||||
[
|
||||
# use an email in the domain of the "from_filter"
|
||||
# inside "from_filter" domain
|
||||
'specific_user@test.mycompany.com',
|
||||
# Use an email outside of the domain of the "from_filter"
|
||||
'"Formatted Name" <specific_user@test.mycompany.com>',
|
||||
'"Formatted Name" <specific_user@test.MYCOMPANY.com>',
|
||||
'"Formatted Name" <SPECIFIC_USER@test.mycompany.com>',
|
||||
# outside "from_filter" domain
|
||||
'test@unknown_domain.com',
|
||||
'"Formatted Name" <test@unknown_domain.com>',
|
||||
], [
|
||||
# inside "from_filter" domain: no rewriting
|
||||
(self.default_bounce_address, 'specific_user@test.mycompany.com'),
|
||||
# Use an email outside of the domain of the "from_filter"
|
||||
# So we will use the notifications email in the headers and the bounce address
|
||||
# in the envelop because the "from_filter" allows to use the entire domain
|
||||
(self.default_bounce_address, '"test" <notifications@test.mycompany.com>')
|
||||
(self.default_bounce_address, '"Formatted Name" <specific_user@test.mycompany.com>'),
|
||||
(self.default_bounce_address, '"Formatted Name" <specific_user@test.MYCOMPANY.com>'),
|
||||
(self.default_bounce_address, '"Formatted Name" <SPECIFIC_USER@test.mycompany.com>'),
|
||||
# outside "from_filter" domain: we will use notifications emails in the
|
||||
# headers, and bounce address in the envelope because the "from_filter"
|
||||
# allows to use the entire domain
|
||||
(self.default_bounce_address, '"test" <notifications.test@test.mycompany.com>'),
|
||||
(self.default_bounce_address, '"Formatted Name" <notifications.test@test.mycompany.com>'),
|
||||
]
|
||||
):
|
||||
with self.subTest(email_from=email_from):
|
||||
with self.mock_smtplib_connection():
|
||||
smtp_session = IrMailServer.connect(smtp_from=email_from)
|
||||
message = self._build_email(mail_from=email_from)
|
||||
IrMailServer.send_email(message, smtp_session=smtp_session)
|
||||
for provide_smtp in [False, True]: # providing smtp session should ont impact test
|
||||
with self.subTest(mail_from=mail_from, provide_smtp=provide_smtp):
|
||||
with self.mock_smtplib_connection():
|
||||
if provide_smtp:
|
||||
smtp_session = IrMailServer.connect(smtp_from=mail_from)
|
||||
message = self._build_email(mail_from=mail_from)
|
||||
IrMailServer.send_email(message, smtp_session=smtp_session)
|
||||
else:
|
||||
message = self._build_email(mail_from=mail_from)
|
||||
IrMailServer.send_email(message)
|
||||
|
||||
self.connect_mocked.assert_called_once()
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from=expected_smtp_from,
|
||||
message_from=expected_msg_from,
|
||||
from_filter='dummy@example.com, test.mycompany.com, dummy2@example.com',
|
||||
)
|
||||
self.connect_mocked.assert_called_once()
|
||||
self.assertEqual(len(self.emails), 1)
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from=expected_smtp_from,
|
||||
message_from=expected_msg_from,
|
||||
from_filter="dummy@example.com, test.mycompany.com, dummy2@example.com",
|
||||
)
|
||||
|
||||
# for from_filter in ICP, overwrite the one from odoo-bin
|
||||
self.env['ir.config_parameter'].sudo().set_param('mail.default.from_filter', 'icp.example.com')
|
||||
|
||||
# Use an email in the domain of the config parameter "mail.default.from_filter"
|
||||
with self.mock_smtplib_connection():
|
||||
message = self._build_email(mail_from='specific_user@icp.example.com')
|
||||
IrMailServer.send_email(message)
|
||||
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from='specific_user@icp.example.com',
|
||||
message_from='specific_user@icp.example.com',
|
||||
from_filter='icp.example.com',
|
||||
)
|
||||
|
||||
@users('admin')
|
||||
def test_mail_server_get_test_email_addresses(self):
|
||||
"""Test the email used to test the mail server connection."""
|
||||
test_server = self.env['ir.mail_server'].create({
|
||||
@@ -509,12 +495,20 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
('notifications@example.com', 'dummy.com, full_email@example_2.com, dummy2.com'),
|
||||
('notifications', 'dummy.com, full_email@example_2.com, dummy2.com'),
|
||||
('notifications@example.com', 'example.com'),
|
||||
# default relies on "odoo"
|
||||
(False, 'example.com'),
|
||||
# fallback on user email
|
||||
('example_2.com', False),
|
||||
(False, False),
|
||||
], [
|
||||
'noreply@example_2.com',
|
||||
'notifications@example_2.com',
|
||||
'full_email@example_2.com',
|
||||
'full_email@example_2.com',
|
||||
'notifications@example.com',
|
||||
'odoo@example.com',
|
||||
self.env.user.email,
|
||||
self.env.user.email,
|
||||
],
|
||||
):
|
||||
with self.subTest(default_from=default_from, from_filter=from_filter):
|
||||
@@ -526,16 +520,16 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
@mute_logger('odoo.models.unlink')
|
||||
@patch.dict(config.options, {'from_filter': 'fake.com', 'smtp_server': 'cli_example.com'})
|
||||
def test_mail_server_config_cli(self):
|
||||
"""Check the mail server when the "smtp_authentication" is "cli".
|
||||
|
||||
Should take the configuration from the odoo-bin argument.
|
||||
The "from_filter" of the mail server should overwrite the one set
|
||||
in the CLI arguments.
|
||||
""" Test the mail server configuration when the "smtp_authentication" is
|
||||
"cli". It should take the configuration from the odoo-bin argument. The
|
||||
"from_filter" of the mail server should overwrite the one set in the CLI
|
||||
arguments.
|
||||
"""
|
||||
IrMailServer = self.env['ir.mail_server']
|
||||
# should be ignored by the mail server
|
||||
self.env['ir.config_parameter'].sudo().set_param('mail.default.from_filter', 'fake.com')
|
||||
|
||||
self.env['ir.mail_server'].create([{
|
||||
server_other = IrMailServer.create([{
|
||||
'name': 'Server No From Filter',
|
||||
'smtp_host': 'smtp_host',
|
||||
'smtp_encryption': 'none',
|
||||
@@ -543,27 +537,25 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
|
||||
'from_filter': 'dummy@example.com, cli_example.com, dummy2@example.com',
|
||||
}])
|
||||
|
||||
IrMailServer = self.env['ir.mail_server']
|
||||
for mail_from, (expected_smtp_from, expected_msg_from, expected_mail_server) in zip(
|
||||
[
|
||||
# check that the CLI server take the configuration in the odoo-bin argument
|
||||
# except the from_filter which is taken on the mail server
|
||||
'test@cli_example.com',
|
||||
# other mail servers still work
|
||||
'specific_user@test.mycompany.com',
|
||||
], [
|
||||
('test@cli_example.com', 'test@cli_example.com', server_other),
|
||||
('specific_user@test.mycompany.com', 'specific_user@test.mycompany.com', self.mail_server_user),
|
||||
],
|
||||
):
|
||||
with self.subTest(mail_from=mail_from):
|
||||
with self.mock_smtplib_connection():
|
||||
message = self._build_email(mail_from=mail_from)
|
||||
IrMailServer.send_email(message)
|
||||
|
||||
# check that the CLI server take the configuration in the odoo-bin argument
|
||||
# except the from_filter which is taken on the mail server
|
||||
with self.mock_smtplib_connection():
|
||||
message = self._build_email(mail_from='test@cli_example.com')
|
||||
IrMailServer.send_email(message)
|
||||
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from='test@cli_example.com',
|
||||
message_from='test@cli_example.com',
|
||||
from_filter='dummy@example.com, cli_example.com, dummy2@example.com',
|
||||
)
|
||||
|
||||
# other mail server still work
|
||||
with self.mock_smtplib_connection():
|
||||
message = self._build_email(mail_from='specific_user@test.mycompany.com')
|
||||
IrMailServer.send_email(message)
|
||||
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from='specific_user@test.mycompany.com',
|
||||
message_from='specific_user@test.mycompany.com',
|
||||
from_filter='specific_user@test.mycompany.com',
|
||||
)
|
||||
self.assertSMTPEmailsSent(
|
||||
smtp_from=expected_smtp_from,
|
||||
message_from=expected_msg_from,
|
||||
mail_server=expected_mail_server,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user