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())