]> granicus.if.org Git - python/commitdiff
#7484: no more <> around addresses in VRFY or EXPN
authorR David Murray <rdmurray@bitdance.com>
Tue, 19 Jul 2011 01:38:54 +0000 (21:38 -0400)
committerR David Murray <rdmurray@bitdance.com>
Tue, 19 Jul 2011 01:38:54 +0000 (21:38 -0400)
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).

Lib/smtplib.py
Lib/test/test_smtplib.py
Misc/NEWS

index 9080e4ae57096eb3767e2e62050a94de86fbe955..7b97a6a88ffdad828a98390b923db37b1b7a5385 100644 (file)
@@ -152,6 +152,13 @@ def quoteaddr(addr):
     else:
         return "<%s>" % m
 
+def _addr_only(addrstring):
+    displayname, addr = email.utils.parseaddr(addrstring)
+    if (displayname, addr) == ('', ''):
+        # parseaddr couldn't parse it, so use it as is.
+        return addrstring
+    return addr
+
 # Legacy method kept for backward compatibility.
 def quotedata(data):
     """Quote data for email.
@@ -514,14 +521,14 @@ class SMTP:
 
     def verify(self, address):
         """SMTP 'verify' command -- checks for address validity."""
-        self.putcmd("vrfy", quoteaddr(address))
+        self.putcmd("vrfy", _addr_only(address))
         return self.getreply()
     # a.k.a.
     vrfy = verify
 
     def expn(self, address):
         """SMTP 'expn' command -- expands a mailing list."""
-        self.putcmd("expn", quoteaddr(address))
+        self.putcmd("expn", _addr_only(address))
         return self.getreply()
 
     # some useful methods
index bacfbdfe51419eb3d84afc29b5071afaa025b0cf..d94c88e8bec002e71d4eeecd0037ad7d3e8e3d9e 100644 (file)
@@ -293,6 +293,23 @@ class DebuggingServerTests(unittest.TestCase):
         mexpect = '%s%s\n%s' % (MSG_BEGIN, m, MSG_END)
         self.assertEqual(self.output.getvalue(), mexpect)
 
+    def testSendNullSender(self):
+        m = 'A test message'
+        smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
+        smtp.sendmail('<>', 'Sally', m)
+        # XXX (see comment in testSend)
+        time.sleep(0.01)
+        smtp.quit()
+
+        self.client_evt.set()
+        self.serv_evt.wait()
+        self.output.flush()
+        mexpect = '%s%s\n%s' % (MSG_BEGIN, m, MSG_END)
+        self.assertEqual(self.output.getvalue(), mexpect)
+        debugout = smtpd.DEBUGSTREAM.getvalue()
+        sender = re.compile("^sender: <>$", re.MULTILINE)
+        self.assertRegex(debugout, sender)
+
     def testSendMessage(self):
         m = email.mime.text.MIMEText('A test message')
         smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
@@ -523,7 +540,7 @@ class BadHELOServerTests(unittest.TestCase):
 
 
 sim_users = {'Mr.A@somewhere.com':'John A',
-             'Ms.B@somewhere.com':'Sally B',
+             'Ms.B@xn--fo-fka.com':'Sally B',
              'Mrs.C@somewhereesle.com':'Ruth C',
             }
 
@@ -539,7 +556,7 @@ sim_auth_credentials = {
 sim_auth_login_password = 'C29TZXBHC3N3B3JK'
 
 sim_lists = {'list-1':['Mr.A@somewhere.com','Mrs.C@somewhereesle.com'],
-             'list-2':['Ms.B@somewhere.com',],
+             'list-2':['Ms.B@xn--fo-fka.com',],
             }
 
 # Simulated SMTP channel & server
@@ -560,15 +577,14 @@ class SimSMTPChannel(smtpd.SMTPChannel):
         self.push(resp)
 
     def smtp_VRFY(self, arg):
-        raw_addr = email.utils.parseaddr(arg)[1]
-        quoted_addr = smtplib.quoteaddr(arg)
-        if raw_addr in sim_users:
-            self.push('250 %s %s' % (sim_users[raw_addr], quoted_addr))
+        # For max compatibility smtplib should be sending the raw address.
+        if arg in sim_users:
+            self.push('250 %s %s' % (sim_users[arg], smtplib.quoteaddr(arg)))
         else:
             self.push('550 No such user: %s' % arg)
 
     def smtp_EXPN(self, arg):
-        list_name = email.utils.parseaddr(arg)[1].lower()
+        list_name = arg.lower()
         if list_name in sim_lists:
             user_list = sim_lists[list_name]
             for n, user_email in enumerate(user_list):
@@ -688,8 +704,7 @@ class SMTPSimTests(unittest.TestCase):
             self.assertEqual(smtp.vrfy(email), expected_known)
 
         u = 'nobody@nowhere.com'
-        expected_unknown = (550, ('No such user: %s'
-                                       % smtplib.quoteaddr(u)).encode('ascii'))
+        expected_unknown = (550, ('No such user: %s' % u).encode('ascii'))
         self.assertEqual(smtp.vrfy(u), expected_unknown)
         smtp.quit()
 
index f444709ab50a1b710d88d96b58a1fb22b800d521..3325966477ebe79f80c7bd75da141eefbcc1c76d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -34,6 +34,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #7484: smtplib no longer puts <> around addresses in VRFY and EXPN
+  commands; they aren't required and in fact postfix doesn't support that form.
+
 - Close the call queue in concurrent.futures.ProcessPoolExecutor when
   shutdown() is called, without waiting for the garbage collector to kick in.