How to Test Emails in PHP

When implementing or updating the email sending functionality in your PHP app, you have to run numerous tests to be sure everything works as designed.

What and how should you test? What are the recommended options? Let’s figure it out.

Email testing approach

In the different stages of implementing the email sending functionality, you will need to test several aspects:

  • email script (capability to send emails)
  • email content (which includes multiple checks – from proper headers to the images, links, and mail merge/personalization)
  • email deliverability (spam checks, in particular)

In any framework, the native email testing functionality is limited. Usually, you are able to run simple checks in a development environment. This is why developers usually create numerous scripts and packages to solve this problem. PHP is not an exception.

However, sooner or later, you will face the need to preview your messages and test workflows (in case of triggered emails). In any case, at some point, you will have to to do the following:

  • send and forward test messages to your own email accounts on different clients and check them on all available devices
  • use several third-party email testing apps to perform all the required checks
  • generate fake email addresses to imitate sending to multiple recipients

We believe in a simpler and safer method.

  • During development and testing, run all email checks with Mailtrap. It imitates the work of an SMTP server and catches all your email experiments to display them in its virtual inboxes. In a safe pre-production environment, you will inspect and debug your email template, test your script, mail merge and dynamic content, and you will be able to share your testing results with your team. In addition, you can automate the testing process by integrating Mailtrap via its API.
  • Use SMTP debug and/or logging to check and fix possible sending errors.

Test with Mailtrap

There are a few methods or packages you can use to send emails from your PHP app. PHPMailer, Swift Mailer, and Pear Mail are among the most popular – we have inspected them in the How to Send Emails from PHP? blog post.

You can easily integrate Mailtrap with any of them, in the same way that you would do with any external SMTP server. For this purpose, specify Mailtrap’s SMTP credentials in your transport method:

Host: smtp.mailtrap.io
Port: 25 or 465 or 587 or 2525
Username: unique for each Mailtrap inbox
Password: unique for each Mailtrap inbox
TLS: Optional (STARTTLS on all ports)

To get a username and a password, go to the SMTP settings tab inside your chosen Mailtrap inbox. You will need to create an account if you don’t have one. Registration takes less than two minutes and doesn’t require a credit card as you can start for free.

PHPMailer integration sample:

$mail->isSMTP();
$mail->Host = '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;

Swift Mailer integration sample:

$transport = (new Swift_SmtpTransport('smtp.mailtrap.io', 2525))
  ->setUsername('1a2b3c4d5e6f7g') // generated by Mailtrap
  ->setPassword('1a2b3c4d5e6f7g') // generated by Mailtrap
;
$mailer = new Swift_Mailer($transport);

Pear Mail integration sample:

$host = 'smtp.mailtrap.io';
$username = '1a2b3c4g5f6g7e'; // generated by Mailtrap
$password = '1a2b3c4g5f6g7e'; // generated by Mailtrap
$port = '2525';

Alternatively, you can integrate your app with Mailtrap via its API. For details, please see full Mailtrap API documentation here.

What happens next? As soon as you have integrated Mailtrap, you can run your email script with peace of mind. With any email addresses in To, Cc, and Bcc, all your messages will go to your Mailtrap inbox only.

Image description

That’s great, but what should you do if your message didn’t arrive in the Mailtrap inbox?

Make sure you have enabled exceptions and configured debugging.

PHPMailer: debugging and exceptions

With PHPMailer, you can use the standard exceptions method. Here is a code sample of a simple HTML message:

<?php use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'path/to/composer/vendor/autoload.php';
require 'path/to/PHPMailer/src/Exception.php';
require 'path/to/PHPMailer/src/PHPMailer.php';
require 'path/to/PHPMailer/src/SMTP.php';
$mail->isSMTP();
$mail->Host = 'yoursmtphost';
$mail->SMTPAuth = true;
$mail->Username = 'username';
$mail->Password = 'password'
$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 with exceptions"; $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';

If any error is found, you will get the description in response.

Also, enable SMTP debugging using one of the levels

  • level 1 = client; shows messages sent by the client only
  • level 2 = client and server; adds server messages (recommended)
  • level 3 = client, server, and connection; recommended for exploring STARTTLS failures
  • level 4 = low-level information

Level 3 and 4 are used when you can’t connect.

Level 0 turns the debugging off.

$mail->SMTPDebug = 2;

For example, let’s enter an invalid hostname. As a result, we will get the following messages:

