Synchronous Access of SMTP
without Timeout
The smtplib.SMTP
, smtplib.SMTP_SSL
, and smtplib.LMTP
classes are used
to send emails via the Simple Mail Transfer Protocol (SMTP). These classes
can establish network connections to mail servers and by default do not
specify a timeout for network operations. If a timeout is not specified,
the connection may block indefinitely, leading to potential resource
exhaustion or application hang-ups, particularly in production environments
or network failure scenarios.
This rule enforces that a timeout parameter must be provided when
instantiating smtplib.SMTP
, smtplib.SMTP_SSL
, or smtplib.LMTP
to prevent
the possibility of indefinite blocking.
Failing to specify a timeout in these functions may cause the application to block indefinitely while waiting for a response from the mail server. This can lead to Denial of Service (DoS) vulnerabilities or cause the application to become unresponsive.
Example
import smtplib
import ssl
server = smtplib.SMTP("smtp.example.com", 587)
server.starttls(context=ssl.create_default_context())
Remediation
Always provide a timeout parameter when using smtplib.SMTP
,
smtplib.SMTP_SSL
, or smtplib.LMTP
. This ensures that if the mail server
is unreachable or unresponsive, the connection attempt will fail after a set
period, preventing indefinite blocking and resource exhaustion.
Alternatively, the global default timeout can be set via
socket.setdefaulttimeout()
. This is a good option to enforce a consistent
timeout for any network library that uses sockets, including smtplib
.
import smtplib
import ssl
server = smtplib.SMTP("smtp.example.com", 587, timeout=10)
server.starttls(context=ssl.create_default_context())
False Positives
In the case of a false positive the rule can be suppressed. Simply add a
trailing or preceding comment line with either the rule ID (PY040
) or
rule category name (no_timeout
).
- Using rule ID
- Using category name
import smtplib
import ssl
# suppress: PY040
server = smtplib.SMTP("smtp.example.com", 587)
server.starttls(context=ssl.create_default_context())
import smtplib
import ssl
# suppress: no_timeout
server = smtplib.SMTP("smtp.example.com", 587)
server.starttls(context=ssl.create_default_context())