If the session got as far as AUTH, your network is fine. DNS resolved, the port opened, TLS negotiated, and the server evaluated a credential and said no. That narrows the problem enormously — and it means changing firewall rules, ports or timeouts will not help. Work through the five causes below in order.
Step 1 — Confirm the Session Actually Reaches AUTH
Before assuming a credentials problem, prove where the session stops. Open the conversation by hand and watch it:
# Connect and upgrade to TLS in one step, then type EHLO at the prompt
openssl s_client -connect smtp.example.com:587 -starttls smtp -crlf
# At the prompt:
EHLO test.example.orgYou are looking for a 250-AUTH line in the response. If the session never gets this far — no banner, no capability list — you have a connection problem, not an authentication one, and timeouts and refused connections is the guide you want instead.
Step 2 — Check Whether the Provider Still Accepts Your Password
This is the single most common cause, and the error message never says so. Once two-factor authentication is enabled, most large providers stop accepting the account password over SMTP entirely. The server returns the same 535 it would for a typo, because from its point of view the credential simply is not valid.
| Provider | What SMTP accepts | Notes |
|---|---|---|
| Gmail / Google Workspace | App password, or OAuth (XOAUTH2) | App passwords require 2FA to be on first |
| Microsoft 365 / Outlook | OAuth, or app password where still permitted | Basic auth for SMTP is disabled on most tenants |
| Yahoo / AOL | App password only | The account password is rejected outright |
| iCloud | App-specific password | Generated per application |
| SendGrid / Mailgun / Postmark | API key as the password | The username is fixed — often literally apikey |
Step 3 — Match the Username Format the Server Expects
Servers differ on what the username is, and a mismatch produces the same rejection as a wrong password. Three formats are in common use:
- Full email address —
alice@example.com. The default for hosted providers, and the safest guess. - Local part only —
alice. Common on self-hosted Postfix and Dovecot setups where the mailbox is a system account. - A fixed literal — relay services often want a constant such as
apikeywith the real secret in the password field.
Also check for the invisible problems: a trailing space or newline pasted from a config file, an unescaped $ or ! in a shell-quoted password, and stale credentials cached by the mail client from a previous configuration.
Step 4 — Offer a Mechanism the Server Will Accept
The post-STARTTLS EHLO lists exactly what the server will take. If your client offers something else, you get 534 rather than 535, and no password change will fix it.
250-smtp.example.com
250-STARTTLS
250-AUTH PLAIN LOGIN XOAUTH2
250-SIZE 35882577
250 8BITMIME| Mechanism | What it sends | When to use it |
|---|---|---|
PLAIN | Username and password, base64, in one line | Default choice inside TLS |
LOGIN | The same, in two prompted steps | Older servers that do not offer PLAIN |
CRAM-MD5 | A challenge-response hash, never the password | Legacy setups; requires a plain-text password store server-side |
XOAUTH2 | A short-lived OAuth access token | Google and Microsoft; mandatory on many tenants |
Step 5 — Authenticate on the Submission Port, After TLS
Two ordering mistakes account for most of the remaining failures, and both produce errors that look like credential problems:
- Authenticating on port 25. Port 25 is server-to-server transport. Many servers do not advertise
AUTHon it at all, and the ones that do often refuse it. Move the client to587(STARTTLS) or465(implicit TLS). - Sending AUTH before STARTTLS. Servers routinely hide the
AUTHcapability until the connection is encrypted. A client that authenticates on the firstEHLOgets530 5.7.0— "authentication required" — which reads as a credentials error but is a sequencing one.
// Nodemailer — 587 upgrades via STARTTLS, so secure stays false
const transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
secure: false, // true only for port 465 (implicit TLS)
requireTLS: true, // refuse to send if STARTTLS is unavailable
auth: {
user: 'alice@example.com',
pass: process.env.SMTP_APP_PASSWORD,
},
});
await transporter.verify(); // fails fast on an auth problemThe equivalent trap in Python is passing an SMTP_SSL connection to port 587, or a plain SMTP connection to 465. Use SMTP plus starttls() on 587, and SMTP_SSL on 465:
import smtplib
with smtplib.SMTP('smtp.example.com', 587) as s:
s.ehlo()
s.starttls() # upgrade first
s.ehlo() # re-issue: AUTH appears only now
s.login(user, app_password)Step 6 — Check Sender Permissions, Not Just Credentials
Authentication can succeed and the message still be refused a moment later, at MAIL FROM. The credential was valid; the account is simply not permitted to send as that address. The reply is usually 550 5.7.1 rather than 535, which is the clue that you have moved past authentication.
- The envelope sender is an alias the authenticated account does not own — grant send-as rights, or send from the account's own address.
- A relay service requires the sending domain or address to be verified before it will accept mail for it.
- The account is authorised for the domain but the specific mailbox in
MAIL FROMdoes not exist.
If the rejection names relaying rather than the sender, 550 5.7.1 relaying denied covers that case specifically.
Quick Reference
| Symptom | Most likely cause | Fix |
|---|---|---|
535 5.7.8 with a known-good password | 2FA is on; the account password is no longer valid for SMTP | Generate an app password or move to OAuth |
534 5.7.9 | Mechanism refused | Offer a mechanism from the 250-AUTH list |
530 5.7.0 | AUTH attempted before STARTTLS, or not attempted | Upgrade TLS, re-issue EHLO, then authenticate |
454 4.7.0 | Auth backend temporarily unavailable | Retry with backoff; do not change credentials |
No AUTH in the capability list | Still on the plain connection, or on port 25 | Use 587/465 and check the post-TLS EHLO |
AUTH succeeds, MAIL FROM rejected | Sender not permitted for this account | Verify the domain or grant send-as rights |
| Works locally, fails in production | Credential truncated or unescaped in the deployed config | Print the length, not the value, on both hosts |
Frequently Asked Questions
1. My password is definitely correct. Why does AUTH still fail?
On Google, Microsoft and most other large providers, your account password is not a valid SMTP credential once two-factor authentication is on. You need an app password or an OAuth token instead. The server cannot tell you that — it only knows the credential was rejected — so it returns the same 535 it returns for a genuine typo.
2. What is the difference between 535 and 534?
535 5.7.8 means the credential was evaluated and rejected. 534 5.7.9 means the mechanism is not acceptable — the server wants a stronger or different method than the one you offered, commonly OAuth where you tried LOGIN. The first is a credentials problem; the second is a configuration problem, and swapping passwords will not help.
3. Why does AUTH not appear in the EHLO response?
Usually because you are still on the plain connection. Most servers only advertise AUTH after STARTTLS, so the first EHLO legitimately omits it and the second one — issued after the TLS upgrade — includes it. If it is missing from the post-TLS EHLO too, you are on port 25, which is transport rather than submission and does not accept authentication.
4. Can a firewall cause an authentication error?
No. A blocked port produces a timeout or a refused connection, and the session never reaches the AUTH step, so the credentials are never evaluated. If you are seeing a 535, connectivity is already proven. Connection-level failures are a separate problem with entirely different fixes.
5. Do I need to base64-encode my credentials myself?
Only when testing by hand. AUTH PLAIN and AUTH LOGIN transmit base64, and every mail library does that encoding for you. Base64 is an encoding, not encryption — which is why authentication must happen inside TLS, and why a credential sent over a plain connection should be treated as disclosed.
6. How do I confirm which auth mechanisms my server offers?
Run the host through the SMTP Test and read the capability list from the post-STARTTLS EHLO — the 250-AUTH line names every mechanism the server will accept. By hand, openssl s_client -connect host:587 -starttls smtp -crlf then EHLO test shows the same list.