End-to-end email testing with testmail.app


While working on MembershipNerd I was looking for a very simple service that would let me write automated, end-to-end tests for sending emails. In particular, I wanted to create an automated test for the sign-up process. By “end-to-end test” I mean that I actually want to send an email, with a real SMTP server, verify that the email has been received by the recipient and contains the correct information.

If I simply wanted to verify that the sign-up triggers an email, then I could use the built-in email service of Django’s testing framework.. If your web framework doesn’t such a convenient way to test email, you might want to have a look at MailHog. Be aware it needs more setup though!

Since I want to make sure that not only does the business logic work correctly, but also verify the correct configuration of all involved services, neither Django’s testing framework nor MailHog will help me.

Basically, I want this to be part of a smoke-test when deploying to production.

Luckily, there are a couple of services that provide this functionality.

The one I settled on for now is testmail.app, because I had an extremely quick onboarding experience that was exactly matching my use case: After logging in, they suggested sending a test-mail to my randomly generated inbox. Next, I was asked to click a link in the browser, which opened a new window and showed the JSON-response I was looking for. The output looked something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
  "result": "success",
  "message": null,
  "count": 1,
  "limit": 10,
  "offset": 0,
  "emails": [
    {
      "cc": "",
      "date": 1633939352000,
      "attachments": [],
      "dkim": "pass",
      "envelope_to": "REDACTED",
      "subject": "Testemail",
      "SPF": "pass",
      "messageId": "REDACTED",
      "to_parsed": [
        {
          "address": "REDACTED",
          "name": ""
        }
      ],
      "oid": "REDACTED",
      "envelope_from": "stefan@ukena.de",
      "cc_parsed": [],
      "namespace": "REDACTED",
      "from": "Stefan Ukena <stefan@ukena.de>",
      "sender_ip": "please see headers",
      "html": "<div dir=\"ltr\">Hi\n",
      "to": "REDACTED",
      "tag": "test",
      "text": "Hi\n",
      "from_parsed": [
        {
          "address": "stefan@ukena.de",
          "name": "Stefan Ukena"
        }
      ],
      "timestamp": 1633939364632,
      "id": "REDACTED",
      "downloadUrl": "https://object.testmail.app/api/REDACTED.eml"
    }
  ]
}

Awesome! Exactly what I was looking for. All of this took probably less than a minute.


See also