Frameworks and toolsCucumberEmail testing

Email testing with Cucumber

Learn how to integrate Mailosaur email testing into Cucumber.

What you’ll find in this guide

  • How to test various aspects of emails
  • Testing links and codes
  • Managing email tests

What you’ll need

Basic usage

To perform email testing with Cucumber, you will:

  1. Send an email message to your Mailosaur inbox (for example, by requesting a password reset).
  2. Write a Gherkin scenario using Given, When, and Then steps, such as: -Connect to the Mailosaur API with the official client library. -Search for the email you sent in step 1.
  3. Verify that the sender is correct.
  4. Implement each Given, When and Then step in code, including assertions.

Cucumber tests are BDD (behavior-driven development) tests and have two parts:

  1. Feature files: These define testing scenarios with Given, When, and Then steps to define the journey being tested.
  2. Step definition files: These contain the code that implements each step from the feature files, including the test setup, actions, and assertions.

Create a scenario in a feature file, replacing "test" with the subject of the email you sent earlier and replacing "Support" with your name and "no-reply@acme.com" with your email address.

Scenario: Basic email usage
    Given the Mailosaur API client is setup for email
    When I search for the "test" email I sent earlier
    Then that email should be sent from "Support" at "no-reply@acme.com"

Next, implement these steps in a step definition file:

Given('the Mailosaur API client is setup for email', function () {
 const apiKey = process.env.MAILOSAUR_API_KEY;
 serverId = process.env.MAILOSAUR_SERVER_ID;

 assert.ok(apiKey, 'MAILOSAUR_API_KEY must be set');
 assert.ok(serverId, 'MAILOSAUR_SERVER_ID must be set');

 mailosaurClient = new MailosaurClient(apiKey);
});

When('I search for the {string} email I sent earlier', async function (subject) {
 const criteria = {
   subject
 };

 message = await mailosaurClient.messages.get(serverId, criteria);

 assert.ok(message, 'Message not found');
});

Then('that email should be sent from {string} at {string}', function (name, emailAddress) {
 assert.strictEqual(message.from[0].name, name, 'Email sender name does not match');
 assert.strictEqual(message.from[0].email, emailAddress, 'Email sender email address does not match');
});
@Given("the Mailosaur API client is setup for email")
public void the_mailosaur_api_client_is_setup() {
   Dotenv dotenv = Dotenv.load();
   String apiKey = dotenv.get("MAILOSAUR_API_KEY");
   serverId = dotenv.get("MAILOSAUR_SERVER_ID");

   assertNotNull("MAILOSAUR_API_KEY must be set", apiKey);
   assertNotNull("MAILOSAUR_SERVER_ID must be set", serverId);
   assertFalse("MAILOSAUR_API_KEY must not be empty", apiKey.isEmpty());
   assertFalse("MAILOSAUR_SERVER_ID must not be empty", serverId.isEmpty());
  
   mailosaurClient = new MailosaurClient(apiKey);
   assertNotNull("Client should be initialized", client);
}

@When("I search for the {string} email I sent earlier")
public void i_search_for_the_email_i_sent_earlier(String subject) throws Exception {
   SearchCriteria criteria = new SearchCriteria().withSubject(subject);
   message = mailosaurClient.messages().get(serverId, criteria);
   assertNotNull("Message not found", message);
}

@Then("that email should be sent from {string} at {string}")
public void that_email_should_be_sent_from_at(String name, String emailAddress) {
   assertEquals(name, message.from().get(0).name());
   assertEquals(emailAddress, message.from().get(0).email());
}
Given('the Mailosaur API key and server ID are set for email test') do
 api_key = ENV['MAILOSAUR_API_KEY']
 @server_id = ENV['MAILOSAUR_SERVER_ID']

 expect(api_key).not_to be_nil, 'MAILOSAUR_API_KEY must be set'
 expect(api_key.strip).not_to be_empty, 'MAILOSAUR_API_KEY must not be empty'

 expect(@server_id).not_to be_nil, 'MAILOSAUR_SERVER_ID must be set'
 expect(@server_id.strip).not_to be_empty, 'MAILOSAUR_SERVER_ID must not be empty'

 @mailosaurClient = Mailosaur::MailosaurClient.new(api_key)
 expect(@client).not_to be_nil
end

When('I search for the {string} email I sent earlier') do |subject|
 criteria = Mailosaur::Models::SearchCriteria.new
 criteria.subject = subject
 @message = @mailosaurClient.messages.get(@server_id, criteria)
 expect(@message).not_to be_nil
end

Then('that email should be sent from {string} at {string}') do |name, email|
 expect(@message.from.first.name).to eq(name)
 expect(@message.from.first.email).to eq(email)
