Convert email address to ASCII to support RFC6530

Python email library does not support non-ASCII emails so we convert email
addresses to ASCII version before passing them to sendmail.

Closes #10650
This commit is contained in:
Cédric Krier committed 2023-04-29 19:04:18 +02:00
1 parent 66f10aed84
commit 13cedb53e8
5 files changed
+37 -19

No files matched your search

+11 -4
View File
@@ -9,11 +9,18 @@ from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval
from trytond.report import get_email
from trytond.sendmail import SMTPDataManager, sendmail_transactional
from trytond.tools.email_ import set_from_header
from trytond.tools.email_ import convert_ascii_email, set_from_header
from trytond.transaction import Transaction
from trytond.wizard import StateTransition
def _formataddr(pair):
name, address = pair
if name:
name = str(Header(name, 'utf-8'))
return formataddr((name, convert_ascii_email(address)))
class Configuration(metaclass=PoolMeta):
__name__ = 'account.configuration'
@@ -117,12 +124,12 @@ class Dunning(metaclass=PoolMeta):
contact = self.party.contact_mechanism_get(
'email', usage=self.level.email_contact_mechanism)
if contact and contact.email:
name = str(Header(contact.name or self.party.rec_name))
to.append(formataddr((name, contact.email)))
name = contact.name or self.party.rec_name
to.append(_formataddr((name, contact.email)))
elif account_config.dunning_email_fallback:
user = account_config.get_multivalue(
'dunning_email_fallback', company=self.company.id)
to.append(formataddr((self.party.rec_name, user.email)))
to.append(_formataddr((self.party.rec_name, user.email)))
cc = []
bcc = []
languages = set()
@@ -32,7 +32,7 @@ from trytond.pyson import Eval, If, PYSONDecoder, TimeDelta
from trytond.report import Report
from trytond.sendmail import SMTPDataManager, sendmail_transactional
from trytond.tools import grouped_slice, reduce_ids
from trytond.tools.email_ import set_from_header
from trytond.tools.email_ import convert_ascii_email, set_from_header
from trytond.transaction import Transaction
from trytond.url import http_host
from trytond.wsgi import Base64Converter
@@ -55,7 +55,7 @@ logger = logging.getLogger(__name__)
def _formataddr(name, email):
if name:
name = str(Header(name, 'utf-8'))
return formataddr((name, email))
return formataddr((name, convert_ascii_email(email)))
class Scenario(Workflow, ModelSQL, ModelView):
+6 -4
View File
@@ -31,7 +31,7 @@ from trytond.pyson import Eval
from trytond.report import Report, get_email
from trytond.sendmail import SMTPDataManager, sendmail_transactional
from trytond.tools import grouped_slice, reduce_ids
from trytond.tools.email_ import set_from_header
from trytond.tools.email_ import convert_ascii_email, set_from_header
from trytond.transaction import Transaction, inactive_records
from trytond.url import http_host
from trytond.wizard import Button, StateTransition, StateView, Wizard
@@ -51,7 +51,7 @@ URL_OPEN = urljoin(URL_BASE, '/m/empty.gif')
def _formataddr(name, email):
if name:
name = str(Header(name, 'utf-8'))
return formataddr((name, email))
return formataddr((name, convert_ascii_email(email)))
def _add_params(url, **params):
@@ -297,7 +297,8 @@ class EmailList(DeactivableMixin, ModelSQL, ModelView):
set_from_header(msg, from_cfg, from_ or from_cfg)
msg['To'] = record.email
msg['Subject'] = Header(title, 'utf-8')
sendmail_transactional(from_cfg, [record.email], msg)
sendmail_transactional(
from_cfg, [convert_ascii_email(record.email)], msg)
def request_unsubscribe(self, email, from_=None):
pool = Pool()
@@ -322,7 +323,8 @@ class EmailList(DeactivableMixin, ModelSQL, ModelView):
set_from_header(msg, from_cfg, from_ or from_cfg)
msg['To'] = record.email
msg['Subject'] = Header(title, 'utf-8')
sendmail_transactional(from_cfg, [record.email], msg)
sendmail_transactional(
from_cfg, [convert_ascii_email(record.email)], msg)
class Message(Workflow, ModelSQL, ModelView):
+10 -5
View File
@@ -6,7 +6,7 @@ from email.header import Header
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.nonmultipart import MIMENonMultipart
from email.utils import formataddr, getaddresses, parseaddr
from email.utils import formataddr, getaddresses
from genshi.template import TextTemplate
@@ -17,7 +17,7 @@ from trytond.pool import Pool
from trytond.pyson import Eval, TimeDelta
from trytond.report import get_email
from trytond.sendmail import SMTPDataManager, sendmail_transactional
from trytond.tools.email_ import set_from_header
from trytond.tools.email_ import convert_ascii_email, set_from_header
from trytond.transaction import Transaction
from .exceptions import TemplateError
@@ -195,8 +195,12 @@ class Email(ModelSQL, ModelView):
msg = content
set_from_header(msg, sender, from_)
msg['To'] = ', '.join(formataddr(parseaddr(a)) for a in to)
msg['Cc'] = ', '.join(formataddr(parseaddr(a)) for a in cc)
msg['To'] = ', '.join(
formataddr((n, convert_ascii_email(a)))
for n, a in getaddresses(to))
msg['Cc'] = ', '.join(
formataddr((n, convert_ascii_email(a)))
for n, a in getaddresses(cc))
msg['Subject'] = Header(title, 'utf-8')
msg['Auto-Submitted'] = 'auto-generated'
return msg, title
@@ -238,7 +242,8 @@ class Email(ModelSQL, ModelView):
cc, cc_languages = self._get_cc(record)
bcc, bcc_languages = self._get_bcc(record)
languages = to_languages | cc_languages | bcc_languages
to_addrs = [e for _, e in getaddresses(to + cc + bcc)]
to_addrs = [
convert_ascii_email(e) for _, e in getaddresses(to + cc + bcc)]
if to_addrs:
msg, title = self.get_email(
record, from_, to, cc, bcc, languages)
+8 -4
View File
@@ -27,7 +27,7 @@ from trytond.report import Report
from trytond.rpc import RPC
from trytond.sendmail import sendmail_transactional
from trytond.tools import escape_wildcard
from trytond.tools.email_ import set_from_header
from trytond.tools.email_ import convert_ascii_email, set_from_header
from trytond.tools.string_ import StringMatcher
from trytond.transaction import Transaction
@@ -56,7 +56,7 @@ def _get_emails(value):
def _formataddr(pair):
"Format address without encoding"
name, address = pair
address.encode('ascii')
convert_ascii_email(address).encode('ascii')
if name:
quotes = ''
if specialsre.search(name):
@@ -167,8 +167,12 @@ class Email(ResourceAccessMixin, ModelSQL, ModelView):
msg = content
from_ = config.get('email', 'from')
set_from_header(msg, from_, user.email or from_)
msg['To'] = ', '.join(formataddr(a) for a in getaddresses([to]))
msg['Cc'] = ', '.join(formataddr(a) for a in getaddresses([cc]))
msg['To'] = ', '.join(
formataddr((n, convert_ascii_email(a)))
for n, a in getaddresses([to]))
msg['Cc'] = ', '.join(
formataddr((n, convert_ascii_email(a)))
for n, a in getaddresses([cc]))
msg['Subject'] = Header(subject, 'utf-8')
to_addrs = list(filter(None, map(