Skip to content

Commit 29cd207

Browse files
committed
bpo-39259: smtp.SMTP/SMTP_SSL now reject timeout = 0
1 parent 100fafc commit 29cd207

File tree

5 files changed

+29
-7
lines changed

5 files changed

+29
-7
lines changed

Doc/library/smtplib.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions).
7070
.. versionadded:: 3.5
7171
The SMTPUTF8 extension (:rfc:`6531`) is now supported.
7272

73+
.. versionchanged:: 3.9
74+
If the *timeout* parameter is set to be zero, it will raise a
75+
:class:`ValueError` to prevent the creation of a non-blocking socket
7376

7477
.. class:: SMTP_SSL(host='', port=0, local_hostname=None, keyfile=None, \
7578
certfile=None [, timeout], context=None, \
@@ -108,6 +111,9 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions).
108111
:func:`ssl.create_default_context` select the system's trusted CA
109112
certificates for you.
110113

114+
.. versionchanged:: 3.9
115+
If the *timeout* parameter is set to be zero, it will raise a
116+
:class:`ValueError` to prevent the creation of a non-blocking socket
111117

112118
.. class:: LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None)
113119

Doc/whatsnew/3.9.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,13 @@ now raises :exc:`ImportError` instead of :exc:`ValueError` for invalid relative
248248
import attempts.
249249
(Contributed by Ngalim Siregar in :issue:`37444`.)
250250

251+
smtplib
252+
-------
253+
254+
:class:`~smtplib.SMTP` and :class:`~smtplib.SMTP_SSL` now raise a :class:`ValueError`
255+
if the given timeout for their constructor is zero to prevent the creation of
256+
a non-blocking socket. (Contributed by Dong-hee Na in :issue:`39259`.)
257+
251258
signal
252259
------
253260

Lib/smtplib.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ def _print_debug(self, *args):
303303
def _get_socket(self, host, port, timeout):
304304
# This makes it simpler for SMTP_SSL to use the SMTP connect code
305305
# and just alter the socket connection bit.
306+
if timeout is not None and not timeout:
307+
raise ValueError('Non-blocking socket (timeout=0) is not supported')
306308
if self.debuglevel > 0:
307309
self._print_debug('connect: to', (host, port), self.source_address)
308310
return socket.create_connection((host, port), timeout,
@@ -1030,13 +1032,12 @@ def __init__(self, host='', port=0, local_hostname=None,
10301032
keyfile=keyfile)
10311033
self.context = context
10321034
SMTP.__init__(self, host, port, local_hostname, timeout,
1033-
source_address)
1035+
source_address)
10341036

10351037
def _get_socket(self, host, port, timeout):
10361038
if self.debuglevel > 0:
10371039
self._print_debug('connect:', (host, port))
1038-
new_socket = socket.create_connection((host, port), timeout,
1039-
self.source_address)
1040+
new_socket = super()._get_socket(host, port, timeout)
10401041
new_socket = self.context.wrap_socket(new_socket,
10411042
server_hostname=self._host)
10421043
return new_socket
@@ -1065,15 +1066,15 @@ class LMTP(SMTP):
10651066
ehlo_msg = "lhlo"
10661067

10671068
def __init__(self, host='', port=LMTP_PORT, local_hostname=None,
1068-
source_address=None):
1069+
source_address=None):
10691070
"""Initialize a new instance."""
1070-
SMTP.__init__(self, host, port, local_hostname=local_hostname,
1071-
source_address=source_address)
1071+
super().__init__(host, port, local_hostname=local_hostname,
1072+
source_address=source_address)
10721073

10731074
def connect(self, host='localhost', port=0, source_address=None):
10741075
"""Connect to the LMTP daemon, on either a Unix or a TCP socket."""
10751076
if host[0] != '/':
1076-
return SMTP.connect(self, host, port, source_address=source_address)
1077+
return super().connect(host, port, source_address=source_address)
10771078

10781079
# Handle Unix-domain sockets.
10791080
try:

Lib/test/test_smtplib.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ def testTimeoutNone(self):
122122
self.assertIsNone(smtp.sock.gettimeout())
123123
smtp.close()
124124

125+
def testTimeoutZero(self):
126+
mock_socket.reply_with(b"220 Hola mundo")
127+
with self.assertRaises(ValueError):
128+
smtplib.SMTP(HOST, self.port, timeout=0)
129+
125130
def testTimeoutValue(self):
126131
mock_socket.reply_with(b"220 Hola mundo")
127132
smtp = smtplib.SMTP(HOST, self.port, timeout=30)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:class:`~smtplib.SMTP` and :class:`~smtplib.SMTP_SSL` now raise a
2+
:class:`ValueError` if the given timeout for their constructor is zero to
3+
prevent the creation of a non-blocking socket. Patch by Dong-hee Na.

0 commit comments

Comments
 (0)