end
@given('the Mailosaur API client is setup for email')
def step_impl(context):
   global apiKey
   global serverId
   global mailosaurClient
   apiKey = os.getenv('MAILOSAUR_API_KEY')
   serverId = os.getenv('MAILOSAUR_SERVER_ID')
   assert apiKey, 'MAILOSAUR_API_KEY environment variable must be set'
   assert serverId, 'MAILOSAUR_SERVER_ID environment variable must be set'
   mailosaurClient = MailosaurClient(apiKey)

@when('I search for the "{subject}" email I sent earlier')
def step_impl(context, subject):
   global message
   criteria = SearchCriteria()
   criteria.subject = subject
   message = mailosaurClient.messages.get(serverId, criteria)
   assert message, 'Message not found'

@then('that email should be sent from "{name}" at "{email}"')
def step_impl(context, name, email):
   assert message.sender[0].name == name, 'Email sender name does not match'
   assert message.sender[0].email == email, 'Email sender email address does not match'
[Given("the Mailosaur API client is setup for email")]
public void GivenTheMailosaurApiClientIsSetupForEmail()
{
   var apiKey = _config["appSettings:MAILOSAUR_API_KEY"];
   serverId = _config["appSettings:MAILOSAUR_SERVER_ID"];

   Assert.NotNull(apiKey);
   Assert.NotNull(serverId);
   Assert.NotEmpty(apiKey);
   Assert.NotEmpty(serverId);

   mailosaurClient = new MailosaurClient(apiKey);
}

[When("I search for the {string} email I sent earlier")]
public void WhenISearchForTheEmailISentEarlier(string subject)
{
   var criteria = new SearchCriteria()
   {
       Subject = subject
   };

   message = mailosaurClient!.Messages.Get(serverId, criteria);

   Assert.NotNull(message);
}

[Then("that email should be sent from {string} at {string}")]
public void ThenTheEmailShouldBeSentFromAt(string name, string emailAddress)
{
   Assert.Equal(name, message!.From[0].Name);
   Assert.Equal(emailAddress, message.From[0].Email);
}

This example will search for the email address that a message was sent to, but you can also search using any of the following criteria:

Parameter Description
sentTo The full email address to which the target message was sent
sentFrom The full email address from which the target message was sent
subject Finds messages where the subject line contains this text
body Finds messages where the message body contains this text

Test email addresses

Each inbox in your account (also known as a server) has a unique identifier, referred to as a Server ID. This ID is used to give your inbox a domain name like this: SERVER_ID.mailosaur.net.

This domain supports a wildcard email pattern, meaning any email address ending with SERVER_ID.mailosaur.net works out of the box.

You don’t need to create email addresses before using them — they just work! However, if you need help thinking of a unique email address, you can use this helper method:

const emailAddress = mailosaurClient.servers.generateEmailAddress("SERVER_ID");

console.log(emailAddress); // "bgwqj@SERVER_ID.mailosaur.net"
String emailAddress = mailosaurClient.servers().generateEmailAddress("SERVER_ID");

System.out.println(emailAddress); // "bgwqj@SERVER_ID.mailosaur.net"
email_address = mailosaurClient.servers.generate_email_address("SERVER_ID")

puts(email_address) # "bgwqj@SERVER_ID.mailosaur.net"
email_address = mailosaurClient.servers.generate_email_address("SERVER_ID")

print(email_address) # "bgwqj@SERVER_ID.mailosaur.net"
var emailAddress = mailosaurClient.Servers.GenerateEmailAddress("SERVER_ID");

Console.WriteLine(emailAddress); // "bgwqj@SERVER_ID.mailosaur.net"

Find an email

When searching for a specific message within your inbox, it’s always better to use messages.get() , as it will automatically wait for messages to arrive and return the full message result.

// Search for the message
const message = await mailosaurClient.messages.get("SERVER_ID", {
  sentTo: "my-test@SERVER_ID.mailosaur.net",
});

console.log(message.html.body);
MessageSearchParams params = new MessageSearchParams();
params.withServer("SERVER_ID");

SearchCriteria searchCriteria = new SearchCriteria();
searchCriteria.withSentTo("test123@SERVER_ID.mailosaur.net");

Message message = mailosaurClient.messages().get(params, searchCriteria);

System.out.println(message.html().body());
criteria = Mailosaur::Models::SearchCriteria.new()
criteria.sent_to = "test123@SERVER_ID.mailosaur.net"

message = mailosaurClient.messages.get("SERVER_ID", criteria)

puts(message.html.body)
criteria = SearchCriteria()
criteria.sent_to = "test123@SERVER_ID.mailosaur.net"

message = mailosaurClient.messages.get("SERVER_ID", criteria)

