Send email from localhost running XAMMP in PHP using GMAIL mail server
Stefan Bogdanescu
Founder & Senior Architect
Sending Emails from Localhost: Why Simple mail() Fails and the Right Way Forward with SMTP
As a senior developer, I’ve seen countless developers struggle with email delivery. The frustration you are experiencing—where the PHP mail() function reports success but no email arrives—is extremely common when dealing with complex mail server configurations or attempting to bridge local systems with external services like Gmail.
The issue you are facing is not a simple coding error; it's a fundamental misunderstanding of how email protocols (SMTP) and local Mail Transfer Agents (MTAs) interact, especially when authentication (like using Gmail) is involved.
Let’s dive into why your current setup fails and what the robust, modern solution looks like.
The Pitfalls of Using mail() for Authenticated Sending
The built-in PHP mail() function relies entirely on the operating system's configured Mail Transfer Agent (MTA), which in your case is sendmail. When you use this function directly, you are essentially asking the OS to hand off the message.
When you try to configure sendmail via sendmail.ini to use an external SMTP server like smtp.gmail.com, you are attempting to make the local MTA act as a full SMTP client. This process is notoriously difficult because it requires precise handling of SSL/TLS negotiation, authentication credentials, and protocol commands (like STARTTLS).
Your error message—Must issue a STARTTLS command first—is the smoking gun. It tells us that while your system attempted to connect to port 587, the initial handshake failed because the necessary security layer (TLS) was not initiated correctly according to the SMTP standard before sending login credentials. This complexity is why trying to patch these low-level systems often leads to configuration nightmares.
The Recommended Solution: Embrace Dedicated Libraries
For almost all modern PHP applications, including those built on frameworks like Laravel, the best practice for sending emails is to bypass direct system calls and use dedicated, well-tested libraries that handle the complexities of SMTP protocol directly.
The gold standard for this in the PHP ecosystem is PHPMailer.
Why PHPMailer is Superior
- Protocol Handling: PHPMailer handles the entire SMTP conversation—connecting, authenticating, initiating TLS encryption (
STARTTLS), sending the message, and closing the connection—all in a structured way. - Reliability: It abstracts away the messy details of system-level mail servers (like your
sendmailconfiguration) and provides a consistent interface regardless of the underlying operating system setup. - Authentication: It manages secure login credentials far more reliably than trying to configure an MTA directly.
If you are building an application that needs robust communication, relying on external services requires a layer that is designed specifically for this task. This shift from low-level system administration to high-level library usage aligns perfectly with the architectural principles favored in modern frameworks like Laravel.
Example: Sending Email with PHPMailer
Here is how you would reliably send an email using SMTP via PHPMailer, which handles the necessary TLS negotiation automatically:
<?php
use PHPMailer\PHPMailer\PHPMailer;
require 'vendor/autoload.php'; // Include Composer autoloader
$mail = new PHPMailer(true);
try {
// Server settings (using Gmail SMTP)
$mail->isSMTP(); // Send using SMTP
$mail->Host = 'smtp.gmail.com'; // Set the SMTP server to send through
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = 'your_email@gmail.com'; // Your Gmail address
$mail->Password = 'your_app_password'; // Your App Password (Not your main password!)
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // Enable TLS encryption (Crucial step)
$mail->Port = 587; // TCP port for STARTTLS
// Recipients
$mail->setFrom('your_email@gmail.com', 'Your Name');
$mail->addAddress('recipient@example.com'); // Add a recipient
// Content
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = 'Reliable Test Email via PHPMailer';
$mail->Body = 'This is the body of the email sent securely.';
$mail->FromString = 'This was sent using a dedicated library.';
$mail->send();
echo 'Message has been sent successfully!';
} catch (Exception $e) {
// If the connection or authentication fails, this block catches the error.
echo 'Message could not be sent. Mailer Error: ' . $e->getMessage();
}
?>
Conclusion
The core takeaway is that when dealing with external services like Gmail via SMTP, avoid trying to manually configure low-level system utilities like sendmail directly for application logic. That approach introduces significant fragility and requires expert-level knowledge of network protocols.
Instead, delegate the heavy lifting to robust, community-vetted libraries like PHPMailer. By using these tools, you ensure that your email sending process is reliable, secure (handling those critical TLS handshakes automatically), and maintainable—a principle that underpins good software development, whether you are working with complex backend systems or building modern web applications on platforms like Laravel.
Note: Blog content is currently available in English.