Sending email from PHP using PHPMailer is surprisingly straightforward once you understand the core components, but the configuration can feel like a dark art. The most common stumbling block isn’t the PHP code itself, but how your server or the remote SMTP server is set up to talk to each other.

Let’s see PHPMailer in action, sending a simple email. We’ll use a Gmail account for this example, as it’s a common starting point.

<?php
// Import PHPMailer classes into the global namespace
// These must be at the top of your script, not inside a function
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

// Load Composer's autoloader
require 'vendor/autoload.php';

$mail = new PHPMailer(true);

try {
    //Server settings
    $mail->SMTPDebug = 2;                      //Enable verbose debug output (0=off, 1=client, 2=server and client)
    $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'; //SMTP username
    $mail->Password   = 'your_app_password';    //SMTP password (use an app password for Gmail)
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; //Enable implicit TLS encryption
    $mail->Port       = 465;                    //TCP port to connect to; use 587 if you set SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS

    //Recipients
    $mail->setFrom('your_email@gmail.com', 'Mailer');
    $mail->addAddress('recipient@example.com', 'Joe User'); //Add a recipient
    $mail->addAddress('recipient2@example.com');          //Name is optional
    $mail->addReplyTo('info@example.com', 'Information');
    $mail->addCC('cc@example.com');
    $mail->addBCC('bcc@example.com');

    //Content
    $mail->isHTML(true);                                  //Set email format to HTML
    $mail->Subject = 'Here is the subject';
    $mail->Body    = 'This is the HTML message body <b>in bold!</b>';
    $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';

    $mail->send();
    echo 'Message has been sent';
} catch (Exception $e) {
    echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}
?>

At its heart, PHPMailer is a library that abstracts away the complexities of the SMTP protocol. Instead of crafting raw SMTP commands yourself (like HELO, MAIL FROM, RCPT TO, DATA, etc.), you interact with a PHP object. The isSMTP() method tells PHPMailer to use an external SMTP server for sending, rather than PHP’s built-in mail() function (which is often unreliable and poorly configured on shared hosting).

The core of the setup revolves around two main areas: your application’s configuration of PHPMailer and the SMTP server’s requirements.

SMTP Server Configuration:

  • Host: This is the address of the SMTP server you’re connecting to. For Gmail, it’s smtp.gmail.com. For Outlook/Office 365, it’s smtp.office365.com. For SendGrid, it might be smtp.sendgrid.net.
  • Port: This is the network port the SMTP server listens on. The two most common are 465 (for SMTPS, which is implicit SSL/TLS) and 587 (for STARTTLS, where the connection starts unencrypted and is then upgraded to TLS).
  • SMTPAuth: This must be true if the SMTP server requires a username and password for authentication. Almost all modern SMTP servers do.
  • Username & Password: These are your credentials for the SMTP server.
    • For Gmail: You must use an "App Password" if you have 2-Step Verification enabled. Go to your Google Account security settings, find "App passwords," and generate one for PHPMailer. Your regular Google password will not work.
    • For Office 365/Exchange: Use your full email address as the username and your account password.
    • For other providers: Consult their documentation for the correct username and password to use.
  • SMTPSecure: This specifies the encryption method.
    • PHPMailer::ENCRYPTION_SMTPS (or 'ssl') uses port 465.
    • PHPMailer::ENCRYPTION_STARTTLS (or 'tls') uses port 587.
    • If you don’t specify this and use port 587, PHPMailer will attempt STARTTLS. If you use port 465 without this, it will likely fail.

PHPMailer Specifics:

  • $mail->SMTPDebug = 2;: This is your best friend during setup. It prints detailed information about the SMTP conversation between PHPMailer and the server. A value of 2 is usually sufficient to see where the handshake is failing.
  • $mail->setFrom(...): This sets the "From" address and name that appears in the recipient’s email client. It’s crucial that this email address is often allowed to be sent by the SMTP server you’re authenticating with. For example, if you authenticate with your_email@gmail.com, you should generally set your "From" address to your_email@gmail.com or a related address.
  • $mail->isHTML(true);: If you want to send rich HTML emails, set this to true. PHPMailer will then expect $mail->Body to be HTML.
  • $mail->AltBody: If isHTML(true) is set, you must provide an $mail->AltBody. This is the plain text version of your email for clients that don’t support HTML.

When troubleshooting, the $mail->ErrorInfo property is invaluable. It will contain the last error message received from the SMTP server.

One often overlooked detail is that some hosting providers block outbound SMTP connections on common ports (like 25, 465, 587) to prevent spam. If you’re on shared hosting and your PHPMailer setup seems perfect but still fails, you might need to use a third-party transactional email service (like SendGrid, Mailgun, Amazon SES) and configure PHPMailer to use their SMTP credentials. These services are designed for programmatic email sending and have much higher deliverability rates.

The next common hurdle after getting basic SMTP working is handling attachments or dealing with rate limits imposed by your SMTP provider.

Want structured learning?

Take the full Smtp course →