print(message.html.body)
var criteria = new SearchCriteria() {
    SentTo = "test123@SERVER_ID.mailosaur.net"
};

var message = mailosaurClient.Messages.Get("SERVER_ID", criteria);

Console.WriteLine(message.Html.Body);

Time range for searching

By default, searches only look for messages received in the last hour. To look back further in your message history, set the “received after” parameter.

// Calculate a datetime for yesterday
const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);

// Use this timestamp in the search
const message = await mailosaurClient.messages.get("SERVER_ID", {
  sentTo: "my-test@SERVER_ID.mailosaur.net",
}, {
  receivedAfter: yesterday
});
// Calculate a timestamp for yesterday
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_YEAR, -1);
long yesterday = calendar.getTimeInMillis();

// Use this timestamp in the search
MessageSearchParams params = new MessageSearchParams();
params.withServer("SERVER_ID");
params.withReceivedAfter(yesterday);

SearchCriteria searchCriteria = new SearchCriteria();
searchCriteria.withSentTo("test123@SERVER_ID.mailosaur.net");

Message message = mailosaurClient.messages().get(params, searchCriteria);
# Calculate a datetime for yesterday
yesterday = Date.today - 1

criteria = Mailosaur::Models::SearchCriteria.new()
criteria.sent_to = "test123@SERVER_ID.mailosaur.net"

# Use this timestamp in the search
message = mailosaurClient.messages.get("SERVER_ID", criteria, received_after: yesterday)
# Calculate a datetime for yesterday
yesterday = datetime.today() - timedelta(days=1)

criteria = SearchCriteria()
criteria.sent_to = "test123@SERVER_ID.mailosaur.net"

# Use this timestamp in the search
message = mailosaurClient.messages.get("SERVER_ID", criteria, received_after=yesterday)
// Calculate a datetime for yesterday
var yesterday = DateTime.Today.AddDays(-1);

var criteria = new SearchCriteria() {
    SentTo = "test123@SERVER_ID.mailosaur.net"
};

// Use this timestamp in the search
var message = mailosaurClient.Messages.Get("SERVER_ID", criteria, receivedAfter: yesterday);

“No matching messages” troubleshooting

If you see the error “No matching messages found in time” when searching for messages:

  • Ensure that the target email or SMS message is visible in the Mailosaur Dashboard, as it may not have arrived at all.
  • Check when the message arrived. By default, searches only include messages received within the last hour. See “time range for searching” above on how to override this.
  • Check that you have correctly set the sent to parameter in your search criteria.

List current inbox contents

See a full list of everything currently in your inbox.

// List the most recent messages
const result = await mailosaurClient.messages.list("SERVER_ID");

// Get the most recent message (the first one in the list)
const latestMessage = result.items[0];

// Get the full message object
const message = await mailosaurClient.messages.getById(latestMessage.id);

console.log(message.html.body);
// List the most recent messages
MessageListParams params = new MessageListParams();
params.withServer("SERVER_ID");
MessageListResult result = mailosaurClient.messages().list(params);

// Get the most recent message (the first one in the list)
MessageSummary latestMessage = result.items().get(0);

// Get the full message object
Message message = mailosaurClient.messages().getById(latestMessage.id());

System.out.println(message.html().body());
# List the most recent messages
result = mailosaurClient.messages.list("SERVER_ID")

# Get the most recent message (the first one in the list)
latest_message = result.items[0]

# Get the full message object
message = mailosaurClient.messages.get_by_id(latest_message.id)

puts(message.html.body)
# List the most recent messages
result = mailosaurClient.messages.list("SERVER_ID")

# Get the most recent message (the first one in the list)
latest_message = result.items[0]

# Get the full message object
message = mailosaurClient.messages.get_by_id(latest_message.id)

print(message.html.body)
// List the most recent messages
var result = mailosaurClient.Messages.List(serverId);

// Get the most recent message (the first one in the list)
var latestMessage = result.Items[0];

// Get the full message object
message = mailosaurClient.Messages.GetById(latestMessage.Id);

Searching for multiple messages

Identify if multiple messages meet the same criteria.

// Search for all messages sent to someone@SERVER_ID.mailosaur.net.
// Limit results to the first 10 matches only.
const result = await mailosaurClient.messages.search(
  "SERVER_ID",
  {
    sentTo: "someone@SERVER_ID.mailosaur.net",
  },
  {
    page: 0,
    itemsPerPage: 10,
  }
);

// Get the most recent message (the first one in the list)
const latestMessage = result.items[0];

// Get the full message object
const message = await mailosaurClient.messages.getById(latestMessage.id);

console.log(message.html.body);
// Search for all messages sent to someone@SERVER_ID.mailosaur.net.
SearchCriteria criteria = new SearchCriteria();
criteria.withSentTo("someone@SERVER_ID.mailosaur.net");

