SMTPLIB
Why Python raises "module 'smtplib' has no attribute 'SMTP'" — a local smtplib.py/email.py shadowing the stdlib — and the exact rename-and-clear-cache fix.
Updated Jul 1, 2026
The short answer
"module 'smtplib' has no attribute 'SMTP'" is a Python AttributeError, not an SMTP server reply. It almost always means a local file or package named smtplib.py (or email.py) is shadowing the standard library, so import smtplib loads your incomplete file. Fix it by renaming that file, deleting its __pycache__/.pyc, and confirming smtplib.__file__ points to the stdlib.
This is a Python error, not an SMTP server response. The 3-digit SMTP reply codes in RFC 5321 (and the enhanced codes in RFC 3463) come from a mail server; this AttributeError is raised by the Python interpreter before any network connection is made. So nothing here is a deliverability, auth, or TLS problem — it's a module-resolution problem in your own project.
Python's smtplib standard-library module exposes SMTP, SMTP_SSL, and LMTP classes (Python docs). If smtplib.SMTP suddenly "doesn't exist," Python is almost certainly importing the wrong smtplib — yours, not the standard library's.
The usual trigger is name shadowing. When you run import smtplib, the interpreter searches built-in modules, then the current directory, then the rest of sys.path. If you have a file named smtplib.py (or a package folder smtplib/) sitting next to your script, your file wins the lookup. Your file doesn't define an SMTP class, so smtplib.SMTP(...) fails.
A file named email.py breaks the import differently: because stdlib smtplib does import email.utils internally, a local email.py shadow makes Python fail while importing smtplib itself, raising ModuleNotFoundError: No module named 'email.utils'; 'email' is not a package — not the AttributeError this page is about, but the same root cause (a shadowing file) and the same fix.
A stale compiled cache is sometimes blamed for this sticking around after a fix, but in practice it's rarely the culprit: once you rename or delete the shadowing file, Python resolves smtplib back to the standard library on the next run.
import smtplibprint(smtplib.__file__)
If it prints a path inside your project (e.g. /your/project/smtplib.py) instead of your Python install's .../lib/python3.x/smtplib.py, that file is the culprit. email.py and smtp.py shadow things the same way.
Rename it to something that isn't a standard-library name, e.g. mailer.py or send_email.py, and update any imports that referenced the old name.
As a safety measure, clear any stale bytecode, though in practice renaming/deleting the shadowing file alone is normally sufficient — CPython will not keep resolving to a deleted module's stale bytecode under the fixed name:
find . -name '__pycache__' -type d -prune -exec rm -rf {} +find . -name '*.pyc' -delete
smtplib.__file__ should now point at the standard library, and smtplib.SMTP("smtp.example.com", 587) will resolve.If you can't find a shadowing file, run dir(smtplib) — if SMTP is missing from the list, you're still importing the wrong module; if it's present, recheck your line for a typo such as lowercase smtplib.smtp (the class is uppercase SMTP).
import smtplibfrom email.message import EmailMessagemsg = EmailMessage()msg["From"] = "you@example.com"msg["To"] = "user@example.com"msg["Subject"] = "Hello"msg.set_content("Sent from Python")with smtplib.SMTP("smtp.example.com", 587) as server:server.starttls()server.login("you@example.com", "your-app-password")server.send_message(msg)
Port 587 (STARTTLS) and 465 (implicit TLS via smtplib.SMTP_SSL) are both valid per RFC 8314. For Gmail, authenticate with an App Password (requires 2-Step Verification) or OAuth2 — Google removed Less Secure Apps access for personal Google accounts in May 2022. Google Workspace accounts followed a separate, later timeline, with basic-auth/LSA access fully cut off by May 1, 2025. None of this matters, though, until the import resolves to the real smtplib.
References
FAQ
No. It is a Python AttributeError raised by the interpreter, not a 3-digit SMTP reply from a mail server. It happens before any connection is made, so RFC 5321/3463 reply codes don't apply. It almost always means a local smtplib.py file is shadowing the standard library.
One API, every provider
Courier connects to your email, SMS, and push providers, handles retries and failover, and surfaces delivery errors in plain language.
Last reviewed Jul 1, 2026. Courier is not affiliated with third-party providers; error behavior may vary by implementation.
© 2026 Courier. All rights reserved.