Plus-addressing is supported by all Mailsac inboxes

When you send to any inbox @mailsac.com, if a + plus symbol is included, we remove that symbol and everything after it.

jeff+12345asdf@mailsac.com

will be delivered to

jeff@mailsac.com

Many email services including Gmail, iCloud and Fastmail support stripping the + plus symbol and everything after it in the local-part of the address (everything before the @ symbol).

Plus-addressing has long been a useful feature to segment user accounts across services. At Mailsac we offer a variety of disposable email and forwarding utilities that are designed for software QA engineers and developers. Things like forwarding all messages in a domain to a single address, or automatically routing email to webhooks or slack, are really easy – may not even require DNS setup.

Speed Up Integration Tests Using WebSockets

All the code shown in this article is published at https://github.com/mailsac/mailsac-integration-test-examples

Integration tests identify errors between systems. These tests can be slow to run because of the interactions between multiple systems.

Mailsac can facilitate integration testing between web apps and transactional email services.

This article explains how to use WebSockets to make your email integration tests faster and simpler than with REST API polling.

Explaining the differences: REST APIs vs WebSockets

A REST API call uses a HTTP request for creating, reading, updating, and deleting objects. The HTTP connection between the client and server is short lived. An example of this is the List Messages In Inbox endpoint. The endpoint will return JSON formatted information about email messages in a Mailsac Inbox. Each time a client checks for new messages a new HTTP connection will be used.

A WebSocket is a persistent connection between a client and server providing full-duplex communication. By reusing an established connection there is no need to poll the REST API for changes, instead data can be pushed to the client in real time. WebSockets often listen on port 80/443 but does not use HTTP, except for the initial connection handshake.

REST API Polling Examples

The examples below use the “old way” – hit the Mailsac REST API and “poll” the inbox for new messages.

Polling is reliable and familiar for API programmers.

However, this approach can result in significant delays between when the email was received by Mailsac and when the test checks for a new message. Every few seconds, you ask the server if there are new messages.

Using a Web Socket Instead of Polling

What if the server could notify you that there are new messages? That’s where WebSockets come in.

This code example uses Node.js and Mocha test framework. Portions of the code example are presented below.

Steps to Validate Email Contents Using a WebSocket

Here’s how you can get notified of a new email message:

  1. Establish a WebSocket connection with Mailsac
  2. Send an email using SMTP to a private Mailsac address
  3. Receive content of the email over the established WebSocket
  4. Validate the content of the email
  5. Send a second email using SMTP to a private Mailsac addrress
  6. Receive content of second email over the established WebSocket
  7. Validate the content of the second email
  8. Delete both email messages
  9. Close WebSocket connection

Test Configuration

This test requires several variables be defined. They can be set by editing the script or by setting environment variables.

const mailsacAPIKey = process.env.MAILSAC_API_KEY || ''; // Generated by mailsac. See https://mailsac.com/api-keys
const mailsacToAddress = process.env.MAILSAC_TO_ADDRESS || ''; // Mailsac email address where the email will be sent
const smtpUserName = process.env.SMTP_USER || ''; // Username for smtp server authentication
const smtpPassword = process.env.SMTP_PASSWORD || ''; // Password for smtp server authentication
const smtpHost = process.env.SMTP_HOST || ''; // hostname of the smtp server
const smtpPort = process.env.SMTP_PORT || 587; // port the smtp is listening on

Setup: Configure Mailsac Address for WebSocket Forwarding

The Mailsac address used in this example needs to have WebSocket forwarding enabled on it. Any messages sent to the email address will be forwarded by the Mailsac WebSocket server.

To enable WebSocket forwarding the Mailsac address must be private. Private addresses have additional features such as forwarding to Slack, forwarding to a Webhook, and forwarding to a WebSocket. Select the “Settings” button next to the email address you want to configure from Manage Owned Email Addresses. Select the check box to “Enabled forwarding all incoming email via web socket” and select “Save Settings”.

1. Establish WebSocket Connection

The NPM package ws is a WebSocket client used to connect to the Mailsac WebSocket service.

