How to Test Emails in PHP using PHPMailer, Symfony Mailer, and Pear Mailer, and mail() function with Fake SMTP

On July 11, 2024
10min read
Diana Lepilkina Content Specialist @Mailtrap
Veljko Ristić Content Manager @ Mailtrap

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. 

The same goes even if you just want to implement a simple PHP mail function with your contact form on WordPress, or any other framework. 

So, what and how should you test? What are the recommended options? 

Let’s figure it out.

Email testing approach

As indicated, testing email functionality is vital to ensure high deliverability and verify that your content appears correctly across various email clients. 

Typically, testing in PHP can be conducted by sending emails to a local mail server, web server, or utilizing a specialized service like Mailtrap Email Testing.

Of course, I’ll be using Mailtrap, since it offers significant advantages. (Yeah, I’m deliberately tooting our own horn a bit 😀)

For instance, it simulates an SMTP server, capturing all outbound emails in a safe, staging environment. And this setup allows you to: 

  • Inspect email content 
  • Test scripts
  • Ensure that personalization works as intended 
  • Avoid the risk of actual deliveries to real recipients.

To learn more about Mailtrap’s email testing functionalities click here.  

In the next section, I’ll show you how to set up Mailtrap Email Testing, the SMTP method. And later, I’ll cover using Mailtrap PHP SDK for testing, hit the link to jump to the SDK section. 

How to test emails in PHP using Mailtrap Email Testing SMTP

Several methods or packages allow you to send emails from your PHP app. PHPMailer and Symfony Mailer are among the popular options. 

After showing you the integration steps, I’ll discuss them in this article, and offer an exemplary PHP script for each. 

Overall, the integration is straightforward, you do it just as you would with any external SMTP server, like Gmail, for example. 

Basically, specify Mailtrap’s SMTP credentials in your transport method, as shown below, and start testing.

Host: sandbox.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 obtain 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. 

The registration process takes less than two minutes and doesn’t require a credit card; can start for free. 

Here’s the PHPMailer integration sample.

$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;

What happens next? 

As soon as you have integrated Mailtrap, you can run your email script with peace of mind. All your messages with email addresses in the To, Cc, and Bcc fields will go to your Mailtrap inbox only. 

Mailtrap Email Testing HTML preview

Looks 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.

Now, off to the examples of using different PHP frameworks and methodologies. 

How to test emails in PHPMailer?

PHPMailer library provides extensive support for SMTP and is flexible enough to handle various email sending and testing scenarios, be it a Windows, Linux, or any other app. That, of course, includes the PHP function to handle HTML content and attachments. 

As previously mentioned, I’ll be using Mailtrap to test the emails. If you haven’t signed up yet, hit the button below to do it. 

Check the sample setup and debugging methodology below. 

<?php
use PHPMailer\PHPMailer\PHPMailer;

require_once './vendor/autoload.php';

$mail = new PHPMailer();
$mail->isSMTP();
$mail->Host = 'yoursmtphost'; // Typically this will be replaced with your Mailtrap SMTP server details when testing
$mail->SMTPAuth = true;
$mail->Username = 'username'; // Your Mailtrap username
$mail->Password = 'password'; // Your Mailtrap password
$mail->SMTPSecure = 'tls';
$mail->Port = 2525; // Port used by Mailtrap

$mail->setFrom('from@example.com', 'First Last');
$mail->addAddress('towho@example.com', 'John Doe');
$mail->isHTML(true);

$mail->Subject = "PHPMailer SMTP test with exceptions";
$mail->Body = '<div>Mail body in HTML</div>';
$mail->AltBody = 'This is the plain text version of the email content';

if(!$mail->send()){
    echo 'Message could not be sent.' . PHP_EOL;
    echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
    echo 'Message has been sent' . PHP_EOL;
}

// SMTP Debugging levels
$mail->SMTPDebug = 2; // Includes both client and server messages. Adjust as needed for your testing.

In the script, I used the standard exceptions method. If any error is found, you will receive a description in response. 

Also, you should enable SMTP debugging using one of the given levels 

  • level 1 = client; shows messages sent by the client only.
  • level 2  = client and server; adds server messages (recommended, as shown in the script).
  • 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 off debugging. 

$mail->SMTPDebug = 2;

For example, if I enter an invalid hostname. As a result, you 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. 

How to test emails in Symfony Mailer?

Symfony Mailer simplifies sending or testing emails and provides robust debugging and validation tools. To use it, you’ll also need composer, here’s how to run it:

Composer require symfony/mailer

For our purposes, the SentMessage object plays a crucial role by encapsulating the result of the send operation. To be exact, the SentMessage object, obtained from the send() method of the TransportInterface, gives you access to the original message through the getOriginalMessage() method.

