Automating Tests with Python

Getting Started

In this guide we’ll be using nose and Mailosaur together to perform automated email testing in Python.

Remember that Mailosaur is language and framework agnostic though, so if you’re using another set up then take a look at our other guides or just get in touch - we’re coders too!

Time to get started! Let’s first install nose and the Mailosaur client library for Python:

pip install nose
pip install mailosaur

Send & Fetch an Email

Create a new folder called test and within it place a blank python file called example.py; this is where we’ll place our sample code.

.
└── test
    └── example.py

Initial code

You can send an email to Mailosaur for testing either via a test email address or by changing your product’s SMTP configuration. Read our guide on sending email for testing for more information.

We’re making the assumption that, because you’re reading an guide on how to perform email testing, you probably know how to send an email. But if you don’t, just check out our guide on sending email via SMTP.

In the code below we skip over how you choose to send an email, because each product is going to be different. But if you need help with this step just get in touch.

from unittest import TestCase
from mailosaur.mailosaur import Mailosaur

client = MailosaurClient("YOUR_API_KEY")

def test_find_single_email(self):
  # At this point you need your code to send an email. You most likely
  # want to do this by triggering an event in your product that causes
  # an email to be sent - for example `my_product.request_password_reset`

  # If you just want to play around for now, you could try Nodemailer.

  criteria = SearchCriteria()
  criteria.sent_to = "someone.SERVER_ID@mailosaur.io"

  email = client.messages.wait_for("SERVER_ID", criteria)

  # Test everything you want to here...
  self.assertEqual("Password reset request", email.subject)

if __name__ == '__main__':
    unittest.main()

What email tests can I perform?

Assuming the code above is working for you, it’s time to get stuck in with some more useful tests.

You will have received an email object, which is documented in our API reference. Using this structure you can perform a wide array of tests, here are some examples to get you started.

Email properties

You can easily test common email properties, such as:

// Who sent the email
self.assertEqual("noreply@company.com", email.sender[0].email)
self.assertEqual("ACME Company", email.sender[0].name)

// To whom was the email addressed
self.assertEqual("john.smith@example.com", email.to[0].email)
self.assertEqual("John Smith", email.to[0].name)

// Any carbon-copies
self.assertEqual("jane.smith@example.com", email.cc[0].email)
self.assertEqual("Jane Smith", email.cc[0].name)

// Any blind carbon-copies
self.assertEqual("aperson@company.com", email.bcc[0].email)
self.assertEqual("Another Person", email.bcc[0].name)

// Email subject line
self.assertEqual("Password reset request", email.subject)

// Was the email was received today?
self.assertEqual(datetime.strftime(datetime.now(), '%Y-%m-%d'), datetime.strftime(email.received, '%Y-%m-%d'))

You can also test email headers via the email.metadata.headers property.

Email content

HTML

If your email contains HTML content, then the email.html.body property will include the full, raw HTML of your email.

You can use this to perform simple checks, such as:

self.assertTrue(email.html.body.contains("<div id="something">"))

However by parsing the HTML you can perform far more detailed HTML testing.

One of the most common end-to-end testing scenarios involving email is the password reset request. This usually involves a product sending a one-time use link via email, which the user must then click.

Mailosaur extracts all links it finds within the HTML body of an email and makes them available via email.html.links:

self.assertEqual(1, len(email.html.links))
self.assertEqual("Set a new password now", email.html.links[0].text)

// Get unique password reset link
var resetLink = email.html.links[0].href;

To complete an end-to-end testing scenario for a password reset you would usually navigate your browser to this link, and complete the remaining UI steps with something like Selenium.

However, if your scenario simply requires a user to click the link (for example in an account verification workflow), you can easily do this as following Python 2.x:

import urllib2

# Verify our account, by 'clicking' the link within the email
urllib2.urlopen(email.html.links[0].href).read()

Or like this in Python 3.x:

import urllib.request

# Verify our account, by 'clicking' the link within the email
urllib.request.urlopen(email.html.links[0].href).read()

Working with images

Just like hyperlinks, Mailosaur extracts any images that it finds within your HTML content:

self.assertEqual(5, len(email.html.images))
self.assertEqual("amazing.png", email.html.images[0].src)
self.assertEqual("A wizard flying a unicorn over a rainbow", email.html.images[0].alt)

Plain Text

The tests above will also work with any plain text content your email contains. Just like HTML content is available via email.html, plain text content is available via email.text.

Working with attachments

The metadata related to any attachments found on the email is available via email.attachments:

self.assertEqual(2, len(email.attachments))

attachment = email.attachments[0]

# A unique identifier for this attachment
self.assertIsNotNone(attachment.id)

# The URL from which this attachment can be downloaded
self.assertIsNotNone(attachment.url)

# Size (in bytes) of the email
self.assertEqual(82138, attachment.length)

# The filename specified when the attachment was sent
self.assertEqual("cat.png", attachment.file_name)

# The file MIME type
self.assertEqual("image/png", attachment.content_type)

You can download attachments either by using the attachment’s url property, or in code via the files API:

file = client.files.get_attachment(attachment.id)

Conclusion

This guide shows you some of the most common approaches to email testing, but we know that every product and project is different. If you can’t find the answer to any question you might have here and would like some help from our team just get in touch!