2020-05-12 14:51:32 Connection: opening to mailtrap.io:2525, timeout=10, options=array()
2020--5-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]
2020-05-12 14:51:42 SMTP ERROR: Failed to connect to server: Operation timed out (60)
2020-05-12 14:51:42 SMTP connect() failed.
Mailer Error: SMTP connect() failed.

Pear Mail: Debug

To enable debugging in Pear Mail, set

'debug' => true

(it is false by default). The full message should look like this:

require_once './vendor/autoload.php';
$from = 'Example <example@example.com>';
$to = 'Me <me@gmail.com>';
$subject = 'Debur Pear Mail';
$headers = ['From' => $from,'To' => $to, 'Subject' => $subject];
// include text and HTML versions
$text = 'Hi there, we are checking how debug works in Pear Mail.';
$html = 'Hi there, we are checking how debug works in <br>Pear Mail</br>.';
$mime = new Mail_mime();
$mime->setTXTBody($text);
$mime->setHTMLBody($html);
$body = $mime->get();
$headers = $mime->headers($headers);
$host = 'smtp.mailtrap.io';
$username = '1a2b3c4g5f6g7e'; // generated by Mailtrap
$password = '1a2b3c4g5f6g7e'; // generated by Mailtrap
$port = '2525';
$smtp = Mail::factory('smtp', [
  'host' => $host,
  'auth' => true,
  'username' => $username,
  'password' => $password,
  'port' => $port,
'debug' => true
]);
$mail = $smtp->send($to, $headers, $body);
if (PEAR::isError($mail)) {
    echo('<p>' . $mail->getMessage() . '</p>');
} else {
    echo('<p>Message successfully sent!</p>');
}

Swift Mailer: Debugging

Swift Mailer provides the Logger plugin.

// Create the Mailer using any Transport
$mailer = new Swift_Mailer(
new Swift_SmtpTransport('smtp.example.org', 25)
);
// To use the ArrayLogger
$logger = new Swift_Plugins_Loggers_ArrayLogger();
$mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger));
// Or to use the Echo Logger
$logger = new Swift_Plugins_Loggers_EchoLogger();
$mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger));
// Continue sending as normal
for ($lotsOfRecipients as $recipient) {
...
$mailer->send( ... );
}
// Dump the log contents
// NOTE: The EchoLogger dumps in realtime so dump() does nothing for it
echo $logger->dump();

The code is taken from https://swiftmailer.symfony.com/docs/plugins.html

Hopefully, you have fixed your script and now your test messages are successfully delivered right to the Mailtrap inboxes.

Mailtrap testing functionality

Now you can safely test your email system and message content to make sure that both triggered and mass emails work exactly as expected.

Send your newly designed email template to your Mailtrap inbox. Inspect the following:

  1. Email headers are properly generated. Check From, To, Cc, and Bcc (In Mailtrap, Bcc testing is available in subscription plans for Businesses).
  2. Email content is rendered well. You can see images, links, fonts are correct, HTML markup is fine, proper attachments are added.
  3. HTML & CSS aren’t causing issues across popular email clients (get the list of issues if there are any referred to the appropriate lines of HTML, on the Check HTML tab).
  4. Spam score is not exceeded and your domain is not blacklisted.

Image description

You’ve just made basic email checks. Here’s what you can do with the advanced functionality:

  1. Load test your large email system with the “Email per inbox” feature. It provides you with a customizable email address. It also supports +any_text that provides you with an almost limitless number of test emails. With this feature you can imitate sending messages to multiple different recipients.
  2. You can also integrate your app with Mailtrap API and run integrational or load tests.
  3. Finally, you can easily report to your product owner on the implemented functionality and test results by sharing your Mailtrap projects and/or inboxes.

Once you have verified that every piece of your email sending functionality works exactly as designed, you can switch to production.

With Mailtrap, you can also monitor your production system: put the address of your inbox(-es) to Bcc and instantly receive all messages sent to your users.

Final words

The functionality of PHP email libraries isn’t designed for proper email testing. You should use specialized tools to thoroughly test every aspect of your email workflows. Mailtrap is designed for safe email testing in development and staging environments, and is compatible with any PHP framework (and other frameworks too). It allows you to test email functionality, inspect and debug your templates, run automated tests, and check complex flows.

Thank you for reading our tutorial on testing emails from Localhost in PHP that was originally published on Mailtrap Blog by Diana Lepilkina.