PHPMailer, SMTP and PHP Contact Form Email Debugger
Find whether your PHP email problem is caused by PHPMailer installation, autoloading, SMTP connection, port, TLS mode, credentials, Gmail app password, sender address, recipient rejection, contact-form logic, attachments, spam filtering or delivery configuration.
Use this tool when: PHPMailer cannot connect or authenticate, Composer classes are missing, Gmail rejects the password, a contact form reports success without sending, messages disappear or enter spam, attachments fail, or email works locally but not on hosting.
Describe Your PHP Email Problem
Use your PHPMailer error, SMTP transcript, provider settings and hosting clues to generate a focused debugging plan.
Likely email failure
Most Likely Root Causes
Fix in This Order
Connection and Authentication Checks
Sender and Delivery Checks
SMTP Configuration Compatibility
Stage-by-Stage Test Matrix
| Email stage | Assessment | Exact test |
|---|
Personalized PHPMailer Templates
Replace placeholders through private environment configuration. Never publish an SMTP password, Google app password, API key or recipient list inside a public GitHub repository or browser JavaScript.
Composer installation and PHPMailer SMTP template
Secure PHP contact-form handler
JSON/AJAX email endpoint
Safe attachment pattern
Temporary SMTP debugging pattern
Security and Abuse-Prevention Warnings
Email Test Cases
Viva-Ready Explanation
Copyable Debugging Report
How PHPMailer Sends an Email
A successful contact form involves more than calling
$mail->send(). PHP must load PHPMailer, connect to the
selected SMTP server, negotiate encryption, authenticate, submit the
sender and recipients, transfer the message and receive an SMTP
acceptance response. The receiving mail system then decides whether to
deliver, quarantine, reject or place the message in spam.
This creates several different meanings of “email not working.” A class loading failure happens before any network connection. A timeout occurs before authentication. A 535 error usually appears during authentication. A sender rejection happens after connection and often after authentication. A message that PHPMailer successfully submits but never reaches the inbox is usually a delivery or filtering problem, rather than the same problem as an SMTP connection failure.
Stage 1: Library loading
Composer’s autoloader or the required manual files must be available before the PHPMailer class and namespaces can be used.
Stage 2: Network connection
The server must resolve the SMTP hostname and reach the selected outbound port without a firewall or hosting restriction.
Stage 3: Encryption
The selected port and TLS mode must agree with the provider’s SMTP service.
Stage 4: Authentication
PHPMailer submits the configured SMTP username and credential using a method accepted by the provider.
Stage 5: Message acceptance
The SMTP server evaluates the From address, recipient, message size and provider sending policy.
Stage 6: Final delivery
The recipient system evaluates reputation, SPF, DKIM, DMARC, content, links and mailbox filtering.
PHPMailer Installation and Autoloading Errors
The recommended PHPMailer installation method is Composer. Composer installs the package and generates an autoloader that resolves the PHPMailer classes and their dependencies.
composer require phpmailer/phpmailer
The PHP file then loads the project autoloader:
require __DIR__ . "/vendor/autoload.php";
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
The relative path depends on where the executing PHP file is located.
Using __DIR__ prevents the path from changing merely
because the script was called from another working directory.
A manual installation requires the relevant source files and matching namespace imports. Copying one PHPMailer file from an old tutorial while using current namespace syntax can produce class-loading errors. Filename capitalization can also appear to work on Windows and fail on case-sensitive hosting.
Match the SMTP Port and Encryption Mode
| Common configuration | Connection behavior | PHPMailer setting |
|---|---|---|
| Port 587 | Connect normally, then upgrade the connection using STARTTLS. |
PHPMailer::ENCRYPTION_STARTTLS
|
| Port 465 | Begin with an encrypted SMTP connection. |
PHPMailer::ENCRYPTION_SMTPS
|
| Port 25 | Commonly used for server-to-server SMTP and frequently restricted by hosting or networks. | Provider-specific; do not assume it matches port 587. |
| Port 2525 | Alternative submission port offered by some SMTP providers. | Follow the provider’s documented encryption setting. |
A TLS “wrong version number” error frequently points to a disagreement between the port and connection mode. Disabling certificate validation may hide a local certificate problem but should not be treated as the permanent fix.
SMTP Connection Errors Are Not Password Errors
Authentication happens only after a network connection is established. When the transcript stops while opening the connection, changing the mailbox password is unlikely to solve the first failure.
| Error clue | Likely layer | First check |
|---|---|---|
| Connection timed out | Firewall, blocked port, routing or unreachable server | Test outbound access from the same server environment. |
| Connection refused | No accepting service, blocked port or wrong host/port | Verify the provider hostname and submission port. |
| Network is unreachable | Hosting or network routing restriction | Ask the hosting provider about outbound SMTP access. |
| Could not resolve host | DNS or hostname error | Remove protocols and check the exact SMTP hostname. |
| 535 authentication failed | Credential or authentication policy | Verify username format, credential type and account policy. |
| Must issue STARTTLS first | Encryption configuration | Use the provider’s STARTTLS submission configuration. |
Gmail Password and App-Password Errors
A normal Google account password may be rejected by an SMTP integration. Where an app password is available and appropriate, it requires 2-Step Verification and is separate from the normal account password. Some work, school, security-key-only or Advanced Protection configurations may not offer app passwords.
An app password should be stored like any other secret. It should not be placed in frontend JavaScript, published source code, screenshots or a public debugging report. Changing the Google account password may revoke existing app passwords, requiring a newly generated credential.
Do not “fix” a Gmail login problem by enabling an outdated less-secure-app setting from an old tutorial. Google account and Workspace policies have changed, so use a currently supported authentication method.
Use the Authenticated Mailbox as the Sender
A common contact-form mistake is using the visitor’s submitted address as the message’s From address. The SMTP provider may reject that sender, rewrite it or accept a message that later fails SPF or DMARC alignment.
Use the authenticated or verified mailbox as From:
$mail->setFrom(
"website@example.com",
"Website Contact Form"
);
Place the validated visitor address in Reply-To:
$mail->addReplyTo(
$visitorEmail,
$visitorName
);
This preserves the ability to reply to the visitor while keeping the actual sender aligned with the account authorized to transmit the message.
send() Success Does Not Guarantee Inbox Delivery
A successful PHPMailer send normally means that the SMTP server accepted the submitted message. It does not promise that the final recipient placed it in the inbox. The message may be delayed, quarantined, rejected later, bounced or classified as spam.
For accepted but missing messages, inspect:
- The spam, junk, quarantine and promotions folders.
- The provider’s activity or delivery log.
- Delayed bounce or rejection messages.
- The exact recipient spelling.
- Whether a different recipient provider receives the message.
- SPF, DKIM and DMARC configuration for a custom domain.
- Sender reputation and sending volume.
- Message content, links, attachments and misleading subject text.
The first test should be a small plain-text message with no attachment, shortened link or complex HTML. Add features one at a time after basic delivery is confirmed.
Why PHP mail() Can Return True Without Delivery
PHP’s mail() return value indicates whether the message was
accepted for handing off to the configured local mail system. It does
not prove final recipient delivery. XAMPP on a normal local Windows
machine does not automatically become a trusted internet mail server.
PHPMailer using authenticated SMTP is often easier to diagnose because
it provides connection, encryption, authentication and server-response
information. Simply changing from PHPMailer to mail() may
remove useful evidence without solving deliverability.
Use SMTP Debug Output Safely
PHPMailer debug output can show where the conversation stops. Level 2 is often enough to see client and server messages, while level 3 adds connection information. Low-level debugging should be temporary.
Do not display an SMTP transcript to public contact-form users. It can reveal hostnames, account identifiers, message metadata and operational details. Capture it privately during development and remove or disable it afterward.
SMTP debug output can also corrupt an AJAX JSON response or cause
output before a redirect header. Keep production
SMTPDebug at zero and log controlled technical details
privately.
Prevent Contact-Form Email Abuse
A public email form can be abused as a spam relay even when SMTP itself is configured correctly. The server must control the recipient, sender, subject structure and message format.
- Keep the destination recipient fixed on the server.
- Validate the visitor name and email.
- Limit message length.
- Reject header-breaking characters in short fields.
- Use CSRF protection where applicable.
- Add rate limiting and bot controls.
- Do not let visitors specify arbitrary CC or BCC recipients.
- Escape visitor content when building an HTML body.
- Log abuse signals without logging SMTP secrets.
Safe PHPMailer Debugging Order
- Confirm PHPMailer loads without a class or autoload error.
- Confirm OpenSSL is available for encrypted SMTP.
- Verify the SMTP hostname, port and encryption combination.
- Test outbound connectivity from the environment running PHP.
- Enable temporary sanitized SMTP debugging.
- Determine whether failure occurs before or after authentication.
- Verify the SMTP username and credential type.
- Use the authenticated or verified mailbox as From.
- Send a minimal message without HTML or attachments.
- Check send result, ErrorInfo and caught exceptions.
- Inspect spam, bounces and provider delivery logs.
- Disable debug output and protect the public form.
Continue Your CodeZips Project Workflow
Technical References
Frequently Asked Questions
Why does PHPMailer say SMTP connect() failed?
Check the SMTP hostname, port, encryption mode, DNS resolution, firewall and hosting outbound SMTP policy. Authentication has not necessarily occurred yet.
Why does Gmail reject my normal password?
A normal account password may not be accepted for SMTP. Depending on the account, use a supported OAuth flow or an app password associated with an account that has 2-Step Verification enabled.
Should the contact-form visitor be used as the From address?
Use the authenticated or verified mailbox as From. Place the validated visitor address in Reply-To so replies still reach the visitor.
Why does PHPMailer send successfully but no email arrives?
SMTP acceptance does not guarantee inbox placement. Check spam, quarantine, bounces, recipient spelling, provider logs and domain authentication.
Why does mail() return true but nothing is delivered?
The return value indicates that PHP accepted the message for transfer to its configured mail system. It does not prove final delivery.
Why does port 465 fail with STARTTLS?
Port 465 commonly expects an encrypted connection from the beginning, while port 587 commonly upgrades using STARTTLS. Follow the exact configuration documented by the provider.
Why does SMTP debugging break my AJAX response?
PHPMailer debug text is additional response output. It can make a JSON document invalid or send content before a redirect header. Disable public debug output and log controlled details privately.
Why is my PHPMailer class not found?
Confirm the Composer package was installed, load the correct vendor/autoload.php path and include the PHPMailer namespace imports.
Does this tool send a test email?
No. It creates a diagnosis and templates locally in the browser. It does not connect to the SMTP provider or use your credentials.
Final Takeaway
Debug PHP email in stages: load PHPMailer, establish the SMTP connection, negotiate the correct encryption, authenticate, submit an authorized sender, confirm server acceptance and then investigate final delivery. Do not treat every failure as a password problem, and never expose SMTP credentials in public code or browser output.

