Let’s face it, almost every website needs to send emails now and then. Whether it’s confirming user registrations, delivering password reset links, or sending out monthly newsletters, email functionality is a must.
PHP developers have long wrestled with the built-in mail() function, which works for most basic needs but quickly shows its limitations as projects become more complex, especially when it comes to handling attachments, HTML content, and using external SMTP servers.
This is where PHPMailer comes into play. As one of PHP’s most downloaded libraries, PHPMailer makes the frustrating task of email delivery easier.
In this guide, we'll take you through everything you need to know about using PHPMailer in your projects. We'll cover the basics, like installation and configuration, but we won't stop there. You'll learn how to create visually appealing HTML emails, attach files securely, manage recipient lists, and troubleshoot common issues.
Prerequisites
- Basic knowledge of PHP
- PHP interpreter installed on your local machine
- Composer installed on your local machine (optional)
What Is PHPMailer And Why Use It Instead Of The PHP Mail() Function?
PHPMailer is an open-source PHP library specially designed to simplify the process of sending emails from PHP applications. First released in 2001, it has grown to become one of the most widely used PHP libraries, with over 70 million installs on Packagist and over 20k stars on GitHub, which is pretty impressive!
Adding to its popularity, it is also included in many PHP frameworks and CMS platforms like WordPress, Drupal, and Laravel.
Its architecture offers a clean, object-oriented interface for email functionality, handling the complexities of email specifications, including support for HTML emails, attachments, and SMTP authentication.
At this point, it may already be clear that most developers prefer PHPMailer over PHP’s native mail() function. To understand the “why” better, let's look at the limitations of mail() in the next section.
The Limitations of PHP’s Native mail() function
PHP’s built-in mail() function might seem like a straightforward solution for sending emails, but it has several issues that make it quite problematic for modern applications:
- Inconsistent Behavior: The mail() function behaves differently across different SMTP server configurations. Programmers have to rely on the system admin for proper configuration.
- Limited HTML Support: Sending HTML emails with mail() requires manual creation of MIME headers and message body parts. This task is time-consuming and prone to errors.
- Poor Attachment Handling: Adding attachments involves even more complex MIME encoding that must be implemented manually.
- Character Encoding Issues: The mail() function struggles with international character sets and UTF-8 encoding. This often results in garbled text.
- No SMTP Choices: It relies on the server's local mail transfer agent (MTA) rather than connecting directly to the necessary SMTP servers, which is too limiting.
- No Proper Error Handling: The function provides minimal feedback about delivery problems, making debugging difficult.
Let's look at the sample code that demonstrates how hard it is to send a very basic HTML email:
// Note the complexity required to send a simple HTML email with PHP's mail() function |
As you can see, even a basic HTML email requires multiple headers to be added manually, and adding attachments or handling multiple recipients would make this code significantly more complex.
Now that we have examined the limitations of PHP mail(), let's look at the advantages of using PHPMailer in the next section.
Advantages of Using PHPMailer
Let’s check out how PHPMailer addresses all these limitations:
- Explicit SMTP Configuration: Connect directly to the SMTP servers you need with proper authentication, bypassing local mail server configurations.
- Effortless HTML Emails: Create HTML emails easily with proper MIME encoding and alternative plain text versions.
- Simplified Attachments: Add file attachments with just a few lines of code, with proper MIME handling.
- Comprehensive Recipient Management: Easily handle multiple recipients, with support for TO, CC, BCC, and Reply-to addresses.
- International Character Support: Built-in handling of UTF-8 and other character sets for proper display of international text.
- Error Handling and Debugging: Detailed exception handling and debugging options for troubleshooting delivery issues.
- Security Features: Support for TLS/SSL encryption, SMTP authentication, and other security measures.
The following code sample demonstrates how PHPMailer simplifies the process of sending an HTML email:
use PHPMailer\PHPMailer\PHPMailer; |
Now, you can see that with PHPMailer, you have a more secure and reliable package for sending those mission critical emails. But don’t get excited just yet! We are going to explore the various capabilities of PHPMailer in the upcoming sections.
How to install and configure PHPMailer
Installation Options
You can install PHPMailer in your PHP project using Composer or by manually adding the package files. Both options are described below.
- Using Composer(Recommended): To install and configure PHPMailer, you first need to download and install the Composer, which is PHP’s dependency manager. It can be installed on Linux/Unix/macOS and Windows.
Since I use a Windows system, I'll be working with that through the rest of this PHPMailer tutorial. You can follow along regardless of the system you use.
To check if Composer was installed successfully, run the command:
composer -V |
You’ll get a response that should look like this:
After installation, you can either add the following line to your composer.json file:
"phpmailer/phpmailer": "^6.9" |
Or create a folder, cd into it, and run the command below on your terminal (recommended):
composer require phpmailer/phpmailer |
After running the command, you should get a success message in your terminal like this:
Now, open the folder on your preferred IDE. I use VSCode for reference.
- Manual Download: if you prefer not to use Composer, you can download PHPMailer directly from the GitHub repository and use the following steps to get it up and running:
- Step1: Download the latest release as a ZIP file
- Step 2: Extract the contents to your project directory
- Step 3: Include the necessary files in your PHP script
require 'path/to/PHPMailer/src/Exception.php'; |
Basic Configuration
You must set up the basic configuration options for PHPMailer to work properly. The configuration setup is described in the PHPMailer documentation. Once you've gathered your SMTP server details and login credentials, plug them into the code, as shown in the example below:
<?php |
How to Send emails using PHPMailer and UniOne SMTP
PHPMailer allows you to use any preferred SMTP server to send your emails, either your own or provided by a third party. Using an external SMTP server is recommended as it is more secure and reliable. Throughout this tutorial, we'll dive headfirst into how to send emails using UniOne’s SMTP service. You can also configure your script for another SMTP server if you opt for an alternative to UniOne.
To get started with UniOne, follow the steps below:
1. Sign up for a UniOne account. This is what your dashboard looks like below after signing up:
2. Add your sender domain. Learn how to do this in this video.
3. Access the SMTP debug tool and sign up to test the SMTP server functionality (more on this later in this tutorial).
Note: you will need your user ID and API key to sign up if you’ll be going with UniOne’s SMTP settings. Learn more about this in this video. You will also need an email from a confirmed domain for this to work.
4. Add your credentials, such as your host, port, and API key from UniOne, into your PHP code.
Now that you have your server settings ready, it's time to learn the different ways of sending emails using PHPMailer.
Sending Plain Text Emails
As we already discussed earlier, PHPMailer allows you to send emails in plain text. Here's the implementation:
<?php |
PHPMailer’s isHTML setting defaults to true. For plain text to work, we set it to false. Once you run the code, you get this or a similar response on your terminal:
You should get similar responses throughout the rest of our tutorial.
Sending File Attachments
Here's the implementation for sending an attachment with PHPMailer:
<?php |
In the code, we specified the attachment and pointed the local path to the .pdf file. You can specify other file types (like .png or .jpg):
//Attachments |
And that's it! You can now send your file with the rest of your email.
Sending HTML Emails
Remember when we set our isHTML to false? Well, change of plans :) To be able to send HTML emails, you have to set it to true.
<?php
|
I included a basic HTML markup to demonstrate how well you can customize your HTML email. Note that CSS style definitions are included in the head section. For better email clients compatibility, it is advisable to use inline CSS, however this makes the HTML part bloated.
Sending to Multiple Recipients (Including CC and BCC)
Sending emails to multiple recipients is easy and requires just a few extra lines of code:
// Adding multiple recipients |
In the code above, we included CC (Carbon Copy) and BCC (Blind Carbon Copy) recipients.
Sending Embedded Images
If you want an image to be shown in your email body, not as an attached file, use the sample code below:
// Embed an image |
Sending an Asynchronous Email
This part may be a little bit tricky, and you don't have to follow along here if you aren't a full-time PHP developer. The first thing we need to know is that PHPMailer operates synchronously by default. This means your application must wait for the email-sending process to complete before continuing execution. This can create noticeable delays in your application, especially when sending multiple emails or emails with attachments.
Unlike server-side languages like Node.js, where asynchronous operations are a fundamental part of the architecture, PHP doesn't natively support non-blocking operations.
However, you can work around this limitation by using PHP's exec() function to run a separate email script in the background.
Here's how to implement this approach:
- Step 1: Create a dedicated email-sending script — First, create a standalone script (let's call it send_email_background.php) that handles the email-sending process, and nothing else:
<?php //Load Composer's autoloader ... ... |
- Step 2: Call the script asynchronously from your main application — In your main application script, use the exec() function to call the script without waiting for it to finish:
<?php |
Important considerations to note are:
- The exec() function is usually disabled in shared hosting environments for security reasons. Check your PHP configuration (php.ini) to see if it's listed in the disable_functions directive.
- In some environments, you might need to specify the full path to the PHP binary:
exec("/usr/bin/php /path/to/send_email_background.php > /dev/null 2>&1 &"); |
Sending Bulk Emails
From an earlier discussion, you may think that sending emails in bulk is easy – just add as much recipients as you need. However, this is not a viable option due to many reasons. For example, you may want to customize the emails to include the addressee’s name in the subject, for example. Next, sending messages to different subscribers may result in different errors which you want to log and act accordingly, and so on. In this section, let's look at how to really send emails in bulk:
<?php require 'vendor/autoload.php'; // Add as many recipients as you need! |
The code uses PHPMailer's SMTPKeepAlive feature to maintain a persistent connection, avoiding the need to reconnect to the SMTP server for each message. It tracks success and failure rates, implementing proper error handling for each email in the batch.
As we can see, sending emails with PHP has never been easier. For really large volumes, however, you’ll need to consider a dedicated job queue system using Beanstalkd, RabbitMQ, or Redis. They are helpful for more complex requirements or high-volume email sending.
Error handling and debugging with PHPMailer
When implementing email functionality in production applications, you'll inevitably encounter situations where emails fail to send. This can be annoying! Fortunately, PHPMailer provides robust debugging options to help you identify and resolve these issues quickly.
Understanding PHPMailer’s Debug Levels
PHPMailer's debugging system exposes the underlying SMTP conversation, giving you visibility into exactly what's happening during the email-sending process. You can activate debugging by setting the SMTPDebug property to different levels. For example:
// Set debug level before configuring other settings |
The available debug levels provide increasingly detailed information:
- Level 0: Off – No output (default)
- Level 1: Client – Shows only messages sent from the client
- Level 2: Client & Server – Shows the conversation between client and server (recommended for most troubleshooting)
- Level 3: Connection details – Adds information about the initial connection, helpful for diagnosing STARTTLS issues
- Level 4: Low-level data output – Very verbose output for advanced debugging
Common Error Cases and Their Debug Output
Let's examine two common error scenarios and how debugging helps identify them:
- Example 1: Connection Problems (Invalid Hostname) — When you can’t connect to the SMTP server, the debug output clearly shows the connection failure:
2025-02-28 09:23:45 Connection: opening to smtp.wrongdomain.com:465, timeout=10, options=array() |
In this example, the error occurs at the connection stage because I've deliberately used an incorrect hostname (smtp.wrongdomain.com). The debug output shows that the connection attempt timed out, indicating either a wrong hostname, port, or network connectivity issues.
- Example 2: Authentication Failures — Authentication issues are another common problem that debugging helps identify:
2025-02-28 09:31:22 Connection: opening to smtp.eu1.unione.io:465, timeout=300, options=array() |
Here, the connection to the SMTP server succeeds, but authentication fails. The debug output shows the exact point of failure: the server rejected the username/password combination. Crosscheck your credentials (i.e. user ID and API key), ensure they are correct and you're good to go!
Alternatively, you can check out our dedicated debug tool to find and fix errors.
How to test PHPMailer implementations?
Testing your email implementation is important before going to production. You can use our SMTP debug tool to perform the following tests:
- SMTP Test
- SMTP Proxy Test (a powerful tool that lets you debug a real SMTP session with your software and an SMTP provider like UniOne)
- SMTP Blackhole test
Security considerations when using PHPMailer
Here are a few security considerations when using PHPMailer:
- Use SMTP with Encryption: Always use SMTP with encrypted connection. You don't want anyone eavesdropping on your emails :)
// Use STARTTLS (more compatibility) |
- Protect Your Credentials: Never, I repeat – never! hardcode SMTP credentials in your code. Instead, use environment variables or a secure configuration system. For example:
// Using environment variables |
- Validate All User Input: Always validate and sanitize all user inputs that will be used in emails to prevent injection attacks:
// Bad practice |
- Implement Rate Limiting: Implement rate limiting to prevent abuse of your email functionality. For example:
function canSendEmail($userId, $maxEmails = 10, $period = 3600) { |
- Use SPF, DKIM, and DMARC: Configure your domain by adding SPF, DKIM, and DMARC records to the DNS to improve deliverability and security (this is also a requirement for using UniOne’s SMTP):
- SPF (Sender Policy Framework): SPF lets you define which servers can legitimately send emails on behalf of your domain.
- DKIM (DomainKeys Identified Mail): DKIM adds a digital signature to your outgoing messages, confirming they haven't been tampered with during delivery.
- DMARC (Domain-based Message Authentication): DMARC provides instructions to receiving mail servers about how to handle messages that don't pass SPF or DKIM verification.
When these settings are configured at the DNS level, PHPMailer can be used with DKIM:
// DKIM signing requires the OpenSSL extension |
- Error Handling: Use proper error handling to avoid exposing sensitive information to the user:
try { |
How UniOne Can Help
UniOne works really well alongside PHPMailer. If you're dealing with a growing number of emails or need better tracking and analytics, UniOne gives you the infrastructure without having to build it yourself. You don't even have to worry about setting up your own server – UniOne already has you covered!
Frequently Asked Questions
What is the use of a PHPMailer?
PHPMailer is a code library that enables secure and straightforward email transmission through PHP code from a web server. It functions as a Mail User Agent (MUA) that communicates with a Mail Submission Agent (MSA) server.
Is PHPMailer secure?
Absolutely! It allows for TSL/SSL encrypted connections. However, you are still responsible for the safety of your credentials. Never expose them explicitly in your code.
Which version of PHP is compatible with PHPMailer?
PHPMailer 6.0 requires PHP 5.5 or newer and maintains full compatibility with all newer PHP versions through 8.4.