[IMP] various: use 'email_formatted' instead of 'formataddr'
PURPOSE Be defensive when dealing with email fields, notably when having multi-emails or email field containing an already-formatted email. SPECIFICATIONS When possible, use 'email_formatted' field on partner, instead of calling 'format_addr'. That way management of corner case input (multi emails and double encapsulation) is managed by the computed field itself. When 'format_addr' has to be used, ensure email part is normalized to avoid formatting issues. Also use tools to extract emails instead of 'email_re' regex when possible. That way all code extracting and managing emails go through the same stack. Task-2612945 (Mail: Defensive email formatting) X-original-commit: odoo/odoo@1c06014531 Part-of: odoo/odoo#134934
This commit is contained in:
@@ -17,7 +17,7 @@ from odoo.addons.phone_validation.tools import phone_validation
|
||||
from odoo.exceptions import UserError, AccessError
|
||||
from odoo.osv import expression
|
||||
from odoo.tools.translate import _
|
||||
from odoo.tools import date_utils, email_re, email_split, is_html_empty, groupby
|
||||
from odoo.tools import date_utils, email_split, is_html_empty, groupby
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
from . import crm_stage
|
||||
@@ -2046,14 +2046,27 @@ class Lead(models.Model):
|
||||
return super(Lead, self)._message_post_after_hook(message, msg_vals)
|
||||
|
||||
def _message_partner_info_from_emails(self, emails, link_mail=False):
|
||||
""" Try to propose a better recipient when having only an email by populating
|
||||
it with the partner_name / contact_name field of the lead e.g. if lead
|
||||
contact_name is "Raoul" and email is "raoul@raoul.fr", suggest
|
||||
"Raoul" <raoul@raoul.fr> as recipient. """
|
||||
result = super(Lead, self)._message_partner_info_from_emails(emails, link_mail=link_mail)
|
||||
for partner_info in result:
|
||||
if not partner_info.get('partner_id') and (self.partner_name or self.contact_name):
|
||||
emails = email_re.findall(partner_info['full_name'] or '')
|
||||
email = emails and emails[0] or ''
|
||||
if email and self.email_from and email.lower() == self.email_from.lower():
|
||||
partner_info['full_name'] = tools.formataddr((self.contact_name or self.partner_name, email))
|
||||
break
|
||||
for email, partner_info in zip(emails, result):
|
||||
if partner_info.get('partner_id') or not email or not (self.partner_name or self.contact_name):
|
||||
continue
|
||||
# reformat email if no name information
|
||||
name_emails = tools.email_split_tuples(email)
|
||||
name_from_email = name_emails[0][0] if name_emails else False
|
||||
if name_from_email:
|
||||
continue # already containing name + email
|
||||
name_from_email = self.partner_name or self.contact_name
|
||||
emails_normalized = tools.email_normalize_all(email)
|
||||
email_normalized = emails_normalized[0] if emails_normalized else False
|
||||
if email.lower() == self.email_from.lower() or (email_normalized and self.email_normalized == email_normalized):
|
||||
partner_info['full_name'] = tools.formataddr((
|
||||
name_from_email,
|
||||
','.join(emails_normalized) if emails_normalized else email))
|
||||
break
|
||||
return result
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -65,9 +65,9 @@ class NewLeadNotification(TestCrmCommon):
|
||||
'name': 'Format Name', 'user_id': self.user_sales_leads.id,
|
||||
'team_id': self.sales_team_1.id,
|
||||
}),
|
||||
(False, 'new.customer.multi.1@test.example.com, new.customer.2@test.example.com', None, 'Customer Email',
|
||||
(False, '"Multi Name" <new.customer.multi.1@test.example.com,new.customer.2@test.example.com>', None, 'Customer Email',
|
||||
{}), # no email_normalized -> no information
|
||||
(False, 'new.customer.simple@test.example.com', None, 'Customer Email',
|
||||
(False, '"Std Name" <new.customer.simple@test.example.com>', None, 'Customer Email',
|
||||
{'company_name': 'Std Name', 'email': 'new.customer.simple@test.example.com',
|
||||
'name': 'Std Name', 'user_id': self.user_sales_leads.id,
|
||||
'team_id': self.sales_team_1.id,
|
||||
@@ -147,7 +147,7 @@ class NewLeadNotification(TestCrmCommon):
|
||||
('Delivery Boy company', 'Test With Company', 'default_create_with_partner@example.com'),
|
||||
('Delivery Boy company', '', 'default_create_with_partner_no_name@example.com'),
|
||||
]:
|
||||
formatted_email = formataddr((name, email))
|
||||
formatted_email = formataddr((name, email)) if name else formataddr((partner_name, email))
|
||||
with self.subTest(partner_name=partner_name):
|
||||
lang = self.env['res.lang'].sudo().search([], limit=1)[0]
|
||||
description = '<p>Top</p>'
|
||||
|
||||
@@ -491,7 +491,7 @@ class Applicant(models.Model):
|
||||
if applicant.partner_id:
|
||||
applicant._message_add_suggested_recipient(recipients, partner=applicant.partner_id.sudo(), reason=_('Contact'))
|
||||
elif applicant.email_from:
|
||||
email_from = applicant.email_from
|
||||
email_from = tools.email_normalize(applicant.email_from)
|
||||
if applicant.partner_name:
|
||||
email_from = tools.formataddr((applicant.partner_name, email_from))
|
||||
applicant._message_add_suggested_recipient(recipients, email=email_from, reason=_('Contact Email'))
|
||||
|
||||
@@ -665,7 +665,7 @@ class MailThread(models.AbstractModel):
|
||||
'email_to': bounce_to,
|
||||
'auto_delete': True,
|
||||
}
|
||||
bounce_from = self.env['ir.mail_server']._get_default_bounce_address()
|
||||
bounce_from = tools.email_normalize(self.env['ir.mail_server']._get_default_bounce_address() or '')
|
||||
if bounce_from:
|
||||
bounce_mail_values['email_from'] = tools.formataddr(('MAILER-DAEMON', bounce_from))
|
||||
elif self.env['ir.config_parameter'].sudo().get_param("mail.catchall.alias") not in message['To']:
|
||||
@@ -1713,6 +1713,7 @@ class MailThread(models.AbstractModel):
|
||||
partner_id, partner_name<partner_email> or partner_name, lang,
|
||||
reason, create_values """
|
||||
self.ensure_one()
|
||||
partner_info = {}
|
||||
if email and not partner:
|
||||
# get partner info from email
|
||||
partner_info = self._message_partner_info_from_emails([email])[0]
|
||||
@@ -1727,11 +1728,11 @@ class MailThread(models.AbstractModel):
|
||||
if partner and partner.email: # complete profile: id, name <email>
|
||||
result[self.ids[0]].append((partner.id, partner.email_formatted, lang, reason, {}))
|
||||
elif partner: # incomplete profile: id, name
|
||||
result[self.ids[0]].append((partner.id, '%s' % (partner.name), lang, reason, {}))
|
||||
result[self.ids[0]].append((partner.id, partner.name, lang, reason, {}))
|
||||
else: # unknown partner, we are probably managing an email address
|
||||
_, parsed_email = self.env['res.partner']._parse_partner_name(email)
|
||||
partner_create_values = self._get_customer_information().get(parsed_email, {})
|
||||
result[self.ids[0]].append((False, email, lang, reason, partner_create_values))
|
||||
result[self.ids[0]].append((False, partner_info.get('full_name') or email, lang, reason, partner_create_values))
|
||||
return result
|
||||
|
||||
def _message_get_suggested_recipients(self):
|
||||
|
||||
@@ -15,8 +15,10 @@ class MailCCMixin(models.AbstractModel):
|
||||
'''return a dict of sanitize_email:raw_email from a string of cc'''
|
||||
if not cc_string:
|
||||
return {}
|
||||
return {tools.email_normalize(email): tools.formataddr((name, tools.email_normalize(email)))
|
||||
for (name, email) in tools.email_split_tuples(cc_string)}
|
||||
return {
|
||||
tools.email_normalize(email): tools.formataddr((name, tools.email_normalize(email)))
|
||||
for (name, email) in tools.email_split_tuples(cc_string)
|
||||
}
|
||||
|
||||
@api.model
|
||||
def message_new(self, msg_dict, custom_values=None):
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import formataddr
|
||||
|
||||
|
||||
class SaleOrderCancel(models.TransientModel):
|
||||
|
||||
@@ -121,7 +121,8 @@ class WebsiteEventBoothController(WebsiteEventController):
|
||||
|
||||
def _prepare_booth_registration_partner_values(self, event, kwargs):
|
||||
if request.env.user._is_public():
|
||||
contact_name_email = tools.formataddr((kwargs['contact_name'], kwargs['contact_email']))
|
||||
conctact_email_normalized = tools.email_normalize(kwargs['contact_email'])
|
||||
contact_name_email = tools.formataddr((kwargs['contact_name'], conctact_email_normalized))
|
||||
partner = request.env['res.partner'].sudo().find_or_create(contact_name_email)
|
||||
if not partner.name and kwargs.get('contact_name'):
|
||||
partner.name = kwargs['contact_name']
|
||||
|
||||
Reference in New Issue
Block a user