PHPMailer – The Classic PHP Email-Sending Library

0

PHPMailer is the most widely used library for sending email from PHP. It has been in use since 2001, ships in WordPress, Drupal, Joomla and thousands of applications, and is installed millions of times a month through Composer. If a PHP application sends mail, there is a good chance PHPMailer is doing it.

This domain hosted the original PHPMailer website and its documentation for over a decade. Development moved to GitHub years ago: github.com/PHPMailer/PHPMailer is the authoritative source for releases, issues and security advisories. The pages here are tutorials, worked examples and a reference for using the library day to day.

What it actually does for you

PHP has a built-in mail() function, so the reasonable question is why a library exists at all. Because mail() gives you a string and a hope:

mail() PHPMailer
SMTP with authentication No Yes
TLS / STARTTLS No Yes
Error reporting A boolean Server response in ErrorInfo, or an exception
MIME multipart Build the headers yourself Handled
Attachments Manual base64 and boundaries addAttachment()
Inline images Manual cid: parts addEmbeddedImage()
HTML + plain-text alternative Manual isHTML() and AltBody
Non-ASCII subjects Manual encoding CharSet
DKIM signing No Built in
Header-injection protection Your problem Validated

That last row is not a convenience. Passing unvalidated user input into mail headers is a real vulnerability class — an attacker who can inject a newline can add recipients and turn your contact form into an open relay. PHPMailer rejects those values instead.

Sending an email, minimally

composer require phpmailer/phpmailer
<?php
use PHPMailerPHPMailerPHPMailer;
use PHPMailerPHPMailerException;

require 'vendor/autoload.php';

$mail = new PHPMailer(true);

try {
    $mail->isSMTP();
    $mail->Host       = 'smtp.example.com';
    $mail->SMTPAuth   = true;
    $mail->Username   = getenv('SMTP_USER');
    $mail->Password   = getenv('SMTP_PASS');
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    $mail->Port       = 587;

    $mail->setFrom('noreply@example.com', 'Your App');
    $mail->addAddress('recipient@example.com');

    $mail->Subject = 'Hello';
    $mail->Body    = 'Sent with PHPMailer.';

    $mail->send();
} catch (Exception $e) {
    echo 'Failed: ' . $mail->ErrorInfo;
}

The true in the constructor turns on exceptions, and it is the single most useful thing on this page. Without it, send() returns false and it is on you to check — which is how applications quietly stop sending email for weeks before anyone notices.

Documentation

Getting started

  • Installing PHPMailer — Composer and manual installation, required extensions, upgrading from 5.x.
  • Tutorial — step by step from an empty project to authenticated SMTP with HTML and attachments.

Examples

  • All examples — one working script per transport: mail(), sendmail, SMTP, Gmail App Password, Gmail XOAUTH2, batching.
  • SMTP example — full configuration, port and encryption pairs, every error explained, provider settings.
  • mail() example — the local transport, its one serious limitation, and when it is still fine.

Reference

The three things that go wrong

Almost every PHPMailer problem is one of these.

SMTP connect() failed

The connection never opened, so credentials were never even tried. Usually the port and encryption constant disagree — 587 goes with ENCRYPTION_STARTTLS, 465 with ENCRYPTION_SMTPS, and crossing them fails every time. Otherwise it is an outbound firewall; most shared hosts and cloud providers block SMTP by default. Check reachability before debugging PHP:

openssl s_client -starttls smtp -connect smtp.example.com:587

Could not authenticate

The connection worked, the credentials were refused. On Gmail this is nearly always an account password used where an App Password is required. Elsewhere, check whether the username should be the full email address or just the local part — providers differ and both are common.

It sends, but everything lands in spam

Not a PHPMailer problem at all, and no code change will fix it. Acceptance is decided by DNS records for your sending domain:

  • SPF — a TXT record listing which servers may send for the domain.
  • DKIM — a public key so receivers can verify the message was signed by you and not altered in transit.
  • DMARC — a policy telling receivers what to do when SPF and DKIM fail, and where to send reports.

Missing DKIM is the usual reason a technically perfect message gets filtered. If your host does not sign outgoing mail, PHPMailer will:

$mail->DKIM_domain   = 'example.com';
$mail->DKIM_selector = 'phpmailer';
$mail->DKIM_private  = '/secure/path/dkim_private.pem';
$mail->DKIM_identity = $mail->From;

When something fails, turn on the protocol conversation before guessing. It identifies the cause on the first run in almost every case:

use PHPMailerPHPMailerSMTP;

$mail->SMTPDebug = SMTP::DEBUG_SERVER;

Versions

6.x is the current line. It is namespaced (PHPMailerPHPMailerPHPMailer), installed with Composer, and supports PHP 5.5 upward including current releases.

5.x — the era of require 'class.phpmailer.php' and a global PHPMailer class — reached end of life years ago and receives no security fixes. Code written against it will not run on 6.x unchanged, though the changes are small; the installation page has the mapping.

PHPMailer or something else?

If you are already inside a framework, use its mailer. Symfony Mailer and Laravel’s Mail facade are wired into the container, the queue and the template engine, and you gain nothing by bypassing that.

PHPMailer suits standalone scripts, legacy codebases, CMS plugins and projects with no framework — anywhere a single dependency that reliably sends email is exactly the right size of tool. It is also the reason so much of the PHP web works: WordPress alone means it is running on a substantial share of the internet.

Contributing

Bug reports, security advisories and pull requests belong on the project’s repository at github.com/PHPMailer/PHPMailer. If you find something inaccurate on these documentation pages, that is ours — let us know.

sunshyne works on technical SEO and email deliverability for French-speaking markets, and runs the digital consultancy at sunshyne.ch. Most of that work sits where the two overlap. On the SEO side: redirect mapping, crawl and indexation diagnostics, server log analysis, and recovering domains whose history has damaged them. On the email side: the authentication layer — SPF, DKIM and DMARC — sender reputation, and the reasons a technically valid message still gets filtered. These PHPMailer pages exist because the second half of that work keeps returning to the same questions: which transport to use, why an SMTP connection fails, and why a correctly formed message is rejected anyway. The examples here are the ones worth keeping after answering those questions more than once.

Comments are closed.