Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4634676

Browse files
committed
#7484: no more <> around addresses in VRFY or EXPN
The RFC doesn't say that they are allowed; apparently many mailers accept them, but not postfix. Contributions to this patch were made by Felipe Cruz and Catalin Iacob. The changeset also adds additional indirect tests for quoteaddr (null address and IDNA-encoded address).
1 parent ae4a78b commit 4634676

3 files changed

Lines changed: 36 additions & 11 deletions

File tree

Lib/smtplib.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ def quoteaddr(addr):
152152
else:
153153
return "<%s>" % m
154154

155+
def _addr_only(addrstring):
156+
displayname, addr = email.utils.parseaddr(addrstring)
157+
if (displayname, addr) == ('', ''):
158+
# parseaddr couldn't parse it, so use it as is.
159+
return addrstring
160+
return addr
161+
155162
# Legacy method kept for backward compatibility.
156163
def quotedata(data):
157164
"""Quote data for email.
@@ -514,14 +521,14 @@ def data(self, msg):
514521

515522
def verify(self, address):
516523
"""SMTP 'verify' command -- checks for address validity."""
517-
self.putcmd("vrfy", quoteaddr(address))
524+
self.putcmd("vrfy", _addr_only(address))
518525
return self.getreply()
519526
# a.k.a.
520527
vrfy = verify
521528

522529
def expn(self, address):
523530
"""SMTP 'expn' command -- expands a mailing list."""
524-
self.putcmd("expn", quoteaddr(address))
531+
self.putcmd("expn", _addr_only(address))
525532
return self.getreply()
526533

527534
# some useful methods

Lib/test/test_smtplib.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,23 @@ def testSendNeedingDotQuote(self):
293293
mexpect = '%s%s\n%s' % (MSG_BEGIN, m, MSG_END)
294294
self.assertEqual(self.output.getvalue(), mexpect)
295295

296+
def testSendNullSender(self):
297+
m = 'A test message'
298+
smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
299+
smtp.sendmail('<>', 'Sally', m)
300+
# XXX (see comment in testSend)
301+
time.sleep(0.01)
302+
smtp.quit()
303+
304+
self.client_evt.set()
305+
self.serv_evt.wait()
306+
self.output.flush()
307+
mexpect = '%s%s\n%s' % (MSG_BEGIN, m, MSG_END)
308+
self.assertEqual(self.output.getvalue(), mexpect)
309+
debugout = smtpd.DEBUGSTREAM.getvalue()
310+
sender = re.compile("^sender: <>$", re.MULTILINE)
311+
self.assertRegex(debugout, sender)
312+
296313
def testSendMessage(self):
297314
m = email.mime.text.MIMEText('A test message')
298315
smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
@@ -523,7 +540,7 @@ def testFailingHELO(self):
523540

524541

525542
sim_users = {'[email protected]':'John A',
526-
'Ms.B@somewhere.com':'Sally B',
543+
'Ms.B@xn--fo-fka.com':'Sally B',
527544
'[email protected]':'Ruth C',
528545
}
529546

@@ -539,7 +556,7 @@ def testFailingHELO(self):
539556
sim_auth_login_password = 'C29TZXBHC3N3B3JK'
540557

541558
sim_lists = {'list-1':['[email protected]','[email protected]'],
542-
'list-2':['Ms.B@somewhere.com',],
559+
'list-2':['Ms.B@xn--fo-fka.com',],
543560
}
544561

545562
# Simulated SMTP channel & server
@@ -560,15 +577,14 @@ def smtp_EHLO(self, arg):
560577
self.push(resp)
561578

562579
def smtp_VRFY(self, arg):
563-
raw_addr = email.utils.parseaddr(arg)[1]
564-
quoted_addr = smtplib.quoteaddr(arg)
565-
if raw_addr in sim_users:
566-
self.push('250 %s %s' % (sim_users[raw_addr], quoted_addr))
580+
# For max compatibility smtplib should be sending the raw address.
581+
if arg in sim_users:
582+
self.push('250 %s %s' % (sim_users[arg], smtplib.quoteaddr(arg)))
567583
else:
568584
self.push('550 No such user: %s' % arg)
569585

570586
def smtp_EXPN(self, arg):
571-
list_name = email.utils.parseaddr(arg)[1].lower()
587+
list_name = arg.lower()
572588
if list_name in sim_lists:
573589
user_list = sim_lists[list_name]
574590
for n, user_email in enumerate(user_list):
@@ -688,8 +704,7 @@ def testVRFY(self):
688704
self.assertEqual(smtp.vrfy(email), expected_known)
689705

690706
691-
expected_unknown = (550, ('No such user: %s'
692-
% smtplib.quoteaddr(u)).encode('ascii'))
707+
expected_unknown = (550, ('No such user: %s' % u).encode('ascii'))
693708
self.assertEqual(smtp.vrfy(u), expected_unknown)
694709
smtp.quit()
695710

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ Core and Builtins
3434
Library
3535
-------
3636

37+
- Issue #7484: smtplib no longer puts <> around addresses in VRFY and EXPN
38+
commands; they aren't required and in fact postfix doesn't support that form.
39+
3740
- Close the call queue in concurrent.futures.ProcessPoolExecutor when
3841
shutdown() is called, without waiting for the garbage collector to kick in.
3942

0 commit comments

Comments
 (0)