This debug info includes all the HTTP calls made, helping you trace any issues with email delivery. If you need more info about the methodology, check the detailed documentation.

Below, I’ll give you the code to use Symfony Mailer with a focus on testing environments. But before that here’s the integration sample to use Mailtrap’s sandbox. 

<?php
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; 
use Symfony\Component\Mime\Email;
require_once './vendor/autoload.php';
$transport = (new EsmtpTransport('sandbox.smtp.mailtrap.io', 2525, false))
                ->setUsername('1a2b3c4d5e6f7g') // generated by Mailtrap
                ->setPassword('1a2b3c4d5e6f7g'); // generated by Mailtrap
$mailer = new Mailer($transport); 

And here’s a simple Symfony testing snippet:

<?php
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;

require_once './vendor/autoload.php';
// Setup transport using Mailtrap for safe email testing
$transport = Transport::fromDsn('smtp://username:password:sandbox.smtp.mailtrap.io:port); // Replace localhost with your Mailtrap DSN
$mailer = new Mailer($transport);

$email = (new Email())
    ->from('hello@example.com')
    ->to('you@example.com')
    ->subject('Time for Symfony Mailer!')
    ->text('Sending emails is fun again!')
    ->html('<p>See Twig integration for better HTML integration!</p>');

try {
    $mailer->send($email);
    echo "Email has been sent successfully!";
} catch (TransportExceptionInterface $e) {
    echo "Failed to send email: " . $e->getMessage();
    // Implement retry logic or log the error for further investigation
}

// Optionally, use debug output from the SentMessage to understand the delivery path
// $debugInfo = $mailer->send($email)->getDebug(); // Uncomment to use this line if needed

To stress, by directing all test emails to Mailtrap, you can safely inspect their content, and headers, and even test different scenarios without the risk of spamming real users. This approach is useful during development stages and can be integrated into your CI/CD pipelines to automate email testing.

How to test emails in PEAR Mailer?

PEAR Mailer is another popular PHP library for sending emails. It provides a range of features to handle various email-sending and testing tasks. And it’s pretty easy to set up and use.

First, install PEAR using the package manager, here’s the snippet:

pear install Mail

Next, I’ll create an email-sending script that will use Mailtrap’s fake SMTP to effectively test the emails. Here’s the example:

<?php
require_once "Mail.php";

// Configuration settings
$config = [
    'host' => 'sandbox.smtp.mailtrap.io',
    'port' => '587',
    'username' => 'your_mailtrap_username',
    'password' => 'your_mailtrap_password',
    'from' => 'from@example.com',
    'to' => 'to@example.com',
    'subject' => 'Test Email from PEAR Mailer',
    'body' => 'This is a test email sent from PEAR Mailer using Mailtrap!'
];

// Headers for the email
$headers = [
    'From' => $config['from'],
    'To' => $config['to'],
    'Subject' => $config['subject']
];

// Create the SMTP object
$smtp = Mail::factory('smtp', [
    'host' => $config['host'],
    'port' => $config['port'],
    'auth' => true,
    'username' => $config['username'],
    'password' => $config['password']
]);

// Send the email
$mail = $smtp->send($config['to'], $headers, $config['body']);

// Check if the email was sent successfully
if (PEAR::isError($mail)) {
    echo 'Email sending failed: ' . $mail->getMessage();
} else {
    echo 'Email sent successfully!';
}
?>

How to test emails using mail()

The quick answer is you don’t test emails using mail(). But let me give you a bit more context and explanations. 

The PHP mail() function provides a straightforward way to send emails. However, it is generally not recommended for production environments due to several significant limitations:

  1. Lack of SMTP authentication: The mail() function doesn’t support SMTP authentication, which is crucial for security and for complying with the policies of many email service providers (no SSL or TLS).
  2. Poor error handling: It provides minimal feedback on email delivery failures, making it difficult to debug and ensure reliable delivery.
  3. Configuration complexity: Proper configuration of the server’s sendmail or postfix system is required, which can be cumbersome and prone to errors.
  4. Limited functionality: mail() lacks support for modern email-sending features such as HTML content, attachments, and custom headers.

So, using a dedicated library like PHPMailer, Symfony Mailer, or even PEAR Mail is generally preferred as they offer more robust features, better security, and improved error handling. The same goes for sending and testing emails. 

You might stumble upon a methodology that tempers with the php.ini trying to muscle in authentication. But the ini file tricks just don’t work since you won’t be able to authenticate the smtp_port, regardless of the PHP version you’re using. 

Email testing with Mailtrap PHP SDK

The official Mailtrap PHP SDK can be installed through the Composer. Note that the SDK is not hard-coupled with any library for HTTP messages, giving you the option to select any HTTP client you’d like to use. 

With that said, we do offer HTTP client recommendations for Symfony and Guzzle. Also, there are Composer packages for Laravel and Symfony to make your life even easier.

Now, before we move onto the nitty-gritty of testing with the PHP SDK, keep in mind that you should autoload all your dependencies via the Composer autoloader. 

Lastly, I assume that you’re already a Mailtrap user and have integrated Mailtrap with your system. 

Pro Tip: Click on the links below to see ready-made code samples. 

  • Attachments – GET single or multiple attachments and catch exceptions
  • Emails – test body, headers, custom variables, and categories of your email message
  • Inboxes – list all inboxes, create new ones, or delete old inboxes. You can also manage an inbox – delete email addresses, reset credentials, mark messages as read, etc. 
  • Messages – GET all messages, or show a specific message. You can also GET the message source, message as an .eml file, HTML message, and more. 
  • Projects – list all your projects, or GET one project and all its inboxes. Also, you can create, delete, or update a project. 

Important Note: You need admin privileges to use Mailtrap Testing API Tokens for the SDKs. Check your Project or Inbox access level at Mailtrap > Settings > API Tokens

Here’s the quick tutorial on how to install and use the PHP SDK. For exemplary purposes, it’s geared towards Symfony. Check the documentation linked above if you’re using a different framework. 

  1. Install the SDK: As indicated, you can do this using Composer:
composer require railsware/mailtrap-php
  1. Include the SDK in your PHP file: Use the require function in PHP as shown below:
require __DIR__ . '/../vendor/autoload.php'; 
  1. Initialize the Mailtrap client: Initialize the Mailtrap client using your Mailtrap API token. Here’s how to do it:
use Mailtrap\Config; 
use Mailtrap\MailtrapSandboxClient;

$apiKey = getenv('MAILTRAP_API_KEY'); 
$mailtrap = new MailtrapSandboxClient(new Config($apiKey));
  1. Compose your email: Now that you have your Mailtrap client ready, you can compose your email using the Symfony Mime components. For example:
use Symfony\Component\Mime\Address;  
use Symfony\Component\Mime\Email; 

$email = (new Email())  
  ->from(new Address('mailtrap@example.com', 'Mailtrap Test'))  
  ->to(new Address('email@example.com', 'Jon'))  
  ->subject('Best practices of building HTML emails')  
  ->text('Hey! Learn the best practices of building HTML emails and play with ready-to-go templates. Mailtrap\'s Guide on How to Build HTML Email is live on our blog')  
  ->html('<html><body><p>Hey! Learn the best practices of building HTML emails and play with ready-to-go templates.</p></body></html>');
  1. Send your email: Once your email is ready, you can send it using the send method of the Mailtrap client. Remember to replace inbox_id with the ID of your Mailtrap inbox.
$response = $mailtrap->emails()->send($email, 'inbox_id');
  1. Inspect the response: After sending the email, you can inspect the response to see if your email was sent successfully:
var_dump($response->getHeaders());
var_dump($response->getStatusCode());
var_dump(ResponseHelper::toArray($response)); 

That’s a basic guide to using the Mailtrap PHP SDK to test emails. Keep in mind that the SDK offers more features than what’s covered in this guide. 

For instance, can add and test additional headers like attachments, custom headers, add custom variables and categories, etc. 

Mailtrap testing functionality explained

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 correctly. You can see images, links, fonts, HTML markup, and attachments are added properly.  
  3. HTML & CSS aren’t causing issues across popular email clients (get the list of issues if there are any, and refer to the appropriate lines of HTML, on the Check HTML tab).
  4. Spam score is not exceeded, and your domain is not blacklisted. 

You’ve just performed 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 and supports +any_text, which provides you with an almost limitless number of test emails. With this feature, you can simulate sending messages to multiple different recipients.
  2. Integrate your app with the Mailtrap API and run integration or load tests. 
  3. 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 by putting the address of your inbox(-es) in Bcc and instantly receiving 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 flow.

PHP related email sending tutorials:

How to Send Emails in PHP?

PHPMailer Guide

How to Send Emails in Symfony with Examples

Article by Diana Lepilkina Content Specialist @Mailtrap
Article by Veljko Ristić Content Manager @ Mailtrap

Linguist by trade, digital marketer at heart, I’m a Content Manager who’s been in the online space for 10+ years. From ads to e-books, I’ve covered it all as a writer, editor, project manager, and everything in between. Now, my passion is with email infrastructure with a strong focus on technical content and the cutting-edge in programming logic and flows. But I still like spreading my gospels while blogging purely about marketing.