Keywords: Python | SSL Error | smtplib | TLS Encryption | Port Configuration | Thread Safety
Abstract: This technical paper provides an in-depth analysis of the common ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] in Python programming, focusing on protocol differences between SMTP_SSL and SMTP+STARTTLS in the smtplib module. Through comparative analysis of SSL/TLS implementations on ports 465 and 587, the paper explains the root causes of port configuration errors and demonstrates correct TLS-encrypted email sending with complete code examples. The article also addresses extended scenarios including thread safety issues and OpenSSL version compatibility, offering developers a comprehensive SSL error troubleshooting guide.
Technical Background of SSL Version Number Errors
In Python network programming, ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1056) is a common cryptographic protocol error. This error typically occurs when there is a mismatch during SSL/TLS protocol version negotiation between client and server. From a technical perspective, SSL (Secure Sockets Layer) and TLS (Transport Layer Security) are both encryption protocols designed to secure network communications, but they exhibit significant differences in protocol versions and implementation details.
SSL and TLS Implementation Differences in SMTP Protocol
In the Simple Mail Transfer Protocol (SMTP), encrypted connections are primarily implemented in two ways:
SMTP_SSL Connection Method: This approach initiates SSL encryption handshake immediately after establishing TCP connection. The standard implementation uses port 465, with entire communication occurring within the SSL encrypted channel. Its workflow can be summarized as: Establish TCP connection → Immediate SSL handshake → Encrypted communication.
SMTP+STARTTLS Connection Method: This method first establishes a plaintext TCP connection, then upgrades to TLS encryption through the STARTTLS command. The standard implementation uses port 587, with communication process divided into two phases: Establish TCP connection → Send STARTTLS command → TLS handshake → Encrypted communication.
Error Code Analysis and Solution
The critical error in the original problem code lies in port configuration:
server = smtplib.SMTP_SSL('smtp.mail.com', 587)
This code attempts to establish an SMTP_SSL connection on port 587, but port 587 is typically configured to support STARTTLS upgrade rather than immediate SSL. This protocol-port mismatch causes the SSL version negotiation error.
The correct solution is to adopt the SMTP+STARTTLS approach:
import smtplib, ssl
port = 587 # STARTTLS standard port
smtp_server = "smtp.gmail.com"
sender_email = "my@gmail.com"
receiver_email = "your@gmail.com"
password = input("Type your password and press enter:")
message = """\
Subject: Hi there
This message is sent from Python."""
context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
server.ehlo() # Send EHLO command to identify client capabilities
server.starttls(context=context) # Upgrade to TLS encryption
server.ehlo() # Re-identify capabilities in encrypted channel
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message)
Detailed SSL Context Configuration
In TLS connections, proper SSL context configuration is crucial:
context = ssl.create_default_context()
This method creates a default SSL context containing system-trusted Certificate Authority (CA) certificates, recommended protocol versions, and cipher suites. In Python 3.4 and later versions, this is the recommended approach for creating secure SSL connections.
Extended Scenarios: Thread Safety and OpenSSL Compatibility
The thread-related SSL errors mentioned in the reference article reveal another important dimension. In multi-threaded environments, HTTP client libraries (such as httplib2) may not be thread-safe. When multiple threads share the same connection object, SSL protocol state confusion may occur, leading to version number errors.
The solution is to create separate connection instances for each thread:
import threading
import shotgun_api3
def worker_thread(thread_id):
# Each thread uses independent Shotgun instance
sg = shotgun_api3.Shotgun(base_url, script_name=script_name, api_key=api_key)
try:
result = sg.find_one('Episode', [['code', 'is', 'F_FaceOnly']])
print(f"Thread {thread_id}: {result}")
except ssl.SSLError as e:
print(f"Thread {thread_id} SSL error: {e}")
threads = []
for i in range(5):
thread = threading.Thread(target=worker_thread, args=(i,))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
Protocol Version Compatibility Considerations
The evolution of SSL/TLS protocol versions is also a significant factor contributing to version number errors. As TLS 1.0 and 1.1 are gradually being deprecated, modern servers typically require TLS 1.2 or higher versions. If clients are configured with outdated protocol versions, version negotiation failures may occur.
Such issues can be avoided through explicit protocol version configuration:
import ssl
context = ssl.create_default_context()
context.options |= ssl.OP_NO_SSLv2 # Disable SSLv2
context.options |= ssl.OP_NO_SSLv3 # Disable SSLv3
context.options |= ssl.OP_NO_TLSv1 # Disable TLSv1 (optional)
context.options |= ssl.OP_NO_TLSv1_1 # Disable TLSv1.1 (optional)
Debugging and Troubleshooting Recommendations
When encountering SSL version number errors, a systematic debugging approach is recommended:
- Verify Port Configuration: Confirm that the used port matches the protocol type (465 for SMTP_SSL, 587 for SMTP+STARTTLS)
- Check Server Support: Use telnet or openssl s_client to test server-supported protocols
- Update Dependencies: Ensure that the Python version and OpenSSL libraries are up-to-date
- Enable Verbose Logging: Configure SSL debug output to obtain more detailed error information
By understanding how SSL/TLS protocols work and correctly configuring connection parameters, developers can effectively prevent and resolve SSL version number errors, ensuring the security and reliability of network communications.