// Limit results to the first 10 matches only.
MessageSearchParams params = new MessageSearchParams();
params.withServer("SERVER_ID")
  .withPage(0)
  .withItemsPerPage(10);

MessageListResult result = mailosaurClient.messages().search(params, criteria);

// Get the most recent message (the first one in the list)
MessageSummary latestMessage = result.items().get(0);

// Get the full message object
Message message = mailosaurClient.messages().getById(latestMessage.id());

System.out.println(message.html().body());
# Search for all messages sent to someone@SERVER_ID.mailosaur.net.
criteria = Mailosaur::Models::SearchCriteria.new()
criteria.sent_to = "someone@SERVER_ID.mailosaur.net"

# Limit results to the first 10 matches only.
result = mailosaurClient.messages.search("SERVER_ID", criteria, page: 0, items_per_page: 10)

# Get the most recent message (the first one in the list)
latest_message = result.items[0]

# Get the full message object
message = mailosaurClient.messages.get_by_id(latest_message.id)

puts(message.html.body)
# Search for all messages sent to someone@SERVER_ID.mailosaur.net.
criteria = SearchCriteria()
criteria.sent_to = "someone@SERVER_ID.mailosaur.net"

# Limit results to the first 10 matches only.
result = mailosaurClient.messages.search("SERVER_ID", criteria, page=0, items_per_page=10)

# Get the most recent message (the first one in the list)
latest_message = result.items[0]

# Get the full message object
message = mailosaurClient.messages.get_by_id(latest_message.id)

print(message.html.body)
// Search for all messages sent to someone@SERVER_ID.mailosaur.net
var criteria = new SearchCriteria() {
    SentTo = "someone@SERVER_ID.mailosaur.net"
};

// Limit results to the first 10 matches only.
var result = mailosaurClient.Messages.Search("SERVER_ID", criteria, page: 0, itemsPerPage: 10);

// Get the most recent message (the first one in the list)
var latestMessage = result.Items[0];

// Get the full message object
var message = mailosaurClient.Messages.GetById(latestMessage.Id);

Console.WriteLine(message.Html.Body);

Common test scenarios

Testing basic properties

Once an SMS has been retrieved, test the properties of that text:

// Test sender information
expect(message.from[0].name).toEqual("Support");
expect(message.from[0].phone).toEqual("654321");

// Test recipient information
expect(message.to[0].name).toEqual("John Smith");
expect(message.to[0].phone).toEqual("1234567890");

Testing SMS contents

SMS message content is available via the text.body property:

console.log(message.text.body); // "Hi Jason, ..."

Testing links

Any links in the content of your email are automatically available via the text.links array:

// How many links?
console.log(message.text.links.length); // 2

const firstLink = message.text.links[0];
expect(firstLink.text).toEqual("Google Search");
expect(firstLink.href).toEqual("https://www.google.com/");

Testing verification codes

Codes are automatically extracted from the content of your SMS message. They are available via the text.codes array:

const otp = message.text.codes[0];
expect(otp.value).toEqual("456812");

Replying to an SMS message

If you have a product that handles SMS replies, you can use our reply feature to simulate this. When you reply, the SMS is sent back to the phone number it was originally sent from:

await mailosaur.messages.reply("MESSAGE_ID", {
  text: "FYI",
});
Parameter Description
text Any additional text content to include in the reply
html Any additional HTML content to include in the reply
subject Optionally override the default subject line
attachments Optional attachments (see 'include attachments' above)

Forwarding a message to email

You can forward messages from your Mailosaur account to external email addresses via the creation of automated forwarding rules, or one at a time. Before you can forward messages, you must set up a verified external email address, so you can send email to it:

await mailosaur.messages.forward("MESSAGE_ID", {
  to: "verified-address@example.com",
  text: "FYI",
});
Parameter Description
to The email address to which the message will be sent. Must be a verified email address
text Any additional text content to forward the message with
html Any additional HTML content to forward the message with
subject Optionally override the default subject line

Deleting messages

Deleting an individual message

Permanently deletes a single message and attachments. This operation cannot be undone:

await mailosaur.messages.del("MESSAGE_ID");

Delete all messages

Permanently deletes all messages held in the specified server/inbox. Also deletes any attachments related to each message. This operation cannot be undone:

await mailosaurClient.messages.deleteAll("SERVER_ID");
mailosaurClient.messages().deleteAll("SERVER_ID");
mailosaurClient.messages.delete_all("SERVER_ID")
mailosaurClient.messages.delete_all("SERVER_ID")
mailosaurClient.Messages.DeleteAll("SERVER_ID");

See also

SMS testing guide MFA/2FA guide