Skip to content

Commit 988a2b8

Browse files
committed
Added explicit charset setting and consistent encoding to several email paths through the datatracker. After introducing support for non-ascii names in email addresses, using role.formatted_email() to insert names into email content doesn't work any more, since uncode names will now be rfc2047-encoded in formatted_email(). Added another method role.name_and_email() for this case. Replaced another case of '%s <%s>' name-and-email formatting with formataddr(). Fixed some tests which did not send unicode email bodies to the email functions. Fixes issue ietf-tools#2017.
- Legacy-Id: 12896
1 parent c889856 commit 988a2b8

10 files changed

Lines changed: 35 additions & 16 deletions

File tree

ietf/doc/mails.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ def email_iana(request, doc, to, msg, cc=None):
369369
# fix up message and send it with extra info on doc in headers
370370
import email
371371
parsed_msg = email.message_from_string(msg.encode("utf-8"))
372+
parsed_msg.set_charset('UTF-8')
372373

373374
extra = {}
374375
extra["Reply-To"] = "noreply@ietf.org"
@@ -377,7 +378,7 @@ def email_iana(request, doc, to, msg, cc=None):
377378

378379
send_mail_text(request, to,
379380
parsed_msg["From"], parsed_msg["Subject"],
380-
parsed_msg.get_payload(),
381+
parsed_msg.get_payload().decode(str(parsed_msg.get_charset())),
381382
extra=extra,
382383
cc=cc)
383384

ietf/doc/utils_charter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
from django.template.loader import render_to_string
66
from django.utils.encoding import smart_text
77

8+
import debug # pyflakes:ignore
9+
810
from ietf.doc.models import NewRevisionDocEvent, WriteupDocEvent
911
from ietf.group.models import ChangeStateGroupEvent
1012
from ietf.name.models import GroupStateName

ietf/group/models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,13 @@ class Role(models.Model):
257257
def __unicode__(self):
258258
return u"%s is %s in %s" % (self.person.plain_name(), self.name.name, self.group.acronym or self.group.name)
259259

260+
def name_and_email(self):
261+
"Returns name and email, e.g.: u'Ano Nymous <ano@nymous.org>' "
262+
if self.person:
263+
return u"%s <%s>" % (self.person.plain_name(), self.email.address)
264+
else:
265+
return u"<%s>" % self.address
266+
260267
def formatted_ascii_email(self):
261268
return email.utils.formataddr((self.person.plain_ascii(), self.email.address))
262269

ietf/group/views_edit.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,10 +324,10 @@ def diff(attr, name):
324324
added = set(new) - set(old)
325325
deleted = set(old) - set(new)
326326
if added:
327-
change_text=title + ' added: ' + ", ".join(x.formatted_email() for x in added)
327+
change_text=title + ' added: ' + ", ".join(x.name_and_email() for x in added)
328328
personnel_change_text+=change_text+"\n"
329329
if deleted:
330-
change_text=title + ' deleted: ' + ", ".join(x.formatted_email() for x in deleted)
330+
change_text=title + ' deleted: ' + ", ".join(x.name_and_email() for x in deleted)
331331
personnel_change_text+=change_text+"\n"
332332
changed_personnel.update(set(old)^set(new))
333333

ietf/mailtrigger/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def gather_submission_confirmers(self, **kwargs):
216216
if doc.stream_id and doc.stream_id not in ['ietf']:
217217
addrs.extend(Recipient.objects.get(slug='stream_managers').gather(**{'streams':[doc.stream_id]}))
218218
else:
219-
addrs.extend([u"%s <%s>" % (author["name"], author["email"]) for author in submission.authors_parsed() if author["email"]])
219+
addrs.extend([formataddr((author["name"], author["email"])) for author in submission.authors_parsed() if author["email"]])
220220
if submission.submitter_parsed()["email"]:
221221
addrs.append(submission.submitter)
222222
return addrs

ietf/message/tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def test_send_plain_announcement(self):
4545
frm="testmonkey@example.com",
4646
cc="cc.a@example.com, cc.b@example.com",
4747
bcc="bcc@example.com",
48-
body="Hello World!",
48+
body=u"Hello World!",
4949
content_type="",
5050
)
5151

