From 571e4a23792f70d5fbfde25df287d9b8576bb054 Mon Sep 17 00:00:00 2001 Message-Id: <571e4a23792f70d5fbfde25df287d9b8576bb054.1449961061.git.wking@tremily.us> From: "W. Trevor King" Date: Sat, 12 Dec 2015 14:51:24 -0800 Subject: [PATCH] smtplib: Set SMTP._host in .connect() With the previous code, starttls uses ._host when calling wrap_socket, but ._host is only setup in SMTP.__init__. Before #22921 [3] starttls would ignore ._host when SNI wasn't available locally. But as far as I can tell, starttls has never used _host when connection happens via an explicit .connect() call. This leads to errors like [4]: >>> smtp = smtplib.SMTP() >>> smtp.connect(host="smtp.gmail.com", port=587) >>> smtp.ehlo() >>> smtp.starttls() File "smtp_test.py", line 10, in smtp.starttls() File "/usr/lib/python3.4/smtplib.py", line 676, in starttls server_hostname=server_hostname) File "/usr/lib/python3.4/ssl.py", line 344, in wrap_socket _context=self) File "/usr/lib/python3.4/ssl.py", line 540, in __init__ self.do_handshake() File "/usr/lib/python3.4/ssl.py", line 767, in do_handshake self._sslobj.do_handshake() ssl.SSLError: [SSL: TLSV1_ALERT_DECODE_ERROR] tlsv1 alert decode error (_ssl.c:598) This commit moves the _host saving to .connect(), so both: SMTP(host=...) (which calls .connect(host=...) internally) and: smtp = SMTP() ... smtp.connect(host=...) will support starttls. We don't need to set a dummy ._host in __init__, because the auto-ehlo will notice the lack-of-socket before getting to the ._host access: >>> import smtplib >>> smtp = smtplib.SMTP() >>> smtp.starttls() Traceback (most recent call last): File "", line 1, in File "/usr/lib64/python3.4/smtplib.py", line 671, in starttls self.ehlo_or_helo_if_needed() File "/usr/lib64/python3.4/smtplib.py", line 569, in ehlo_or_helo_if_needed if not (200 <= self.ehlo()[0] <= 299): File "/usr/lib64/python3.4/smtplib.py", line 423, in ehlo self.putcmd(self.ehlo_msg, name or self.local_hostname) File "/usr/lib64/python3.4/smtplib.py", line 349, in putcmd self.send(str) File "/usr/lib64/python3.4/smtplib.py", line 341, in send raise SMTPServerDisconnected('please run connect() first') smtplib.SMTPServerDisconnected: please run connect() first [1]: https://hg.python.org/cpython/file/323c10701e5d/Lib/smtplib.py#l766 [2]: https://hg.python.org/cpython/file/323c10701e5d/Lib/smtplib.py#l244 [3]: http://bugs.python.org/issue22921 [4]: http://stackoverflow.com/questions/23616803/smtplib-smtp-starttls-fails-with-tlsv1-alert-decode-error [5]: https://hg.python.org/cpython/file/323c10701e5d/Lib/smtplib.py#l251 --- Lib/smtplib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 4756973..fb83ec4 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -241,7 +241,6 @@ class SMTP: will be used. """ - self._host = host self.timeout = timeout self.esmtp_features = {} self.command_encoding = 'ascii' @@ -316,6 +315,7 @@ class SMTP: specified during instantiation. """ + self._host = host if source_address: self.source_address = source_address -- 2.1.0.60.g85f0837