Email Debugging with MailCatcher

Matthew Setter
Share

You use email in your applications, right? Ok, that’s a rhetorical question. Of course you do. Despite email being over 30 years old, it’s still the most popular application on the planet, by far. Here are some stats from Pingdom, for 2012:

  • 2.2 billion – Number of email users worldwide
  • 144 billion – Total email traffic per day worldwide
  • 4.3 billion – Number of email clients worldwide in 2012

Staggering!

But why another article on email?

For one simple reason, one which we’ve likely all been caught by at one point or another. Because we need to test, as close to production as we can, but without emailing our clients accidentally, and them consequently becoming confused or frustrated, or embarrassed that their clients have received test emails.

I’m sure you know what I mean. You think you’ve set your application in some kind of debug mode. Given that, you start your test, which sends a load of emails from your application. All the while, you feel comfortable in the knowledge that no one but you is ever going to see them.

Your tests pass, you congratulate yourself, and move on. A short time later, you receive a rather, let’s just say terse, Skype call from your client. She’s rather annoyed as her customers have been ringing up, asking why they’ve been receiving odd emails from her company. She’s not happy and wants answers?

Been there? Don’t want to be there again? I’m guessing you don’t. Here’s the solution – MailCatcher. If you’re not familiar with it, MailCatcher

…runs a super simple SMTP server which catches any message sent to it to display in a web interface. Run mailcatcher, set your favourite app to deliver to smtp://127.0.0.1:1025 instead of your default SMTP server, then check out http://127.0.0.1:1080 to see the mail that’s arrived so far.

Sound like a good solution? No matter if you’re tired, under pressure, new on the team, or just need to run tests – MailCatcher will ensure that no email ever gets sent outside of your network, or even outside of your development virtual machine.

In this post, I’m going to show you how to set it up and run through the interface when emails have been captured by it.

A Pre-Prepared Virtual Machine

To save you a lot of trouble of getting MailCatcher set up, I’ve created a custom Vagrant box which does it all for you. Make sure you have VirtualBox and Vagrant installed, then clone a copy of the article’s repository using the following command:

git clone git@github.com:sitepoint-examples/mailcatcher-article.git

Then, in the cloned project directory, run the following command:

vagrant up

This will launch the virtual machine provisioning process, displaying quite a lot of output as the provisioning process runs. The configured virtual machine is quite minimalist. It has MailCatcher, Sendmail and Nginx installed.

Nginx has a simple VHost setup, which maps the project directory to /var/www/ on the virtual machine. If you’d like to know exactly what happens during provisioning, checkout provision.sh.

Manually Installing MailCatcher

If you want to install MailCatcher yourself, and you have a virtual machine (or a Linux machine available), here are the steps to run:

sudo apt-get install -y vim curl python-software-properties lynx nginx
sudo apt-get install -y php5-fpm php5-memcache memcached php-apc
sudo apt-get install -y build-essential libsqlite3-dev ruby1.9.3
sudo gem install mailcatcher
sudo mailcatcher --http-ip 0.0.0.0

You may or may not have to run the third command. I did as I’m using a very minimalist Ubuntu Precise 64 Vagrant image, which needs the packages to build MailCatcher. Please be aware that if you’re on a different Linux distribution or version, the individual package names may be different.

Note: if you follow the standard MailCatcher startup process, it will only listen on IP 127.0.0.1, and port 1025. With this setup we couldn’t see it from the host machine. So I’ve added a public IP on the virtual machine, 192.168.56.111 and changed MailCatcher’s configuration so that it listens on all IPs.

The MailCatcher Web UI

Now you’ll be able to see the MailCatcher web UI at http://192.168.56.111:1080. It will look like the image below:

MailCatcher UI

It’s a pretty simple interface, listing the emails in the MailCatcher queue, when available, at the top. When there are emails in the list, the bottom pane does a good job of showing you information about them, which we’ll see later.

Sample Code

For this article, I’ve created a simple PHP script, index.php, available in the project repository, and accessible at http://192.168.56.111. It uses SwiftMailer to connect to MailCatcher and send an email on load. You can see in the code below a fairly standard HTML page.

<?php require_once('mail-loader.php'); ?>
<html>
<head>
    <title>Simple MailCatcher PHP Example</title>
</head>
<body>
    <h1>Simple MailCatcher PHP Example</h1>
    <p>This application sends a number of emails which will be caught by MailCatcher. To check them, view them in <a href="http://192.168.56.111:1080/" target="_blank">the local MailCatcher installation</a></p>
</body>
</html>

It includes mail-loader.php, which is available below.

<?php
require('vendor/autoload.php');
$email = 'matthew@example.com';
$subject = 'testing';
$message = 'test message';

$transport = Swift_SmtpTransport::newInstance(
    "localhost", 1025
);

$message = Swift_Message::newInstance();
$message->setTo(array(
    "matthew@maltblue.com" => "Matthew Setter",
));
$message->setSubject(
    "This email is sent using Swift Mailer"
);
$message->setBody("You're our best client ever.");
$message->setFrom("matthew@localhost", "Your bank");

$mailer = Swift_Mailer::newInstance($transport);
$mailer->send($message, $failedRecipients);
print_r($failedRecipients);

If you’re not familiar with SwiftMailer Aurelio’s article here on SitePoint provides an excellent introduction. Incidentally, it’s his code I’ve used for this example. Thanks Aurelio.

Basically, there’s only one line that’s important for us to note, which is the following:

$transport = Swift_SmtpTransport::newInstance(
    "localhost", 1025
);

This creates a connection to the MailCatcher server which we’ve just set up. That’s it, nothing fancy! I’ve now reloaded the page three times, which has sent three emails. You can see that they’re listed in MailCatcher in the image below.

MailCatcher UI Showing Mail Content

I’ve clicked on the first entry, which shows the received, from, to and subject details, as well as the body of the email. If we switch to the Source tab, as in the image below, we can see the raw email details:

MailCatcher UI Showing Raw Mail Content

Via the third tab, we can use Fractal to analyse the content of our email. I’ll skip that today as it’s beyond the scope of this article.

We’re All Set

With that done, we can now create emails as we otherwise would, setting recipients, subjects, attachments and so on, like I have above, and know that they will never actually go to the real addresses.

We can write tests to verify that the code works as it should. We can check the mail sending workflow, check message contents, recipients, headers and so forth. It’s as practical as it gets, without actually sending anything outside of our environment.

Now we can rest assured that our clients (and their clients) will never receive any emails that were never intended for them. What a relief.

Wrapping Up

Now, this is a rather trivial example, only using a simple SwiftMailer code snippet for the example. I’m sure that your codebases are much more complex and sophisticated than this example.

But I’m sure that in your applications, you’ll have debug and test configurations available, where you can set the host and port accordingly, differentiating it from live. By doing so, no other code will ever need to change, and you can reap the benefits of the peace of mind MailCatcher brings.

Do you already use MailCatcher? What’s your experience of integrating it? Were there any issues which caught you unaware? Share your thoughts in the comments.