SMTPLIB

smtplib SMTP Server Disconnected

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.

What causes smtplib.SMTPServerDisconnected?

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:

  • Wrong port/encryption pairing. Using 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.
  • Missing 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.
  • Idle timeout / firewall / security appliance. A connection held open too long can be reset, but the failure mode is broader than simple idling. Sentry's self-hosted project documents this exact error string, in one case traced to a socket timeout compounded by the mail relay demanding a client TLS certificate it wasn't configured to send — illustrating that "Connection unexpectedly closed" can stem from network or security-appliance behavior, not just app code.
  • Server-side limits. Sending too many messages on one connection, or hitting a provider connection cap, causes the remote end to disconnect.

How do I fix smtplib.SMTPServerDisconnected?

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 smtplib
from email.message import EmailMessage
msg = 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 STARTTLS
server.login("user", "app_password")
server.send_message(msg)

If the message is Connection unexpectedly closed:

  1. Match port and encryption. Use 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.
  2. Call ehlo() before and after starttls() as shown above.
  3. Open a fresh connection per send rather than holding one SMTP object open across long idle periods; set an explicit timeout= so hangs fail fast.
  4. Verify credentials/auth method. "Less Secure Apps" access ended May 30, 2022 for consumer Gmail accounts, and Google Workspace accounts lost the same access starting January 2025 — use an App Password (requires 2-Step Verification) or OAuth2, not your normal password.
  5. Check for IP/network blocks. If you're on a cloud host (AWS, GCP, etc.), the provider may drop connections from that IP range or block port 25 — confirm in your SMTP provider's docs and use 587/465 with authentication. Sending through a managed API (such as Courier or a transactional provider) sidesteps raw-socket disconnects entirely.

FAQ

Common questions

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

Stop debugging raw provider errors

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.