@@ -73,7 +73,7 @@ def test_send_mime_announcement(self):
7373
frm="testmonkey@example.com",
7474
cc="cc.a@example.com, cc.b@example.com",
7575
bcc="bcc@example.com",
76-
body='--NextPart\r\n\r\nA New Internet-Draft is available from the on-line Internet-Drafts directories.\r\n--NextPart\r\nContent-Type: Message/External-body;\r\n\tname="draft-huang-behave-bih-01.txt";\r\n\tsite="ftp.ietf.org";\r\n\taccess-type="anon-ftp";\r\n\tdirectory="internet-drafts"\r\n\r\nContent-Type: text/plain\r\nContent-ID: <2010-07-30001541.I-D@ietf.org>\r\n\r\n--NextPart--',
76+
body=u'--NextPart\r\n\r\nA New Internet-Draft is available from the on-line Internet-Drafts directories.\r\n--NextPart\r\nContent-Type: Message/External-body;\r\n\tname="draft-huang-behave-bih-01.txt";\r\n\tsite="ftp.ietf.org";\r\n\taccess-type="anon-ftp";\r\n\tdirectory="internet-drafts"\r\n\r\nContent-Type: text/plain\r\nContent-ID: <2010-07-30001541.I-D@ietf.org>\r\n\r\n--NextPart--',
7777
content_type='Multipart/Mixed; Boundary="NextPart"',
7878
)
7979

ietf/person/models.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,18 @@ def formatted_ascii_email(self):
243243
else:
244244
return self.address
245245

246+
def name_and_email(self):
247+
"Returns name and email, e.g.: u'Ano Nymous <ano@nymous.org>' "
248+
if self.person:
249+
return u"%s <%s>" % (self.person.plain_name(), self.address)
250+
else:
251+
return u"<%s>" % self.address
252+
246253
def formatted_email(self):
254+
"""
255+
Similar to name_and_email(), but with email header-field
256+
encoded words (RFC 2047) and quotes as needed.
257+
"""
247258
if self.person:
248259
return formataddr((self.person.plain_name(), self.address))
249260
else:

ietf/person/tests.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from ietf.person.factories import EmailFactory,PersonFactory
1212
from ietf.person.models import Person
1313
from ietf.utils.test_data import make_test_data
14-
from ietf.utils.test_utils import TestCase, unicontent
14+
from ietf.utils.test_utils import TestCase
1515
from ietf.utils.mail import outbox, empty_outbox
1616

1717

@@ -41,8 +41,7 @@ def test_profile(self):
4141

4242
url = urlreverse("ietf.person.views.profile", kwargs={ "email_or_name": person.plain_name()})
4343
r = self.client.get(url)
44-
self.assertEqual(r.status_code, 200)
45-
self.assertIn(person.photo_name(), unicontent(r))
44+
self.assertContains(r, person.photo_name(), status_code=200)
4645
q = PyQuery(r.content)
4746
self.assertIn("Photo of %s"%person, q("div.bio-text img.bio-photo").attr("alt"))
4847

ietf/utils/mail.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,8 @@ def send_mail(request, to, frm, subject, template, context, *args, **kwargs):
183183
return send_mail_text(request, to, frm, subject, txt, *args, **kwargs)
184184

185185
def encode_message(txt):
186-
if isinstance(txt, unicode):
187-
msg = MIMEText(txt.encode('utf-8'), 'plain', 'UTF-8')
188-
else:
189-
msg = MIMEText(txt)
190-
return msg
186+
assert isinstance(txt, unicode)
187+
return MIMEText(txt.encode('utf-8'), 'plain', 'UTF-8')
191188

192189
def send_mail_text(request, to, frm, subject, txt, cc=None, extra=None, toUser=False, bcc=None):
193190
"""Send plain text message."""
@@ -307,6 +304,7 @@ def send_mail_mime(request, to, frm, subject, msg, cc=None, extra=None, toUser=F
307304
def parse_preformatted(preformatted, extra={}, override={}):
308305
"""Parse preformatted string containing mail with From:, To:, ...,"""
309306
msg = message_from_string(preformatted.encode("utf-8"))
307+
msg.set_charset('UTF-8')
310308

311309
for k, v in override.iteritems():
312310
if k in msg:
@@ -332,7 +330,8 @@ def send_mail_preformatted(request, preformatted, extra={}, override={}):
332330
extra headers as needed)."""
333331

334332
(msg,headers,bcc) = parse_preformatted(preformatted, extra, override)
335-
send_mail_text(request, msg['To'], msg["From"], msg["Subject"], msg.get_payload(), extra=headers, bcc=bcc)
333+
txt = msg.get_payload().decode(str(msg.get_charset()))
334+
send_mail_text(request, msg['To'], msg["From"], msg["Subject"], txt, extra=headers, bcc=bcc)
336335
return msg
337336

338337
def send_mail_message(request, message, extra={}):

ietf/utils/tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class TestSMTPServer(TestCase):
5252
def test_address_rejected(self):
5353

5454
def send_simple_mail(to):
55-
send_mail_text(None, to=to, frm=None, subject="Test for rejection", txt="dummy body")
55+
send_mail_text(None, to=to, frm=None, subject="Test for rejection", txt=u"dummy body")
5656

5757
len_before = len(outbox)
5858
send_simple_mail('good@example.com,poison@example.com')

0 commit comments

Comments
 (0)