PHPMailer: SMTP Error: Could not authenticate.
That is not the error. It is PHPMailer’s summary of one.
PHPMailer reports its own summary and does not print what the server said. The server’s line is available, but only if debug output is switched on.
This matters because the summary is the same regardless of cause, and the server’s line is not. One of them tells you whether you have days or minutes.
The line the server actually sent
Authentication unsuccessful, basic authentication is disabled
Microsoft 365 refused username-and-password authentication. The credentials are almost certainly fine — the authentication method is switched off. Retyping the password, generating a new one, or recreating the mailbox will not change anything.
Everything about this error — what causes it, which of the causes are still reversible, and how long each one has.
How to make PHPMailer show it
Do this before changing any setting. A guess costs an hour; the server’s own sentence costs one line.
Set $mail->SMTPDebug = 2; before send() and the transcript shows the server’s own refusal, including the enhanced status code.
What to do once you can read it
The server’s line decides, not the library’s. Two cases, and they are not close:
- An admin, Security Defaults or a Conditional Access policy turned SMTP AUTH off. Reversible today, and it is a tenant setting, not a code change. Nothing in PHPMailer needs touching.
- It is the end-of-December-2026 default change. Switched off by default on existing tenants. An administrator can re-enable it, so this is a reprieve rather than a fix — and Microsoft announces the final removal date in the second half of 2027. If you do not administer the tenant, that reprieve is not yours to take.
Which one you are looking at is decided by the exact string, which is why getting it printed comes first.
If re-enabling it is not something you can do
ZeroSMTP is a free SMTP relay that accepts the credentials PHPMailer already sends. It is a host, a port and a username — no OAuth flow, no app registration, no code path that does not exist yet in the version you are running.
Working PHP example — the whole change is the connection settings.
Related
- The server error behind this one
- All library error messages
- All SMTP AUTH error messages
- What breaks at the end of December 2026
Your library prints something else? Send the exact string and what produced it. A message copied from a real failure is worth more than one transcribed from documentation.
Last reviewed 2026-08-27.
Updated 30 Aug 2026