The Websocket connection to Mailsac is established on lines 12-14. The ws package will only reject a Promise if it fails to connect to the WebSocket server due to a network error. Wrapping the connection in a Promise allows for additional validations.

The Mailsac WebSocket server will send the message ({"status":200,"msg":"Listening","addresses":["example@mailsac.com"]}) after the initial connection. In lines 16-26 the initial message is parsed and checked for value of the property status. The Promise is rejected if the initial status message is not received or does not have a status code of 200.

const mailsacAPIKey = process.env.MAILSAC_API_KEY || ''; // Generated by mailsac. See https://mailsac.com/api-keys
const mailsacToAddress = process.env.MAILSAC_TO_ADDRESS || ''; // Mailsac email address where the email will be sent

describe("send email to mailsac", function () {

  // Open websocket waiting for email. This websocket will be reused for tests in this file.
  before(() => {
    return new Promise((resolve, reject) => {
      ws = new WebSocket(
        `wss://sock.mailsac.com/incoming-messages?key=${mailsacAPIKey}&addresses=${mailsacToAddress}`
      );
      let wsMessage; // message response object
      ws.on("message", (msg) => {
        try {
          wsMessage = JSON.parse(msg);
        } catch {
          assert(wsMessage, "Failed to parse JSON from websocket message");
        }
        if (wsMessage.status != 200) {
          reject(new Error("connection error: " + wsMessage.error));
          return;
        }
        resolve(wsMessage);
      });
      ws.on("error", (err) => {
        reject(err);
      });
    });
  });
});

2. Send email using SMTP

The NPM package nodemailer is used to send a test email via SMTP.

The connection to the STMP server is configured in lines 4-10. Most SMTP servers will require authentication.

The email’s to, from, subject, and content are set in lines 14-18. The email will be sent to the address defined in the configuration at the beginning of the script or the environment variable MAILSAC_TO_ADDRESS. The email will include a link to the website https://example.com.

  it("sends email with link to example.com website", async () => {
    // create a transporter object using the default SMTP transport
    const transport = nodemailer.createTransport({
      host: smtpHost,
      port: smtpPort,
      auth: {
        user: smtpUserName,
        pass: smtpPassword,
      },
    });
    // send mail using the defined transport object
    const result = await transport.sendMail({
      from: smtpUserName, // sender address
      to: mailsacToAddress, // recipient address
      subject: "Hello!",
      text: "Check out https://example.com",
      html: "Check out <a href https://example.com>My website</a>",
    });
  });

3. Receive Message via WebSocket

