Common causes
- Wrong username or password; many hosts require the full email address as the username
- Gmail/Google Workspace accounts with 2-Step Verification need an App Password; the normal account password is rejected
- Microsoft 365 has SMTP AUTH disabled for the tenant or mailbox, or is phasing out basic authentication
- Credentials loaded from .env or config are empty or have stray quotes or spaces
- Mismatched encryption and port (SMTPSecure ssl with 587, or tls with 465), causing authentication to fail or fall back
- The mailbox was locked or its password changed, or the provider blocked logins from the server's IP
How to fix it
- Turn on SMTP debug output. Set $mail->SMTPDebug = SMTP::DEBUG_SERVER; temporarily and read the server's response after AUTH. The 535 code and text tell you which cause applies. Turn it off afterwards, as the log can expose details.
- Verify credentials. Log in to webmail with the same username and password. Use the full email address as Username and check that environment variables are actually loaded (var_dump(getenv('SMTP_USER')) on a test page, then remove it).
- Use an App Password for Gmail. Enable 2-Step Verification on the Google account, create an App Password under Security, and use it as $mail->Password. 'Less secure app access' no longer exists.
- Check Microsoft 365 SMTP AUTH. If you see 5.7.139, an admin must enable Authenticated SMTP for that mailbox in the Microsoft 365 admin center. Microsoft is retiring basic auth for SMTP AUTH, so plan for OAuth2 (PHPMailer supports XOAUTH2) or a relay service.
- Match port and encryption. Use port 587 with PHPMailer::ENCRYPTION_STARTTLS or port 465 with PHPMailer::ENCRYPTION_SMTPS. On cPanel hosts, use the mail server name shown in Email Accounts > Connect Devices.
- Contact the provider if credentials are right. If webmail login works but SMTP fails, the provider may be blocking the server IP or require a different host. Ask for the correct SMTP settings for scripts.
PHP (PHPMailer 6)
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->SMTPAuth = true;
$mail->Username = '[email protected]'; // full address
$mail->Password = getenv('SMTP_PASSWORD'); // never hard-code
$mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
// $mail->SMTPDebug = PHPMailer\PHPMailer\SMTP::DEBUG_SERVER; // temporary How to stop it happening again
- Store SMTP credentials in environment variables or a config file outside the web root
- Use a dedicated mailbox or transactional email service for website mail
- Monitor failed sends so a password change or policy change is noticed quickly