def _send_wecom_prepare_values(self, partner=None): """ 根据合作伙伴返回有关特定电子邮件值的字典,或者对整个邮件都是通用的。对于特定电子邮件值取决于对伙伴的字典,或者对mail.email_to给出的整个收件人来说都是通用的。 :param Model partner: 具体的收件人合作伙伴 """ self.ensure_one() body_html = self._send_prepare_body_html() body_json = self._send_prepare_body_json() body_markdown = self._send_prepare_body_markdown() # body_alternative = tools.html2plaintext(body_html) if partner: email_to = [ tools.formataddr((partner.name or "False", partner.email or "False")) ] message_to_user = [ tools.formataddr( (partner.name or "False", partner.wecom_userid or "False") ) ] else: email_to = tools.email_split_and_format(self.email_to) message_to_user = self.message_to_user res = { # "message_body_text": message_body_text, # "message_body_html": message_body_html, "email_to": email_to, "message_to_user": message_to_user, "body_json": body_json, "body_html": body_html, "body_markdown": body_markdown, } return res
def test_channel_mailing_list_recipients(self): """ Posting a message on a mailing list should send one email to all recipients """ self.env['ir.config_parameter'].set_param('mail.catchall.domain', 'schlouby.fr') self.test_channel.write({'email_send': True}) # Subscribe an user without email. We shouldn't try to send email to them. nomail = self.env['res.users'].create({ "login": "******", "name": "No Mail", "email": False, "notification_type": "email", }) self._join_channel( self.test_channel, self.user_employee.partner_id | self.test_partner | nomail.partner_id) self.test_channel.message_post(body="Test", message_type='comment', subtype='mt_comment') self.assertEqual(len(self._mails), 1) for email in self._mails: self.assertEqual( set(email['email_to']), set([ formataddr( (self.user_employee.name, self.user_employee.email)), formataddr( (self.test_partner.name, self.test_partner.email)) ]))
def test_message_process_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='*****@*****.**', subject='spam', extra='In-Reply-To: <12321321-openerp-%d-mail.test.simple@%s>' % (self.test_record.id, socket.gethostname()), msg_id='<*****@*****.**>') # when 6.1 messages are present, compat mode is available # Odoo 10 update: compat mode has been removed and should not work anymore self.fake_email.write({'message_id': False}) # 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='<*****@*****.**>', to='*****@*****.**>', 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='<*****@*****.**>', to='*****@*****.**>', subject='spam', extra='In-Reply-To: <*****@*****.**>' % self.test_record.id) # Test created messages self.assertEqual(len(self.test_record.message_ids), 1) self.assertEqual(len(self.test_record.message_ids[0].child_ids), 0)
def _notify_get_reply_to_formatted_email(self, record_email, record_name): """ Compute formatted email for reply_to and try to avoid refold issue with python that splits the reply-to over multiple lines. It is due to a bad management of quotes (missing quotes after refold). This appears therefore only when having quotes (aka not simple names, and not when being unicode encoded). To avoid that issue when formataddr would return more than 78 chars we return a simplified name/email to try to stay under 78 chars. If not possible we return only the email and skip the formataddr which causes the issue in python. We do not use hacks like crop the name part as encoding and quoting would be error prone. """ # address itself is too long for 78 chars limit: return only email if len(record_email) >= 78: return record_email company_name = self.env.company.name # try company_name + record_name, or record_name alone (or company_name alone) name = f"{company_name} {record_name}" if record_name else company_name formatted_email = tools.formataddr((name, record_email)) if len(formatted_email) > 78: formatted_email = tools.formataddr((record_name or company_name, record_email)) if len(formatted_email) > 78: formatted_email = record_email return formatted_email
def test_notify_reply_to_computation_mc(self): """ Test reply-to computation in multi company mode. Add notably tests depending on user company_id / company_ids. """ # Test1: no company_id field test_record = self.env['mail.test.gateway'].browse( self.test_record.ids) res = test_record._notify_get_reply_to() self.assertEqual( res[test_record.id], formataddr( ("%s %s" % (self.user_employee_c2.company_id.name, test_record.name), "%s@%s" % (self.alias_catchall, self.alias_domain)))) # Test2: company_id field, MC environment self.user_employee_c2.write( {'company_ids': [(4, self.user_employee.company_id.id)]}) test_records = self.env['mail.test.multi.company'].create([ { 'name': 'Test', 'company_id': self.user_employee.company_id.id }, { 'name': 'Test', 'company_id': self.user_employee_c2.company_id.id }, ]) res = test_records._notify_get_reply_to() for test_record in test_records: self.assertEqual( res[test_record.id], formataddr( ("%s %s" % (self.user_employee_c2.company_id.name, test_record.name), "%s@%s" % (self.alias_catchall, self.alias_domain))))
def test_mail_message_values_document_manual_alias(self): test_record = self.env['mail.test.simple'].create({ 'name': 'Test', 'email_from': '*****@*****.**' }) alias = self.env['mail.alias'].create({ 'alias_name': 'MegaLias', 'alias_user_id': False, 'alias_model_id': self.env['ir.model']._get('mail.test.simple').id, 'alias_parent_model_id': self.env['ir.model']._get('mail.test.simple').id, 'alias_parent_thread_id': test_record.id, }) msg = self.Message.create({ 'model': 'mail.test.simple', 'res_id': test_record.id }) self.assertIn('-openerp-%d-mail.test.simple' % test_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.user.company_id.name, test_record.name) reply_to_email = '%s@%s' % (alias.alias_name, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email)))
def test_channel_blacklisted_recipients(self): """ Posting a message on a channel should send one email to all recipients, except the blacklisted ones """ test_channel = self.env['mail.channel'].create({ 'name': 'Test', 'description': 'Description', 'alias_name': 'test', 'public': 'public', 'email_send': True, }) test_partner = self.env['res.partner'].create({ 'name': 'Test Partner', 'email': '*****@*****.**', }) blacklisted_partner = self.env['res.partner'].create({ 'name': 'Blacklisted Partner', 'email': '*****@*****.**', }) # Set Blacklist self.env['mail.blacklist'].create({ 'email': '*****@*****.**', }) test_channel._action_add_members(test_partner + blacklisted_partner) with self.mock_mail_gateway(): test_channel.message_post(body="Test", message_type='comment', subtype_xmlid='mail.mt_comment') self.assertEqual(len(self._mails), 1, 'Number of mail incorrect. Should be equal to 1.') for email in self._mails: self.assertEqual( set(email['email_to']), set([formataddr((test_partner.name, test_partner.email))]), 'email_to incorrect. Should be equal to "%s"' % ( formataddr((test_partner.name, test_partner.email))))
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))) 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(len(self._mails), 0, 'No notification / bounce should be sent')
def test_mail_message_values_document_alias(self): msg = self.Message.create({ 'model': 'mail.test', 'res_id': self.alias_record.id }) self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.user.company_id.name, self.alias_record.name) reply_to_email = '%s@%s' % (self.alias_record.alias_name, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual( msg.email_from, '"%s" <%s>' % (self.user_employee.name, self.user_employee.email)) # no alias domain -> author self.env['ir.config_parameter'].search([ ('key', '=', 'mail.catchall.domain') ]).unlink() msg = self.Message.create({ 'model': 'mail.test', 'res_id': self.alias_record.id }) self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) self.assertEqual( msg.reply_to, formataddr((self.user_employee.name, self.user_employee.email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) # no catchall -> don't care, alias self.env['ir.config_parameter'].set_param('mail.catchall.domain', self.alias_domain) self.env['ir.config_parameter'].search([ ('key', '=', 'mail.catchall.alias') ]).unlink() msg = self.Message.create({ 'model': 'mail.test', 'res_id': self.alias_record.id }) self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.company.name, self.alias_record.name) reply_to_email = '%s@%s' % (self.alias_record.alias_name, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual( msg.email_from, formataddr((self.user_employee.name, self.user_employee.email)))
def test_mail_message_values_fromto_long_name(self): """ Long headers may break in python if above 78 chars as folding is not done correctly (see ``_notify_get_reply_to_formatted_email`` docstring + commit linked to this test). """ # name would make it blow up: keep only email test_record = self.env['mail.test.container'].browse(self.alias_record.ids) test_record.write({ 'name': 'Super Long Name That People May Enter "Even with an internal quoting of stuff"' }) msg = self.env['mail.message'].create({ 'model': test_record._name, 'res_id': test_record.id }) reply_to_email = f"{test_record.alias_name}@{self.alias_domain}" self.assertEqual(msg.reply_to, reply_to_email, 'Reply-To: use only email when formataddr > 78 chars') # name + company_name would make it blow up: keep record_name in formatting test_record.write({'name': 'Name that would be more than 78 with company name'}) msg = self.env['mail.message'].create({ 'model': test_record._name, 'res_id': test_record.id }) self.assertEqual(msg.reply_to, formataddr((test_record.name, reply_to_email)), 'Reply-To: use recordname as name in format if recordname + company > 78 chars') # no record_name: keep company_name in formatting if ok test_record.write({'name': ''}) msg = self.env['mail.message'].create({ 'model': test_record._name, 'res_id': test_record.id }) self.assertEqual(msg.reply_to, formataddr((self.env.user.company_id.name, reply_to_email)), 'Reply-To: use company as name in format when no record name and still < 78 chars') # no record_name and company_name make it blow up: keep only email self.env.user.company_id.write({'name': 'Super Long Name That People May Enter "Even with an internal quoting of stuff"'}) msg = self.env['mail.message'].create({ 'model': test_record._name, 'res_id': test_record.id }) self.assertEqual(msg.reply_to, reply_to_email, 'Reply-To: use only email when formataddr > 78 chars') # whatever the record and company names, email is too long: keep only email test_record.write({ 'alias_name': 'Waaaay too long alias name that should make any reply-to blow the 78 characters limit', 'name': 'Short', }) self.env.user.company_id.write({'name': 'Comp'}) sanitized_alias_name = 'waaaay-too-long-alias-name-that-should-make-any-reply-to-blow-the-78-characters-limit' msg = self.env['mail.message'].create({ 'model': test_record._name, 'res_id': test_record.id }) self.assertEqual(msg.reply_to, f"{sanitized_alias_name}@{self.alias_domain}", 'Reply-To: even a long email is ok as only formataddr is problematic')
def assertSentEmail(self, author, recipients, **values): """ Tool method to ease the check of send emails. :param author: email author, either a string (email), either a partner record; :param recipients: list of recipients, each being either a string (email), either a partner record; :param values: dictionary of additional values to check email content; """ base_expected = {} for fname in ['reply_to', 'subject', 'attachments', 'body', 'references', 'body_content', 'body_alternative_content', 'references_content']: if fname in values: base_expected[fname] = values[fname] expected = dict(base_expected) if isinstance(author, self.env['res.partner'].__class__): expected['email_from'] = formataddr((author.name, author.email)) else: expected['email_from'] = author email_to_list = [] for email_to in recipients: if isinstance(email_to, self.env['res.partner'].__class__): email_to_list.append(formataddr((email_to.name, email_to.email))) else: email_to_list.append(email_to) expected['email_to'] = email_to_list sent_mail = next( (mail for mail in self._mails if set(mail['email_to']) == set(expected['email_to']) and mail['email_from'] == expected['email_from'] ), False) debug_info = '-'.join('From: %s-To: %s' % (mail['email_from'], mail['email_to']) for mail in self._mails) if not bool(sent_mail) else '' self.assertTrue(bool(sent_mail), 'Expected mail from %s to %s not found in %s' % (expected['email_from'], expected['email_to'], debug_info)) for val in ['reply_to', 'subject', 'references', 'attachments']: if val in expected: self.assertEqual(expected[val], sent_mail[val], 'Value for %s: expected %s, received %s' % (val, expected[val], sent_mail[val])) if 'attachments_info' in values: attachments = sent_mail['attachments'] for attachment_info in values['attachments_info']: attachment = next(attach for attach in attachments if attach[0] == attachment_info['name']) if attachment_info.get('raw'): self.assertEqual(attachment[1], attachment_info['raw']) if attachment_info.get('type'): self.assertEqual(attachment[2], attachment_info['type']) self.assertEqual(len(values['attachments_info']), len(attachments)) for val in ['body']: if val in expected: self.assertHtmlEqual(expected[val], sent_mail[val], 'Value for %s: expected %s, received %s' % (val, expected[val], sent_mail[val])) for val in ['body_content', 'body_alternative', 'references_content']: if val in expected: self.assertIn(expected[val], sent_mail[val[:-8]], 'Value for %s: %s does not contain %s' % (val, sent_mail[val[:-8]], expected[val]))
def test_channel_classic_recipients(self): """ Posting a message on a classic channel should work like classic post """ self.test_channel.write({'alias_name': False}) self.test_channel.message_subscribe([self.user_employee.partner_id.id, self.test_partner.id]) self.test_channel.message_post(body="Test", message_type='comment', subtype='mt_comment') sent_emails = self._mails self.assertEqual(len(sent_emails), 2) for email in sent_emails: self.assertIn( email['email_to'][0], [formataddr((self.user_employee.name, self.user_employee.email)), formataddr((self.test_partner.name, self.test_partner.email))])
def test_mail_group_notification_recipients_separated(self): # Remove alias, should trigger classic behavior of mail group self.group_private.write({'alias_name': False}) self.group_private.message_subscribe_users([self.user_employee.id, self.user_portal.id]) self.group_private.message_post(body="Test", message_type='comment', subtype='mt_comment') sent_emails = self._mails self.assertEqual(len(sent_emails), 2) for email in sent_emails: self.assertIn( email['email_to'][0], [formataddr((self.user_employee.name, self.user_employee.email)), formataddr((self.user_portal.name, self.user_portal.email))])
def test_mail_message_values_document_no_alias(self): test_record = self.env['mail.test.simple'].create({'name': 'Test', 'email_from': '*****@*****.**'}) msg = self.Message.create({ 'model': 'mail.test.simple', 'res_id': test_record.id }) self.assertIn('-openerp-%d-mail.test.simple' % test_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.user.company_id.name, test_record.name) reply_to_email = '%s@%s' % (self.alias_catchall, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual(msg.email_from, formataddr((self.user_employee.name, self.user_employee.email)))
def _compute_email_formatted(self): for partner in self: if partner.email: partner.email_formatted = tools.formataddr( (partner.name or u"False", partner.email or u"False")) else: partner.email_formatted = ''
def test_post_notify(self): self.user_employee.write({'notification_type': 'inbox'}) with self.mock_mail_gateway(): new_notification = self.test_record.message_notify( subject='This should be a subject', body='<p>You have received a notification</p>', partner_ids=[self.partner_1.id, self.partner_admin.id, self.user_employee.partner_id.id], ) self.assertEqual(new_notification.subtype_id, self.env.ref('mail.mt_note')) self.assertEqual(new_notification.message_type, 'user_notification') self.assertEqual(new_notification.body, '<p>You have received a notification</p>') self.assertEqual(new_notification.author_id, self.env.user.partner_id) self.assertEqual(new_notification.email_from, formataddr((self.env.user.name, self.env.user.email))) self.assertEqual(new_notification.notified_partner_ids, self.partner_1 | self.user_employee.partner_id | self.partner_admin) self.assertNotIn(new_notification, self.test_record.message_ids) admin_mails = [x for x in self._mails if self.partner_admin.name in x.get('email_to')[0]] self.assertEqual(len(admin_mails), 1, 'There should be exactly one email sent to admin') admin_mail = admin_mails[0].get('body') admin_access_link = admin_mail[admin_mail.index('model='):admin_mail.index('/>') - 1] if 'model=' in admin_mail else None self.assertIsNotNone(admin_access_link, 'The email sent to admin should contain an access link') self.assertIn('model=%s' % self.test_record._name, admin_access_link, 'The access link should contain a valid model argument') self.assertIn('res_id=%d' % self.test_record.id, admin_access_link, 'The access link should contain a valid res_id argument') partner_mails = [x for x in self._mails if self.partner_1.name in x.get('email_to')[0]] self.assertEqual(len(partner_mails), 1, 'There should be exactly one email sent to partner') partner_mail = partner_mails[0].get('body') self.assertNotIn('/mail/view?model=', partner_mail, 'The email sent to admin should not contain an access link')
def test_email_formataddr(self): email = '*****@*****.**' cases = [ # (name, address), charsets expected (('', email), ['ascii', 'utf-8'], '*****@*****.**'), (('joe', email), ['ascii', 'utf-8'], '"joe" <*****@*****.**>'), (('joe doe', email), ['ascii', 'utf-8'], '"joe doe" <*****@*****.**>'), (('joe"doe', email), ['ascii', 'utf-8'], '"joe\\"doe" <*****@*****.**>'), (('joé', email), ['ascii'], '=?utf-8?b?am/DqQ==?= <*****@*****.**>'), (('joé', email), ['utf-8'], '"joé" <*****@*****.**>'), (('', 'joé@example.com'), ['ascii', 'utf-8'], UnicodeEncodeError), # need SMTPUTF8 support (('', 'joe@examplé.com'), ['ascii', 'utf-8'], UnicodeEncodeError), # need IDNA support ] for pair, charsets, expected in cases: for charset in charsets: with self.subTest(pair=pair, charset=charset): if isinstance(expected, str): self.assertEqual(formataddr(pair, charset), expected) else: self.assertRaises(expected, formataddr, pair, charset)
def test_complex_mail_mail_send(self): message = self.env['mail.message'].sudo().create({ 'subject': 'Test', 'body': '<p>Test</p>', 'author_id': self.env.user.partner_id.id, 'email_from': self.env.user.partner_id.email, 'model': 'mail.test.container', 'res_id': self.container.id, }) mail = self.env['mail.mail'].sudo().create({ 'body_html': '<p>Test</p>', 'mail_message_id': message.id, 'recipient_ids': [(4, pid) for pid in self.partners.ids], }) mail_ids = mail.ids with self.assertQueryCount(__system__=7, emp=7): self.env['mail.mail'].sudo().browse(mail_ids).send() self.assertEqual(mail.body_html, '<p>Test</p>') self.assertEqual( mail.reply_to, formataddr(('%s %s' % (self.env.company.name, self.container.name), '*****@*****.**')))
def _compose_default_from(self, email=False): """ Compose email based on company setting and :param email: Char email address :return: formatted email (e.g. "Bob Doe via MyCompany <*****@*****.**>") """ # Check settings. # If not using company email fallback to original function if not email: return False user = self.env.user company = user.company_id if company.add_company_from: if company.add_company_mode == 'r': name_from = company.name else: if company.email_joint: name_from = '%s %s %s' % (user.name, company.email_joint, company.name) else: name_from = '%s %s' % (user.name, company.name) else: name_from = user.name return formataddr((name_from, email))
def _create_leads_batch(self, lead_type='lead', count=10, partner_ids=None, user_ids=None): """ Helper tool method creating a batch of leads, useful when dealing with batch processes. Please update me. :param string type: 'lead', 'opportunity', 'mixed' (lead then opp), None (depends on configuration); """ types = ['lead', 'opportunity'] leads_data = [{ 'name': 'TestLead_%02d' % (x), 'type': lead_type if lead_type else types[x % 2], 'priority': '%s' % (x % 3), } for x in range(count)] # customer information if partner_ids: for idx, lead_data in enumerate(leads_data): lead_data['partner_id'] = partner_ids[idx % len(partner_ids)] else: for idx, lead_data in enumerate(leads_data): lead_data['email_from'] = tools.formataddr(( 'TestCustomer_%02d' % (idx), '*****@*****.**' % (idx) )) # salesteam information if user_ids: for idx, lead_data in enumerate(leads_data): lead_data['user_id'] = user_ids[idx % len(user_ids)] return self.env['crm.lead'].create(leads_data)
def test_message_process_alias_followers_bounce(self): """ 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_thread_id': self.test_record.id, }) # Test: unknown on followers alias -> bounce record = self.format_and_process( MAIL_TEMPLATE, to='[email protected], [email protected]') self.assertEqual(len(record), 0, 'message_process: should have bounced') self.assertEqual( len(self._mails), 1, 'message_process: incoming email on Followers alias should send a bounce email' ) # 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') self.assertEqual( len(self._mails), 1, 'message_process: incoming email on Followers alias should send a bounce email' )
def test_move_composer_multi_form(self): with self.assertQueryCount(user_account=17): # acc: 15 / com 15 account_moves = self.env['account.move'].browse(self.test_account_moves.ids) default_ctx = account_moves.action_send_and_print()['context'] composer_form = Form(self.env['account.invoice.send'].with_context(default_ctx)) with self.mock_mail_gateway(mail_unlink_sent=True), \ self.mock_mail_app(), \ self.assertQueryCount(user_account=510): # acc: 509 / com 489 composer = composer_form.save() composer.send_and_print_action() self.assertEqual(len(self._new_mails), 10) for index, move in enumerate(self.test_account_moves): if move.partner_id.lang == 'es_ES': _exp_subject = 'SpanishSubject for %s' % move.name _exp_body_tip = '<p>SpanishBody for %s</p>' % move.name else: _exp_subject = '%s Invoice (Ref %s)' % (self.env.user.company_id.name, move.name) _exp_body_tip = 'Please remit payment at your earliest convenience' self.assertEqual(move.partner_id, self.test_customers[index]) self.assertSentEmail(self.user_account_other.email_formatted, move.partner_id, body_content=_exp_body_tip, subject=_exp_subject, reply_to=formataddr( ('%s %s' % (move.company_id.name, move.display_name), '%s@%s' % (self.alias_catchall, self.alias_domain)) ), )
def test_email_formataddr(self): email = '*****@*****.**' email_idna = 'joe@examplé.com' cases = [ # (name, address), charsets expected (('', email), ['ascii', 'utf-8'], '*****@*****.**'), (('joe', email), ['ascii', 'utf-8'], '"joe" <*****@*****.**>'), (('joe doe', email), ['ascii', 'utf-8'], '"joe doe" <*****@*****.**>'), (('joe"doe', email), ['ascii', 'utf-8'], '"joe\\"doe" <*****@*****.**>'), (('joé', email), ['ascii'], '=?utf-8?b?am/DqQ==?= <*****@*****.**>'), (('joé', email), ['utf-8'], '"joé" <*****@*****.**>'), (('', email_idna), ['ascii'], '*****@*****.**'), (('', email_idna), ['utf-8'], 'joe@examplé.com'), (('joé', email_idna), ['ascii'], '=?utf-8?b?am/DqQ==?= <*****@*****.**>'), (('joé', email_idna), ['utf-8'], '"joé" <joe@examplé.com>'), (('', 'joé@example.com'), ['ascii', 'utf-8'], 'joé@example.com'), ] for pair, charsets, expected in cases: for charset in charsets: with self.subTest(pair=pair, charset=charset): self.assertEqual(formataddr(pair, charset), expected)
def test_message_track_template(self): """ Update some tracked fields linked to some template -> message with onchange """ self.record.write({'mail_template': self.env.ref('test_mail.mail_test_full_tracking_tpl').id}) self.assertEqual(self.record.message_ids, self.env['mail.message']) self.record.write({ 'name': 'Test2', 'customer_id': self.user_admin.partner_id.id, }) self.assertEqual(len(self.record.message_ids), 2, 'should have 2 new messages: one for tracking, one for template') # one new message containing the template linked to tracking self.assertEqual(self.record.message_ids[0].subject, 'Test Template') self.assertEqual(self.record.message_ids[0].body, '<p>Hello Test2</p>') # one email send due to template self.assertEqual(len(self._mails), 1) self.assertEqual(set(self._mails[0]['email_to']), set([formataddr((self.user_admin.name, self.user_admin.email))])) self.assertHtmlEqual(self._mails[0]['body'], '<p>Hello Test2</p>') # one new message containing tracking; without subtype linked to tracking self.assertEqual(self.record.message_ids[1].subtype_id, self.env.ref('mail.mt_note')) self.assertTracking( self.record.message_ids[1], [('customer_id', 'many2one', False, self.user_admin.partner_id) # onchange tracked field ])
def test_notify_from_user_id(self): """ Test notify coming from user_id assignment. """ test_record = self.env['mail.test.track'].create({ 'company_id': self.env.user.company_id.id, 'email_from': self.env.user.email_formatted, 'name': 'Test UserId Track', 'user_id': False, }) self.flush_tracking() with self.mock_mail_gateway(), self.mock_mail_app(): test_record.write({'user_id': self.user_employee_2.id}) self.flush_tracking() self.assertEqual(len(self._new_msgs), 2, 'Should have 2 messages: tracking and assignment') assign_notif = self._new_msgs.filtered(lambda msg: msg.message_type == 'user_notification') self.assertTrue(assign_notif) self.assertMessageFields( assign_notif, {'author_id': self.partner_employee, 'email_from': formataddr((self.partner_employee.name, self.partner_employee.email_normalized)), 'model': test_record._name, 'notified_partner_ids': self.partner_employee_2, 'res_id': test_record.id, 'subtype_id': self.env.ref('mail.mt_note'), } ) self.assertIn('Dear %s' % self.partner_employee_2.name, assign_notif.body)
def test_notify_from_user_id_batch(self): """ Test notify coming from user_id assignment. """ test_records, _ = self._create_records_for_batch( 'mail.test.track', 10, { 'company_id': self.env.user.company_id.id, 'email_from': self.env.user.email_formatted, 'user_id': False, } ) test_records = self.env['mail.test.track'].browse(test_records.ids) self.flush_tracking() with self.mock_mail_gateway(), self.mock_mail_app(): test_records.write({'user_id': self.user_employee_2.id}) self.flush_tracking() self.assertEqual(len(self._new_msgs), 20, 'Should have 20 messages: 10 tracking and 10 assignments') for test_record in test_records: assign_notif = self._new_msgs.filtered(lambda msg: msg.message_type == 'user_notification' and msg.res_id == test_record.id) self.assertTrue(assign_notif) self.assertMessageFields( assign_notif, {'author_id': self.partner_employee, 'email_from': formataddr((self.partner_employee.name, self.partner_employee.email_normalized)), 'model': test_record._name, 'notified_partner_ids': self.partner_employee_2, 'res_id': test_record.id, 'subtype_id': self.env.ref('mail.mt_note'), } )
def _get_default_from(self): """ Check settings and use company's email if forced. Make 'From:' look like 'John Smith via Your Company <*****@*****.**> """ # Check settings. # If not using company email fallback to original function user = self.env.user company = user.company_id if not company.use_company_email: if user.email: return formataddr((user.name, user.email)) raise UserError( _("Unable to send email, please configure the sender's email address." )) if company.email: res = self._compose_default_from(company.email) if res: return res raise UserError( _("Unable to send email, please configure company email address."))
def test_post_flow(self): channel = self.env['mail.channel'].browse(self.channel.ids) msg_admin = channel.message_post(message_type='email', subtype_xmlid='mail.mt_comment', author_id=self.partner_admin.id) msg_moderator = channel.message_post( message_type='comment', subtype_xmlid='mail.mt_comment', author_id=self.partner_employee.id) msg_email1 = channel.message_post(message_type='comment', subtype_xmlid='mail.mt_comment', email_from=formataddr( ("MyName", "*****@*****.**"))) msg_email2 = channel.message_post(message_type='email', subtype_xmlid='mail.mt_comment', email_from="*****@*****.**") msg_notif = channel.message_post() messages = self.env['mail.message'].search([ ('model', '=', 'mail.channel'), ('res_id', '=', channel.id) ]) pending_messages = messages.filtered( lambda m: m.moderation_status == 'pending_moderation') accepted_messages = messages.filtered( lambda m: m.moderation_status == 'accepted') self.assertFalse(msg_email1) self.assertEqual(msg_admin, pending_messages) self.assertEqual(accepted_messages, msg_moderator | msg_email2 | msg_notif) self.assertFalse(msg_admin.channel_ids) self.assertEqual(msg_email2.channel_ids, channel)
def _create_new_message(self, channel_id, status='pending_moderation', author=None, body='', message_type="email"): author = author if author else self.env.user.partner_id message = self.env['mail.message'].create({ 'model': 'mail.channel', 'res_id': channel_id, 'message_type': 'email', 'body': body, 'moderation_status': status, 'author_id': author.id, 'email_from': formataddr((author.name, author.email)), 'subtype_id': self.env['mail.message.subtype'].search([('name', '=', 'Discussions')]).id }) return message
def test_message_process_alias_update(self): """ Incoming email update discussion + notification email """ self.alias.write({'alias_force_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='*****@*****.**', msg_id= '<*****@*****.**>', to='*****@*****.**>', subject='Re: cats') # Test: no new group + new message self.assertEqual( len(record), 0, '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')