Once the email arrives, Mailsac will send a JSON formatted version of the email on the WebSocket established earlier in this example. ws.on("message", (msg) => { ... } is a function that will run when new message is sent by the WebSocket server. The msg is parsed as JSON. Then the Promise will resolve if the message has a to property. The existence of the to property is checked to make sure the message sent by the WebSocket server was an email and not a status message. The await keyword will cause the test to wait until a message is sent over the WebSocket or the test times out.

const wsMessage = await new Promise((resolve) => {
  ws.on("message", (msg) => {
    const wsResponse = JSON.parse(msg);
    if (wsResponse.to) {
      resolve(wsResponse);
    }
  });
});

Example JSON formatted message

{

    "status": 200,
    "email": 

{

    "text": "string",
    "body": "string",
    "raw": "string",
    "headers": { },
    "_id": "m3phnJ2ag3example-0",
    "from": 

[

    {
        "name": "string",
        "address": "string"
    }

],
"to": 
[

    {
        "name": "string",
        "address": "string"
    }

],
"cc": 
[

    {
        "name": "string",
        "address": "string"
    }

],
"bcc": 
[

    {
        "name": "string",
        "address": "string"
    }

],
"subject": "string",
"savedBy": "string",
"originalInbox": "string",
"inbox": "user@example.com",
"domain": "example.com",
"received": "1985-04-12T23:20:50.52Z",
"size": 0,
"attachments": 
[

    "5ea9c924627e68f988c9c7ca44340892"

],
"ip": "string",
"via": "string",
"folder": "inbox",
"labels": 
[

    "string"

],
"read": true,
"rtls": true,
"links": 

        [
            "string"
        ],
        "spam": 0.345
    }

}

4. Validate Content of the Email

The assert package is used to validate the contents of the email. The subject and text properties are assigned to new variables. assert.equal(subject, "Hello!"); will cause an exception if subject is not equal to Hello!. The test framework Mocha will interpret this as a failure and the test will fail. Likewise, if the variable email_text is not Check out https://example.com the test will fail.

const subject = wsMessage.subject;
const email_text = wsMessage.text;
assert.equal(subject, "Hello!");
assert.equal(email_text, "Check out https://example.com");

5-7. Send Another Email and Validate Its Content

The reason to send a second email is to demonstrate that the Mailsac WebSocket connection can be reused. This second test will reuse the WebSocket connection established (variable name ws) in the before() block in step 1. The only difference between the first and second test is the content of the email.

// Sends a second email reusing the websocket.
it("sends email with link to unsubscribe.example.com website", async () => {
  const transport = nodemailer.createTransport({
    host: smtpHost,
    port: smtpPort,
    auth: {
      user: smtpUserName,
      pass: smtpPassword,
    },
  });
  const result = await transport.sendMail({
    from: smtpUserName, // sender address
    to: mailsacToAddress, // recipient address
    subject: "Unsubscribe",
    text: "Click the link to unsubscribe https://unsubscribe.example.com",
    html: "Check out <a href https://example.com>My website</a>",
  });

  console.log("Sent email with messageId: ", result.messageId);

  const wsMessage = await new Promise((resolve) => {
    ws.on("message", (msg) => {
      const wsResponse = JSON.parse(msg);
      if (wsResponse.to) {
        resolve(wsResponse);
      }
    });
  });

  assert(wsMessage, "Never received messages!");

  const subject = wsMessage.subject;
  const email_text = wsMessage.text;
  assert.equal(subject, "Unsubscribe");
  assert.equal(
    email_text,
    "Click the link to unsubscribe https://unsubscribe.example.com"
  );
});

8. Delete Emails to Prevent Leaky Tests

An after() block will run after the tests have completed. The REST API Endpoint – Delete All Messages In An In Inbox is called to delete the test emails. By deleting all the test emails, it prevents these emails from being fetched in another test, which could impact the results of another test. It is best practice to clean up tests after they ran.

The NPM package supertest is used to make the REST call to delete the messages. Virtually any HTTP client library could be used to do this. Feel free to use the HTTP client library you feel most comfortable with.

afte(() =>
  request("https://mailsac.com")
    .delete(`/api/addresses/${mailsacToAddress}/messages`)
    .set("Mailsac-Key", mailsacAPIKey)
    .expect(204)
);

9. Close WebSocket Connection

An after() block is used to close the WebSocket connection after all the tests have completed. It is best practice to close all connections on the termination of the test.

// close websocket after all tests finish
after(() => ws.close());

Next Steps

The use of WebSockets helps speed up tests and uses API calls more efficiently.

See the WebSocket Test Page to see a WebSocket in action in your browser. This page includes a basic code example usage ofoffor a WebSocket client and is a great starting point before divining into integration testing using WebSockets.

If you have questions about this example or the Mailsac WebSocket service please post on https://forum.mailsac.com

Using Selenium To Test Account Email Signups

All the code shown in this article is published at
https://github.com/mailsac/selenium-js-example

Selenium and Mailsac can be used to test the delivery and contents of a signup email sent by a web application.

This example will demonstrate how to configure Selenium and provide code examples to automate and integrate testing with Mailsac.

What is Selenium?

Selenium is an automation tool for testing website user interfaces. It is open-source and supports multiple programming languages such as Java, Python, Javascript etc.

Selenium is not a single tool but is composed a several tools. Our example will focus on the WebDriver component. This will allow us to test our application as if a real person were operating the web browser.

Prerequisites

Installing Selenium

The Selenium WebDriver is installed during step 2 by running npm install.

  1. Clone the selenium-js-example repository and change directories to the cloned repository
    git clone https://github.com/mailsac/selenium-js-example.git && cd ./selenium-js-example
  2. Install the Selenium WebDriver by running npm install
  3. Download browser driver for the browser that will be tested (see table for download links).
  4. Place the browser driver in the system PATH
BrowserDriver
Chromechromedriver(.exe)
Internet ExplorerIEDriverServer.exe
EdgeMicrosoftWebDriver.msi
Firefoxgeckodriver(.exe)
Safarisafaridriver

The safaridriver is included with Safari 10 for OSX El Capitan and macOS Sierra. It does require Remote Automation in the Develop Menu to be enabled.

Configure the Browser for Selenium to Use

This example will default to using Firefox. In order to use a different browser set the SELENIUM_BROWSER environment variable.

List of supported SELENIUM_BROWSER values

SELENIUM_BROWSER=chrome
SELENIUM_BROWSER=firefox
SELENIUM_BROWSER=internet_explorer
SELENIUM_BROWSER=safari
SELENIUM_BROWSER=edge
SELENIUM_BROWSER=opera

Web Application Overview

The example web application consists of a single page with a form. The form accepts a username and email address.

Configuring the Web Application

Email will be sent using the Mailsac Outbound Message REST API. You will need to update mailsacAPIKey with your API keymailsacFromAddress is the address that this example will use are the from address.

const mailsacAPIKey = ""; // Generated by mailsac. See https://mailsac.com/api-keys
const mailsacFromAddress = "web-application@mailsac.com";

Manual Test of Email Delivery

To manually test email delivery, launch the example web application by running npm start from the command line. Use a web browser to view http://localhost:3000/index.html

  1. Enter a username and email address.

2. If everything went well you should see a confirmation.

3. Check the inbox of Mailsac address you send to using the form on https://mailsac.com

4. Verify the message you sent has been received.

Automated Testing Using Selenium

To automate UI testing a few different components are required:

  • Selenium WebDriver: Automates input into our web application’s form
  • Mocha: Test framework to run the tests
  • HTTP Requests Module: To interact with the Mailsac API
  • Assert Module: Validates if a given expression is true
  • Webserver: Runs our web application

All of these components are installed when running npm install

Configure Mailsac API Key

To interact with the Mailsac API an API Key is needed. To generate a new API Key sign in to Mailsac and go to the API Keys Page.

An API Key is available for free to all registered users of Mailsac.

Configure the test to work with your API Key by adding it to the following line in ./test/test.js

const mailsacAPIKey = ""; // Generated by mailsac. See https://mailsac.com/api-keys

Run the Test

Before running the tests your Mailsac API key needs to be configured in ./test/test.js and SMTP settings configured in app.js.

The tests can be executed by running npm test from the command line.

npm test

> selenium-tests@1.0.0 test /home/user/repos/selenium-js-example
> mocha



  http-server
    register new user
(node:838754) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
      ✓ sends email with link to example.com website (1383ms)


  1 passing (1s)

The last line in the above code snippet 1 passing (1s) shows our test passed. If the test failed, an error message will be displayed.

If you are using a browser other than Firefox you will need to add an environment variable when running the tests (eg SELENIUM_BROWSER=chrome npm test).

Using Mocha and Selenium to Automate Tests

This section will cover how Mocha and Selenium work together in this code example to test email delivery.

The integration tests are located in ./test/test.js. The tests are written in Mocha, which uses a behavior driver development model. This allows for the description of tests in easy to understand language.

Mocha Test Introduction

In the following example, the describe block includes a description of what is being tested. The it block describes the expected result. assert is used to test the for truth. If the expected statement is not true, there will be an exception, and the test will fail.

describe("tests truth", () => {
    it('true equals true', function() {
        assert(true); // assert checks for truth
    });
    it('false equals false', () => {
        // assert equal checks the first and second parameter are equal
        assert.equal(false,false);
    });
})

Mocha and Selenium

This section is a line by line explanation of the Mocha tests in the example. The code example is available on GitHub.

Mocha is used to call the Selenium WebDriver to perform actions on the example Web Application. The describe block shows we are going to be testing the process of registering a new user. The it block tells us what we expect to happen.

Inside the it block Selenium WebDriver is instructed to:

  • open a web browser using the webapp’s localhost URL
  • find the html element with the id username and enter text in the field
  • find the html element with the id email and enter specified text in the field
  • find the html element with the id submitUserCreation and click on it
it("sends email with link to example.com website", async () => {
  await driver.get(webappUrl);
  await driver.findElement(webdriver.By.id("username")).sendKeys("webdriver", "ExampleUser");
  await driver.findElement(webdriver.By.id("email")).sendKeys("webdriver", signupEmailAddress);
  await driver.findElement(webdriver.By.id("submitUserCreation")).click();
...

Our webapp will then email the address submitted by Selenium.

There is a for loop, following the Selenium commands, that uses the Mailsac API to fetch the mail from the specified email address. If an email isn’t found, it will retry 10 times waiting about 5 seconds between tries.

let messages = [];
for (let i = 0; i < 10; i++) {
   // returns the JSON array of email message objects from mailsac.
   const res = await request("https://mailsac.com")
           .get(`/api/addresses/${signupEmailAddress}/messages`)
           .set("Mailsac-Key", mailsacAPIKey);
   messages = res.body;
   if (messages.length > 0) {
      break;
   }
   await wait(4500);
}

If no messages are received from the Mailsac API after 10 tries, assert will create an exception and throw the error Never received messages!. The contents of the email are checked to see if the link https://example.com is in the email. If, the link is not found, an exception is created stating Missing / Incorrect link in email

assert(messages.length, "Never received messages!");
const link = messages[0].links.find((l) => "https://example.com");
assert(link, "Missing / Incorrect link in email");

Next Steps

This example can be modified to automate your team’s UI testing procedures. For another example of Mocha tests using Mailsac see the Integration Tests Blog Post.

Our forums are a great place to discuss usage of Mailsac’s API.

Github repository for all source code in this example:
https://github.com/mailsac/selenium-js-example

Write Integration Tests Using Mailsac

Mailsac has a REST API that can be leveraged to validate emails are being received with the correct contents. This can be useful for web applications that send customized emails to customers.

This example will demonstrate how to send an email via an SMTP server and validate the email was received. The code used in this example is available on GitHub.

Setup Project Directory

Node version 12 or greater is required for this example due to the use of async and await.

Begin by creating a directory for the project.

mkdir mailsac-tests
cd mailsac-tests
npm init # enter project information, for test command use 'mocha'

Verify package.json looks something like this. The most important part is "scripts": { "test": "mocha" }

{
  "name": "mailsac-integration-tests",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "test": "mocha"
  },
  "author": "",
  "license": "ISC"
}

Installing a Test Framework

The test framework for this example is Mocha. It is a test framework for Javascript applications. A test framework will allow us to write tests against our code.

Setup Test Directory

These directions are inspired by the Mocha Getting Started Guide.

cd mailsac-tests
npm install --save-dev mocha
mkdir test
$EDITOR test/test.js # or open with your favorite editor

Write a Test to Test For Truth

This section is for people who are new to Mocha and test frameworks. Skip ahead if you know how to write tests.

Mocha follows a Behavior Driven Development (BDD) model of testing. This allows for human readable descriptions of software behavior. The first line of the code shows exactly what the following tests will test (ie describe("tests truth"). The following lines state the expected outcome of the test (ie it(true equals true).

This test uses Node’s built in assert. The first parameter passed to assert() is checked for true. If it is true, the assert passes. If the value is false, it throws an exception. In this example, we assert that true is true and that false is equal to false.

Create a describe block in test/test.js
describe("tests truth", () => {
    it('true equals true', function() {
        assert(true); // assert checks for truth
    });
    it('false equals false', () => {
        // assert equal checks the first and second parameter are equal
        assert.equal(false,false);
    });
})

This code can be run and the test should pass. Run the test with npm test . Confirm the test passed.

Congratulations! You have a working test.

Write an Integration Test

In this example, an email will be sent to Mailsac using the ubiquitous Javascript SMTP library NodeMailer, then the test framework will call Mailsac to validate that the email was received.

Install Dependencies

There are a few Node modules that will make sending an email and interacting with the Mailsac REST API easier. NodeMailer will be used to send the email via SMTP. SuperTest will be used to call the Mailsac API.

npm install

Integration Test Example

Back in the text editor, open / create the file test.js in the test folder. Copy and paste the following code or see GitHub for the complete example.

Import required modules
const assert = require("assert");
const nodemailer = require("nodemailer");
const request = require("supertest");
Configure SMTP settings and Mailsac Credentials
// Generated by mailsac. See https://mailsac.com/api-keys
const mailsacAPIKey = "";
// Mailsac email address where the email will be sent
const mailsacToAddress = "example@mailsac.com";
// Username for smtp server authentication
const smtpUserName = "";
// Password for smtp server authentication
const smtpPassword = "";
// hostname of the smtp server
const smtpHost = "";
// port the smtp is listening on
const smtpPort = 587;
Create wait Function

The test will contact the Mailsac API multiple times while waiting for the email to arrive. This function will be used later in a for loop while waiting for the email to arrive.

const wait = (millis) => new Promise((resolve) => setTimeout(resolve, millis));
Add a Describe block with Timeout and Test Cleanup

The describe callback describes in human readable terms what the test is going to do. The increased timeout is required because the default timeout for Mocha is 2 seconds. The test email will likely not arrive that quickly. The afterEach section is used to delete all messages after the test runs. This prevents a leaky test.

describe("send email to mailsac", function () {
  this.timeout(50000); // test can take a long time to run. This increases the default timeout for mocha

  /* delete all messages in the inbox after the test runs to prevent leaky tests.
       This requires the inbox to private, which is a paid feature of Mailsac.
       The afterEach section could be omitted if using a public address
    */
  afterEach(() =>
    request("https://mailsac.com")
      .delete(`/api/addresses/${mailsacToAddress}/messages`)
      .set("Mailsac-Key", mailsacAPIKey)
      .expect(204)
  );
});
Add it block and NodeMailer Configuration

The it interface describes what the test will do "sends email with link to example.com website“. The transport variable is used to store the configuration of the SMTP server.

result = await transport.sendMail({… Attempts to send the email and capture the result.

describe("send email to mailsac", function () {
...

  it("sends email with link to example.com website", async () => {
    // create a transporter object using the default SMTP transport
    const transport = nodemailer.createTransport({
      host: smtpHost,
      port: smtpPort,
      auth: {
        user: smtpUserName,
        pass: smtpPassword,
      },
    });
    // send mail using the defined transport object
    const result = await transport.sendMail({
      from: smtpUserName, // sender address
      to: mailsacToAddress, // recipient address
      subject: "Hello!",
      text: "Check out https://example.com",
      html: "Check out <a href https://example.com>My website</a>",
    });

    // logs the messageId of the email, confirming the
    // email was submitted to the smtp server
    console.log("Sent email with messageId: ", result.messageId);
});
Add Loop to Check Mail

This section of code uses a for loop and a http library (supertest) to check if the message has arrived at Mailsac. The test uses the Mailsac API endpoint /api/addresses/{email}/messages which lists all messages in an inbox.

describe("send email to mailsac", function () {
...

  it("sends email with link to example.com website", async () => {
...
    // Check email in the inbox 10x, waiting 5 secs in between. Once we find mail, abort the loop.
    let messages = [];
    for (let i = 0; i < 10; i++) {
      // returns the JSON array of email message objects from mailsac.
      const res = await request("https://mailsac.com")
        .get(`/api/addresses/${mailsacToAddress}/messages`)
        .set("Mailsac-Key", mailsacAPIKey);

      messages = res.body;
      if (messages.length > 0) {
        break;
      }
      await wait(4500);
    }
  });
});
Add Assertion to Check for Link in the Message

assert is used twice. First, to check to see if any messages were fetched from the Mailsac inbox. This checks the length of the messages array to see if any messages were received. The second assert is used to check for a link to http://example.com .

describe("send email to mailsac", function () {
  // ...
  it("sends email with link to example.com website", async () => {
    // ...
    let messages = [];
    for (let i = 0; i < 10; i++) {
      // ... await get messages from mailsac
    }
    assert(messages.length, "Never received messages!");

    // After a message is retrieved from mailsac, the JSON object is checked to see if the link was parsed from the email and it is the correct link
    const link = messages[0].links.find((l) => "https://example.com");
    assert(link, "Missing / Incorrect link in email");
  });
});
Run Test

At this point the test code is complete and can be run using npm test. If all went well the following output is written to the console.

npm test

Run Test Using GitHub Repository

If you are having some trouble with the tests, I recommend downloading the code from GitHub and running it.

git clone https://github.com/mailsac/mailsac-integration-test-examples.git
cd mailsac-integration-test-examples
npm install
$EDITOR test/test.js # or open with your favorite editor

Edit the test.js and fill in your SMTP settings and Mailsac API key

const mailsacAPIKey = ""; // Generated by mailsac. See https://mailsac.com/api-keys
const mailsacToAddress = "example@mailsac.com"; // Mailsac email address where the email will be sent
const smtpUserName = ""; // Username for smtp server authentication
const smtpPassword = ""; // Password for smtp server authentication
const smtpHost = ""; // hostname of the smtp server
const smtpPort = 587; // port the smtp is listening on

Run test running the command npm test in your terminal.

Next Steps

The example above can be used as part of your team’s quality assurance process. A real world example would be validating password reset links to customers. This test could be used to validate that when a customer requests a password reset an email is sent to them containing the correct password reset link.

If you have any questions about this example or want to talk about other implementations reach out to our community at https://forum.mailsac.com .

Multi-User Login using API Credentials, For Team Collaboration

Update: April 2021 – Multi-User login is now called “Sub-Accounts”

Named API Keys can now be used as website authentication.

Custom domains and Private Addresses have been great for quality assurance teams to conduct end to end automated testing of email. But sometimes interacting with an REST API can be a lot of overhead for non-repeating tasks. API Credentials can now be used to login to the website.

All private addresses and custom domains associated with the primary account will be visible from the website for API users. The permissions for API users are the same as API keys.

Quality assurance teams often share credentials of test accounts for the web application they are testing. These test accounts might to be associated with an email provisioned by their IT department or the QA tester’s personal email. Mailsac private domains allow the test accounts to be created in an an environment all members of the QA team have access to.

This feature allows teams to work together in the Mailsac platform. There is no longer a need to for each person to have their own Mailsac account. A named API Key can be created for each person. That API key can be used to interact with the REST API and the website. As a result, password resets and transaction emails sent to a Mailsac private domain can be accessed by any member of the QA team.

“Internally we have used Mailsac for collaboration. Being able to share a private address or domain allows my team members to see exactly what I am seeing. This feature allows our customers to do the same with their own private domains and addresses” Michael Mayer – Member – Forking Software LLC

Getting started is as easy as provisioning a new set of API credentials and enabling the website login on the API Key. This can be done the the Dashboard and selecting API Credentials & Users

Enable Website Login

We will be rolling this feature out to our Business and Enterprise Plans in the next couple weeks. If you have an immediate need for this feature we can enable it on your account. Contact support@team.mailsac.com to get early access to this feature on you Business or Enterprise Plan.

Using Mailsac for Shared QA Email Accounts

When building software-as-a-service, several pre-production environments are often in play.

Developers, product managers, and QA engineers work together to test software in the various environments.

But there’s confusion around which user accounts can be used in which environments. Which accounts have the right permissions for testing. And your test environments environments don’t map 1:1 with 3rd party services. It’s confusing to know if you tested the right thing.

Mailsac lets you create disposable email accounts within a private custom. Temp email addresses to share with the team. This results in less effort keeping testing environment accounts separate. It prevents user collisions with third party providers.

Common Environment Setup Example

A QA team may have a test environment called “UAT” and developers have a different test environment called “Staging.”

The infrastructure might map to URLs with different subdomains like:

  • uat.example.com – QA team
  • staging.example.com – Developers
  • app.example.com – Production (customers)

where each subdomain has a completely separate database with a users table.

However, our sample app uses a 3rd identity provider (such as Amazon Cognito, Forgerock, Auth0, etc). The identity provider only has two environments:

  • test-identity.example.com – All non-production usage (UAT, Staging)
  • identity.example.com – Production (customers)

Furthermore, our app uses Stripe, which also has only two environments:

  • Stripe Test Mode – All non-production usage (UAT, Staging)
  • Production Mode – Production (customers)

One can imagine a users database table with the following properties:

  • users.id int, primary
  • users.email text, unique
  • users.identity_provider_id text, unique, corresponds to the Identity Provider
  • users.stripe_customer_id text, unique, corresponds to the Stripe Customer ID

Such a setup is common. Problems begin brewing when using the same email address in multiple environments.

Password issues with shared email addresses

A QA person wants to test their app. They sign up with alice@example.com in UAT. alice@example.com was created by a friendly sysadmin at their company. It is a real email inbox. The company has to pay a few bucks per month for the inbox, and it isn’t easily accessible by anybody else. Where’s that password again? Oh you asked Dave from IT to reset the email password? Oh you mean the UAT app password was changed only? The new password should be in a spreadsheet..oops somebody reset it and didn’t update the password? It doesn’t look like I have access to the alice@example.com inbox. Wait a second..the Dev team is also using it?

Identity Provider Clash, Stripe duplicate

UAT person uses alice@example.com and creates the user account with the Identity Provider, linking the identity_provider_id to their user in UAT. They also link the Stripe customer.

idemailidentity_provider_idstripe_id
22alice@example.comidp_q7e4cus_t6n
UAT users table

But then a developer in Staging attempts to perform the action but gets blocked by the identity provider, and duplicates the customer in Stripe with the same email address, making the tracking of financial transactions overly complicated. UAT and Stating also end up with a different user id.

idemailidentity_provider_idstripe_id
19alice@example.comNULL (failed)cus_yb1
Staging users table

It is possible the same password is used for alice@example.com with the identity provider, and both UAT and Development are able to login. But the identity_provider_id will need to be manually set to match both environments, and it will never match the users.id column.

Let’s add one more common layer: role based permissions.

Developer 1 sets up alice@example.com to

These are just a few of the problems with using a limited number of shared credentials for testing software.

Using Mailsac for Test User Accounts

A software team and QA team can share the Mailsac Business account to add nearly unlimited email addresses, and apply special features to up to 50 private address across 5 custom domains (and more via addons). Mailsac allows any custom subdomain of *.msdc.co, it may not even be necessary to involve an IT department to configure DNS.

QA team sets up example-uat.msdc.co.

The QA team will create 10 private addresses with specific purposes such as a user they will configure in uat.example.com with elevated admin permissions:

Next the Dev team, can do something similar but with a different custom domain, and different private email addresses.

Setting up a bunch of private addresses is simple and included with any paid plan. It can help prevent test credential collisions.

Random Inboxes and API Keys

It is not even necessary to setup private addresses, as done above, to receive email.

With a custom domain, any Developer or QA person can send email to any address in the domain without needing to create it first. Then they can check the mail with a personal API key.

The Business Plan allows creating multiple custom API keys:

API Key management in Mailsac

To make a random address, generate a random string:

openssl rand -hex 4 yields de692e19 (for example)

and prefix it to your custom domain:

de692e19@dev-env-sample.msdc.co

Assume Greg’s API key is: wv6OCCXE4svjxuv7sOsCBA (note: never share these!)

He can easily check the inbox using the following URL scheme:
https://mailsac.com/inbox/de692e19@dev-env-sample.msdc.co?_mailsacKey=wv6OCCXE4svjxuv7sOsCBA

Or get messages as JSON:

curl --header 'Mailsac-Key: wv6OCCXE4svjxuv7sOsCBA' https://mailsac.com/api/de692e19@dev-env-sample.msdc.co/messages

which returns an array of messages including any links to be clicked.

[{
  "_id": "m77238f-0",
  "inbox": "de692e19@dev-env-sample.msdc.co",
  "subject": "Confirm your account or something",
  //.........
  "links": ["https://app.example.com/confirm-account/iOZifOYkLX5qFfEo"]
}]

Concluding remarks

We hope this guide provides an overview of how software teams are using Mailsac to simplify testing.

Thousands of enterprises and software project teams use Mailsac to test their environments and manage “known good” test accounts for their SaaS.

Start for free instantly