Site icon FSIBLOG

How to Send an Email via Gmail SMTP Server Using PHP

How to Send an Email via Gmail SMTP Server Using PHP

How to Send an Email via Gmail SMTP Server Using PHP

How I broke it, what that cryptic error actually means, and the cleaner code I use today plus a few drills you can practice on your own.

Error Code

I just wanted to ship a friendly “Hello” from a PHP page. Instead, Gmail greeted me with this brick wall:

Authentication failure [SMTP: SMTP server does no support authentication
(code: 250, response: mx.google.com at your service, [98.117.99.235]
SIZE 35651584 8BITMIME STARTTLS ENHANCEDSTATUSCODES PIPELINING)]

At first glance it screams, “Gmail won’t let you log in,” but hidden in the noise is the clue: STARTTLS.

My First Snippet

<?php
require_once "Mail.php"; // PEAR Mail

$from = "Sandra Sender <sender@example.com>";
$to = "Ramona Recipient <ramona@microsoft.com>";
$subject = "Hi!";
$body = "Hi,\n\nHow are you?";

$host = "smtp.gmail.com";
$port = 587; // Gmail’s TLS port
$username = "testtest@gmail.com";
$password = "testtest"; // never hard-code real secrets

$headers = [
'From' => $from,
'To' => $to,
'Subject' => $subject
];

$smtp = Mail::factory('smtp', [
'host' => $host,
'port' => $port,
'auth' => true,
'username' => $username,
'password' => $password
]);

$result = $smtp->send($to, $headers, $body);

echo PEAR::isError($result)
? "<p>" . $result->getMessage() . "</p>"
: "<p>Message successfully sent!</p>";
?>

Why it Fizzled

SymptomPlain-English cause
SMTP server does no support authentication (code: 250)Gmail is happy to talk, but on port 587 it demands a STARTTLS handshake before it will listen to any username or password. PEAR Mail tried to log in first—Gmail politely refused.

A couple more rules bit me too:

Quick Patch While Staying on PEAR Mail

$smtp = Mail::factory('smtp', [
'host' => 'tls://smtp.gmail.com', // tell PEAR to negotiate TLS
'port' => 587,
'auth' => true,
'username' => getenv('GMAIL_USER'), // read from env vars
'password' => getenv('GMAIL_APP_PASS')
]);

This does work, but PEAR Mail is frozen in the early 2010s and has no native OAuth2 helper. That sent me hunting for a friendlier library.

The Clean UpGrade: PHPMailer

Install in one line:

composer require phpmailer/phpmailer

Drop the sample below into send-gmail.php and run it:

<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'vendor/autoload.php';

$mail = new PHPMailer(true); // throws Exceptions

try {
/* --- server --- */
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = getenv('GMAIL_USER'); // me@gmail.com
$mail->Password = getenv('GMAIL_APP_PASS'); // 16-char app password
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;

/* --- recipients --- */
$mail->setFrom('sender@example.com', 'Sandra Sender');
$mail->addAddress('ramona@microsoft.com', 'Ramona Recipient');
$mail->addReplyTo('noreply@example.com', 'No-reply');

/* --- content --- */
$mail->isHTML(true);
$mail->Subject = 'Hi!';
$mail->Body = '<p>Hi Ramona,<br><br>How are you?</p>';
$mail->AltBody = "Hi Ramona,\n\nHow are you?";

$mail->send();
echo 'Message sent!';
} catch (Exception $e) {
echo "Mailer Error: {$mail->ErrorInfo}";
}
?>

Why this works

Stretch Goals

DrillOne-liner to drop in
Attach a file$mail->addAttachment(__DIR__.'/invoice.pdf');
Send CC/BCC$mail->addCC('boss@example.com');
$mail->addBCC('audit@example.com');
Watch every SMTP command$mail->SMTPDebug = 2; (great on a staging box—turn off in production)
Load secrets from .envcomposer require vlucas/phpdotenv then $_ENV['GMAIL_USER']
HTML contact formPair a small index.html with action="send-gmail.php"; sanitize POST fields before calling $mail->Body.
Full OAuth2 (hard-mode)Register a Google Cloud project, enable Gmail API, and use PHPMailer’s OAuth class.

Work through them one at a time enable SMTPDebug, re-run, and watch the live conversation: EHLO, STARTTLS, AUTH, MAIL FROM, RCPT TO, DATA, QUIT. Seeing the handshake click into place is oddly satisfying.

Final Thought

The scary-looking error wasn’t cryptic at all once I read between the brackets it was Gmail saying, “Talk TLS to me first.” As soon as I negotiated encryption and switched to an app password, Gmail behaved like any normal SMTP server.

Exit mobile version