When it comes to adding email functionality to your PHP app, PHPMailer class is the winning option. It is compatible with most of the PHP frameworks (Laravel or Symfony are based on the SwiftMailer library, though, but it is still possible to use PHPMailer as well.) PHPMailer provides powerful functionality to create HTML emails with attachments and send them to multiple recipients via SMTP or a local webserver. Learn how to easily use all these options in this tutorial!
What is PHPMailer
PHPMailer is the classic email sending library for PHP. It supports several ways of sending email messages, such as mail(), Sendmail, qmail, and direct dispatch to SMTP servers. In addition, it provides numerous advanced features:
- SMTP authentication
- secure/MIME encryption
- support of TLS and SSL protocols
- HTML content along with plain text
- multiple fs, string, and binary attachments
- embedded images support
Sending Email With PHPMailer and SMTP
To send emails with PHPMailer and SMTP, you need to install PHPMailer and configure SMTP settings first.
How to install PHPMailer
Up to version 5, PHPMailer was providing “PHPMailerAutoload.php” file, so all that was needed was to include it in your script and create a PHPMailer instance. Starting from PHPMailer 6.0, released in August 2017, you need to install it, preferably via Composer, a dependency manager for PHP (this way is recommended by PHPMailer’s creators on Github). After installing Composer, add this line to your composer.json file:
"phpmailer/phpmailer": "~6.1"
or run
composer require phpmailer/phpmailer
If you don’t want to install Composer, for example, while working within a testing environment, you can add PHPMailer manually. Download files with PHPMailer source code, then copy the contents of the PHPMailer folder to one of the include_path directories specified in your PHP configuration, and load each class file manually:
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'path/to/PHPMailer/src/Exception.php';
require 'path/to/PHPMailer/src/PHPMailer.php';
require 'path/to/PHPMailer/src/SMTP.php';
Adding Exception class will help you handle errors and debug them. In PHP it works similarly to other programming languages. So, without it, if there is an error in your email sending code, you will just see a message saying Exception class is not found, but you won’t be provided with any details on how to debug it. We will describe debugging in a separate section of this post.
To see detailed instructions on installation, check PHPMailer documentation on Github.
SMTP configuration
For PHPMailer to be able to send emails from your PHP app, you will need to connect it to an SMTP server.
We suggest you first use an email testing tool such as Mailtrap Email Testing and its SMTP server to test the functionality before sending anything to real recipients. Once you make sure that things are working properly and your emails look right, you can easily substitute Email Testing SMTP settings with the settings of your real server.
Besides providing you with SMTP settings, Email Testing also allows you to preview, inspect and debug emails in staging. This way, you can fix any errors before the sending is done and not risk spamming real recipients with test emails.
The most notable features of this testing tool include spam checking, HTML/CSS validation, blacklist reports, and more.
To start using Mailtrap Email Testing, create a free account, go to Email Testing-> Inboxes, and copy-paste the provided SMTP settings to your PHPMailer script:
$phpmailer = new PHPMailer();
$phpmailer->isSMTP();
$phpmailer->Host = 'sandbox.smtp.mailtrap.io';
$phpmailer->SMTPAuth = true;
$phpmailer->Port = 2525;
$phpmailer->Username = '07f4dbf61b8122';
$phpmailer->Password = 'd7fc5d57bc6eac';
There is one more point left to mention about SMTP: POP-before-SMTP for authentication. This method is almost fully replaced by the SMTP authentication but still can be used sometimes. Its main advantage is the transparency for the user who is sending an email. Check this Github page to get the example of using POP-before-SMTP with PHPMailer.
Sending HTML email via SMTP with PHPMailer
You will most likely use HTML to design your email notification. So, let’s review some examples of using HTML methods and attributes.
Basic HTML message
If you have used Composer for installation, include the Composer generated autoload.php file:
require 'path/to/composer/vendor/autoload.php';
If you have installed PHPMailer manually, initialize it like this:
require path/to/PHPMailer/src/PHPMailer.php';
require path/to/PHPMailer/src/SMTP.php';
require path/to/PHPMailer/src/Exception.php';
Then create the PHPMailer class:
<?php
use PHPMailer\PHPMailer\PHPMailer;
The next step is to create a new PHPMailer object:
$mail = new PHPMailer();
Now let’s move to an SMTP configuration:
$mail->isSMTP();
$mail->Host = 'sandbox.smtp.mailtrap.io';
$mail->SMTPAuth = true;
$mail->Username = '1a2b3c4d5e6f7g'; //paste one generated by Mailtrap
$mail->Password = '1a2b3c4d5e6f7g' //paste one generated by Mailtrap
$mail->SMTPSecure = 'tls';
$mail->Port = 2525;
Specify PHPMailer headers:
$mail->setFrom('info@mailtrap.io', 'Mailtrap');
$mail->addReplyTo('info@mailtrap.io', 'Mailtrap');
$mail->addAddress('recipient1@mailtrap.io', 'Tim');
$mail->addCC('cc1@example.com', 'Elena');
$mail->addBCC('bcc1@example.com', 'Alex');
If you need to add several addresses, specify each of them as a new command:
$mail->AddBCC('bcc2@example.com', 'Anna');
$mail->AddBCC('bcc3@example.com', 'Mark');
With PHPMailer, you can loop your message and send it to multiple recipients. In particular, you can read a list from the table. We will review such examples a bit later in this post, and now let’s get back to our basic message.
Set a subject:
$mail->Subject = 'Test Email via Mailtrap SMTP using PHPMailer';
Then set the email format to HTML with isHTML(true) property:
$mail->isHTML(true);
Now you can input the desired content:
$mailContent = "<h1>Send HTML Email using SMTP in PHP</h1>
<p>This is a test email I’m sending using SMTP mail server with PHPMailer.</p>";
$mail->Body = $mailContent;
With PHPMailer, you can also make a nice HTML email, with custom formatting, images, and send emails with attachments. For your convenience, PHPMailer provides an option to read an HTML message body from an external file, convert referenced images to embedded as well as convert HTML into a basic plain-text alternative body. This way, you will not overload your message sending code with HTML and will be able to update your HTML template independently. To include a separate HTML file, add these attributes:
$mail->msgHTML(file_get_contents('contents.html'), __DIR__);
In the end, specify the email sending attributes:
if($mail->send()){
echo 'Message has been sent';
}else{
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
}
The result “Message has been sent” informs you that your code was executed correctly.
Since you used Mailtrap Email Testing’s SMTP settings, you can then go to Email Testing-> Inboxes to check what your HTML email looks like.
Capture all test emails and inspect them all in one place.
HTML email with attachments
There are two options for adding files to your message:
- Enclose a file from your filesystem – like you can make it in the email client. In this case, your files should be saved in the same directory as the script.
- Also, a file can be inlined into your message, this is valid for images.
- Add a string attachment – in this case, the data stored in a variable is attached to the message. It can be extracted from a database, for example, so you don’t need to save it as a file.
To attach a file, you just need to specify its path. Also, you can add a filename but it’s optional: the script will use the actual name of your file:
$mail->addAttachment('path/to/invoice1.pdf', 'invoice1.pdf');
To add another file, repeat the command:
$mail->addAttachment('path/to/calculation1.xlsx', 'calculation1.xlsx');
To add an attachment from the string, use addStringAttachment() command. You should pass the content and the filename:
$mysql_data = $mysql_row['blob_data'];
$mail->addStringAttachment($mysql_data, 'db_data.db');
This is an example of adding data stored as a BLOB (Binary Large OBject) from MySQL database.
Alternatively, you can use a remote URL, like below:
$mail->addStringAttachment(file_get_contents($url), 'myfile.pdf');
To embed an image, we use CID attachments here:
$mail->addEmbeddedImage('path/to/image_file.jpg', 'image_cid');
$mail->isHTML(true);
$mail->Body = '<img src="cid:image_cid">';
Finally, let’s review an example of a whole message with an inlined image and internal HTML body:
<?php
use PHPMailer\PHPMailer\PHPMailer;
require 'path/to/composer/vendor/autoload.php';
$mail->isSMTP();
$mail->Host = 'sandbox.smtp.mailtrap.io';
$mail->SMTPAuth = true;
$mail->Username = 'paste one generated by Mailtrap';
$mail->Password = 'paste one generated by Mailtrap’
$mail->SMTPSecure = 'tls';
$mail->Port = 2525;
$mail->setFrom('from@example.com', 'First Last');
$mail->addReplyTo('towho@example.com', 'John Doe';
$mail->isHTML(true);
$mail->Subject = "PHPMailer SMTP test";
$mail->addEmbeddedImage('path/to/image_file.jpg', 'image_cid');
$mail->Body = '<img src="cid:image_cid"> Mail body in HTML';
$mail->AltBody = 'This is the plain text version of the email content';
if(!$mail->send()){
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
}else{
echo 'Message has been sent';
The result “Message has been sent” informs you that your code is executing correctly. To check the delivery result and details, go to your Mailtrap inbox: your messages will get there in seconds.
Sending emails to multiple recipients
Above, we have examined how to send one and the same email to several recipients, including CCing and BCCing. What if you need to send a modified message to a list of recipients, which is often required for transactional emails? PHPMailer offers features for such use cases as well!
<?php
use PHPMailer\PHPMailer\PHPMailer;
require 'path/to/composer/vendor/autoload.php';
$mail = new PHPMailer;
$body = file_get_contents('contents.html');
$mail->isSMTP();
$mail->Host = 'sandbox.smtp.mailtrap.io';
$mail->SMTPAuth = true;
$mail->Username = '1a2b3c4d5e6f7g'; //generated by Mailtrap
$mail->Password = '1a2b3c4d5e6f7g'; //generated by Mailtrap
$mail->SMTPSecure = 'tls';
$mail->Port = 2525;
$mail->SMTPKeepAlive = true; // add it to keep SMTP connection open after each email sent
$mail->setFrom('list@example.com', 'List manager');
$mail->Subject = "New Mailtrap mailing list";
$users = [
['email' => 'max@example.com', 'name' => 'Max'],
['email' => 'box@example.com', 'name' => 'Bob']
];
foreach ($users as $user) {
$mail->addAddress($user['email'], $user['name']);
$mail->Body = "<h2>Hello, {$user['name']}!</h2> <p>How are you?</p>";
$mail->AltBody = "Hello, {$user['name']}! \n How are you?";
try {
$mail->send();
echo "Message sent to: ({$user['email']}) {$mail->ErrorInfo}\n";
} catch (Exception $e) {
echo "Mailer Error ({$user['email']}) {$mail->ErrorInfo}\n";
}
$mail->clearAddresses();
}
$mail->smtpClose();
Test emails like this in a safe testing environment.
How to use PHPMailer with Gmail SMTP
Gmail is one of the most popular SMTP servers, which allows you to send emails for free.
Prior to May 30, 2022, from your Google account security settings “Less secure app access” had to be turned on to send emails using PHPMailer. Since the “Less secure apps” feature that allows third-party software and devices to sign in to your Gmail account is no longer supported by Google you can choose the other more secure options available. However, it does require some tinkering with authentication settings.
Follow our detailed PHPMailer Gmail Tutorial that brakes down the steps from installing the PHP dependency manager, Composer to listing the full Gmail SMTP sending script.
Send an email with PHPMailer without SMTP server
An SMTP transport option is the most popular and usable with PHPMailer. However, as we’ve already mentioned, it supports other ways as well.
For localhost, you can use the standard Sendmail program:
// Set mailer with this method
$mailer->isSendmail();
// And send mail as usual
$mailer->send();
If you prefer Unix, then use qmail:
// Set mailer with this method
$mailer->isQmail();
// And send mail as usual
$mailer->send();
Can I send emails without PHPMailer?
If using PHPMailer is not really up your alley, you’re in luck, as there are plenty of other ways to send emails in PHP.
Those of you looking for a fast and hassle-free solution should consider doing the email sending with third-party email services such as Mailtrap Email Sending, which is part of the Mailtrap Email Delivery Platform along with the Email Testing we mentioned earlier.
Mailtrap Email Sending is an end-to-end sending solution perfect for taking control over your email functionality and removing sending issues that might be preventing your emails from reaching recipient inboxes.
How is this possible? Thanks to Email Sending’s actionable analytics features made up of email deliverability alerts, up to 60-day email logs, critical metrics dashboards, and much more.
The dashboards are great for gaining useful insights into the state of your email infrastructure, while the alerts keep you in the know about any deliverability issues that might occur. And if that isn’t enough, you can also count on weekly deliverability performance reports.
Integrating Email Sending into your PHP app is pretty straightforward and only requires you to complete a few simple steps:
- In the Mailtrap dashboard, go to Email Sending-> Sending Domains, add and verify your domain, and then go to API and SMTP Integration.
- Select the API option and mark PHP as your language of choice. This will provide you with a code snippet you should add to your app.
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://send.api.mailtrap.io/api/send',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>'{"from":{"email":"mailtrap@mailtrap.club","name":"Mailtrap Test"},"to":[{"email":"viktoriia.ivanenko@railsware.com"}],"subject":"You are awesome!","text":"Congrats for sending test email with Mailtrap!","category":"Integration Test"}',
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer <your api token>,
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
And voila, you’re all done!
Debugging
If you experience some troubles when sending emails through an SMTP server, the SMTPDebug command will help you explore those errors and find out what should be fixed.
Enable SMTP debugging and set the debug level in your script as follows:
$mail->SMTPDebug = 2;
- level 1 = client; will show you messages sent by the client
- level 2 = client and server; will add server messages, it’s the recommended setting.
- level 3 = client, server, and connection; will add details about the initial information, which might be useful for discovering STARTTLS failures
- level 4 = low-level information.
Use level 3 or level 4 if you are not able to connect at all. Setting level 0 will turn the debugging off, it is usually used for production.
For a better understanding of how debugging in PHPMailer works, let’s review a couple of examples.
Example1. Invalid SMTP hostname
2018-12-12 14:51:32 Connection: opening to mailtrap.io:2525, timeout=10, options=array()
2018-12-12 14:51:42 Connection failed. Error #2: stream_socket_client(): unable to connect to mailtrap.io:2525 (Operation timed out) [/Users/xxxx/Downloads/PHPMailer/src/SMTP.php line 326]
2018-12-12 14:51:42 SMTP ERROR: Failed to connect to server: Operation timed out (60)
2018-12-12 14:51:42 SMTP connect() failed.
Mailer Error: SMTP connect() failed.
For this example, we entered an invalid hostname: mailtrap.io instead of smtp.mailtrap.io. and instantly received a message that an error had occurred at the very first stage of communication with the server.
Example 2. Invalid credentials
2018-12-12 14:49:26 Connection: opening to sandbox.smtp.mailtrap.io:2525, timeout=300, options=array()
2018-12-12 14:49:26 Connection: opened
2018-12-12 14:49:26 SMTP INBOUND: "220 mailtrap.io ESMTP ready"
2018-12-12 14:49:26 SERVER -> CLIENT: 220 mailtrap.io ESMTP ready
...
2018-12-12 14:49:30 SMTP INBOUND: "535 5.7.0 Invalid login or password"
2018-12-12 14:49:30 SERVER -> CLIENT: 535 5.7.0 Invalid login or password
2018-12-12 14:49:30 SMTP ERROR: Username command failed: 535 5.7.0 Invalid login or password
2018-12-12 14:49:30 SMTP Error: Could not authenticate.
2018-12-12 14:49:30 CLIENT -> SERVER: QUIT
2018-12-12 14:49:30 SMTP INBOUND: "221 2.0.0 Bye"
2018-12-12 14:49:30 SERVER -> CLIENT: 221 2.0.0 Bye
2018-12-12 14:49:30 Connection: closed
2018-12-12 14:49:30 SMTP connect() failed.
Mailer Error: SMTP connect() failed.
This example demonstrates where the error occurs: now the SMTP, its hostname, and port are valid but a combination of login and password was not found, so you should double-check and modify your credentials.
There are a couple of detailed articles on GitHub about debugging and troubleshooting, refer to them when you need to dive deeper into these topics.
What else you should know about PHPMailer
In this tutorial we have reviewed the most common PHPMailer use cases: creating HTML emails with images and attachments, sending them via SMTP or localhost to different types of recipients along with debugging options.
If you need more specific examples, have a look at the “examples” folder inside PHPMailer documentation on Github.
Comments
6 replies