SMTPLIB
smtplib.SMTPServerDisconnected fires when the connection drops or sendmail() is called before connecting. Fix the port, use starttls() correctly.
Updated Jul 1, 2026
The short answer
smtplib.SMTPServerDisconnected is a Python exception, not an SMTP reply code. The standard library raises it in two cases: the server unexpectedly closed the TCP connection (often "Connection unexpectedly closed"), or you called a method like sendmail() before connect()/login() ("please run connect() first"). Fix it by connecting on the right port, calling ehlo() around starttls(), and using a fresh SMTP object per send.
smtplib.SMTPServerDisconnected is a Python standard-library exception, not a numeric SMTP reply code. Per the smtplib docs, it "is raised when the server unexpectedly disconnects, or when an attempt is made to use the SMTP instance before connecting it to a server." The two messages you'll typically see are Connection unexpectedly closed and please run connect() first.
There are two fundamentally different triggers, and the message tells you which one you have:
1. please run connect() first — Your code called a method that needs a live session (sendmail(), login(), ehlo(), starttls()) before a connection existed, or after the connection was already closed (for example after quit(), or by reusing a stale SMTP object). This is a code-ordering bug, not a network problem.
2. Connection unexpectedly closed — The server (or something in between) dropped the TCP connection mid-conversation. Common real causes:
SMTP starttls() against an implicit-TLS port (465) — or SMTP_SSL against a STARTTLS port (587) — makes the server tear down the socket. Port 587 uses STARTTLS over a plaintext SMTP connection; port 465 uses implicit TLS via SMTP_SSL (RFC 8314). Port 25 is for server-to-server relay and is frequently blocked by cloud/ISP networks.ehlo() around STARTTLS. Per RFC 3207 and the smtplib docs, after starttls() you must call ehlo() again; skipping the EHLO handshake can cause the server to close the connection.If the message is please run connect() first: ensure you connect before you send, and don't reuse a closed object. Use a context manager so the lifecycle is correct:
import smtplibfrom email.message import EmailMessagemsg = EmailMessage()msg["From"] = "you@example.com"msg["To"] = "to@example.com"msg["Subject"] = "Test"msg.set_content("Hello")with smtplib.SMTP("smtp.example.com", 587, timeout=30) as server:server.ehlo()server.starttls()server.ehlo() # required again after STARTTLSserver.login("user", "app_password")server.send_message(msg)
If the message is Connection unexpectedly closed:
SMTP(host, 587) starttls(), or SMTP_SSL(host, 465) (implicit TLS, no starttls() call). Don't mix them. RFC 8314 actually favors implicit TLS (465) as the long-term direction, with STARTTLS (587) retained for transition/legacy-client compatibility — but as of today, neither is deprecated and 587 remains extremely common.ehlo() before and after starttls() as shown above.SMTP object open across long idle periods; set an explicit timeout= so hangs fail fast.References
FAQ
No. It is a Python smtplib exception class, not a 3-digit SMTP reply code from RFC 5321. It signals either an unexpectedly closed TCP connection or use of the SMTP object before connect().
One API, every provider
Courier connects to your email, SMS, and push providers, handles retries and failover, and surfaces delivery errors in plain language.
Reply-code definitions per RFC 3207. Last reviewed Jul 1, 2026. Courier is not affiliated with third-party providers; error behavior may vary by implementation.
© 2026 Courier. All rights reserved.