Delivery Confirmation Example
Consider a scenario, where you have an automated process that sends emails. You may wish to test that this automated process is sending emails and they are being received. Mailsac provides an API so you can check that these emails are being received.
These examples sends emails to mailsac.com using an SMTP server.
Validate receipt using Node.js Javascript.
Full Node.js Example.
const assert = require("assert");
const nodemailer = require("nodemailer");
const request = require("supertest");
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
// Assumes SMTP relay requires authentication
if (mailsacAPIKey == '' || mailsacToAddress == '' || smtpUserName == '' || smtpPassword == '' || smtpHost == '' ) {
throw new Error('Missing required variable')
}
const wait = (millis) => new Promise((resolve) => setTimeout(resolve, millis));
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)
);
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);
// 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);
}
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");
});
});
Validate receipt using Python
""" This script is an example of sending an email via smtp
and confirming its receipt using the mailsac api"""
import time
import sys
import smtplib
import email.utils
import requests
from email.mime.text import MIMEText
"""
Checks if a message from a given address in the a specific mailsac
inbox. If it is it returns when the message was recived, if not it returns
a message stating the message was not received"""
def check_received(receive_address, send_address, base_url, headers):
api_url = '{0}/addresses/{1}/messages'.format(base_url, receive_address)
response = requests.get(api_url, headers=headers)
for message in response.json():
if message['from'][0]['address'] == send_address:
return message['received']
return '{0} has not received an email from {1}'.format(receive_address, send_address)
SMTP_USERNAME = 'mysmtp_user'
SMTP_PASSWORD = 'mysmtp_password'
SMTP_SERVER = 'mysmtp_server.company.com'
SMTP_PORT = 587
FROM_ADDRESS = 'myuser@company.com'
FROM_NAME = 'MyTest User'
SUBJECT = "Testing email to mailsac"
API_TOKEN = 'MY_API_TOKEN_FROM_MAILSAC'
BASE_URL = 'https://mailsac.com/api/'
BODY_TEXT = ("Mailsac SMTP Validate Email Send\r\n"
"This email was sent using the SMTP to test receipt of an email."
)
for x in range(1, 10):
try:
to_address = 'user{}@mailsac.com'.format(x)
msg = MIMEText(BODY_TEXT)
msg['Subject'] = SUBJECT
msg['From'] = email.utils.formataddr((FROM_NAME, FROM_ADDRESS))
msg['To'] = to_address
conn = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
conn.set_debuglevel(True)
conn.ehlo()
conn.starttls()
conn.ehlo()
conn.login(SMTP_USERNAME, SMTP_PASSWORD)
try:
conn.sendmail(FROM_ADDRESS, to_address, msg.as_string())
conn.close()
except Exception as e:
print("Error: ", e)
else:
print("Email Sent!")
except Exception as ex:
print(ex)
time.sleep(30)
for x in range(1, 10):
print(check_received('user{}@mailsac.com'.format(x), send_address=FROM_ADDRESS,
base_url=BASE_URL, headers={'Mailsac-Key': API_TOKEN}))
Validate receipt using Java.
Full Java Example.
package com.mailsac.api;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class AppTest {
// MAILSAC_API_KEY environment variable. Generated by mailsac. See
// https://mailsac.com/api-keys
static String mailsacAPIKey = "";
// MAILSAC_TO_ADDRESS environment variable. Who you're sending an email to.
static String mailsacToAddress = "";
// SMTP_FROM_ADDRESS environment variable. Necessary if you are sending
// through out.mailsac.com (unlikely - you most likely will replace
// sendMail() below.
static String fromAddress = "";
// SMTP_USERNAME environment variable. Required for authenticated SMTP sending
static String smtpUserName = "";
// SMTP_PASSWORD environment variable. Required for authenticated SMTP sending
static String smtpPassword = "";
// SMTP_HOST environment variable. Hostname of your SMTP server
static String smtpHost = "";
// SMTP_PORT environment variable. Port used for SMTP sending
static int smtpPort = 587;
@BeforeAll
static void setup() throws Exception {
mailsacAPIKey = System.getenv().get("MAILSAC_API_KEY");
mailsacToAddress = System.getenv().get("MAILSAC_TO_ADDRESS");
fromAddress = System.getenv().get("SMTP_FROM_ADDRESS");
smtpUserName = System.getenv().get("SMTP_USERNAME");
smtpPassword = System.getenv().get("SMTP_PASSWORD");
smtpHost = System.getenv().get("SMTP_HOST");
if (System.getenv().get("SMTP_PORT") != null) {
Integer.parseInt(System.getenv().get("SMTP_PORT"));
}
if (mailsacAPIKey == null || mailsacToAddress == null || fromAddress == null) {
throw new Exception("Missing environment variable setup!");
}
if (smtpUserName == null || smtpPassword == null || smtpHost == null) {
throw new Exception("Missing SMTP environment variables");
}
System.out.println(mailsacAPIKey);
System.out.println(mailsacToAddress);
System.out.println(fromAddress);
}
// This is an example of sending email. Mailsac will accept SMTP traffic
// sent from anywhere - even your computer. In your environment, you're
// likely using an email relay already, so you can replace this method with your
// outbound
// email sending code.
static void sendMail(String subject, String textMessage, String htmlMessage)
throws UnsupportedEncodingException, MessagingException {
Session session = Session.getDefaultInstance(new Properties());
javax.mail.Transport transport = session.getTransport("smtp");
MimeMessage msg = new MimeMessage(session);
// set message headers
msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
msg.addHeader("format", "flowed");
msg.addHeader("Content-Transfer-Encoding", "8bit");
msg.setFrom(fromAddress);
msg.setReplyTo(InternetAddress.parse(fromAddress));
msg.setSubject(subject, "UTF-8");
msg.setText(textMessage, "UTF-8");
msg.setContent(htmlMessage, "text/html");
msg.setSentDate(new Date());
msg.setRecipients(Message.RecipientType.TO, mailsacToAddress);
msg.saveChanges();
System.out.println("Email message is ready to send");
transport.connect(smtpHost, smtpPort, smtpUserName, smtpPassword);
transport.sendMessage(msg, msg.getAllRecipients());
System.out.println("Email sent successfully");
}
@BeforeEach
@AfterEach
// purgeInbox cleans up all messages in the inbox before and after running each
// test,
// so there is a clean state.
void purgeInbox() throws UnirestException, JsonProcessingException {
HttpResponse<String> response = Unirest
.get(String.format("https://mailsac.com/api/addresses/%s/messages", mailsacToAddress))
.header("Mailsac-Key", mailsacAPIKey)
.asString();
// Parse JSON
ObjectMapper objectMapper = new ObjectMapper();
Object[] messagesArray = objectMapper.readValue(response.getBody(), Object[].class);
for (int i = 0; i < messagesArray.length; i++) {
JsonNode m = objectMapper.convertValue(messagesArray[i], JsonNode.class);
String id = m.get("_id").asText();
System.out.printf("Purging inbox message %s\n", id);
Unirest.delete(String.format("https://mailsac.com/api/addresses/%s/messages/%s", mailsacToAddress, id))
.header("Mailsac-Key", mailsacAPIKey)
.asString();
}
}
@Test
void checkEmailWithLink() throws MessagingException, UnirestException, IOException, InterruptedException {
sendMail("Hello!", "Check out https://example.com", "Check out <a href='https://example.com'>My website</a>");
// Check inbox for the message up to 10x, waiting 5 seconds between checks.
found: {
for (int i = 0; i < 10; i++) {
// Send request to fetch a JSON array of email message objects from mailsac
HttpResponse<String> response = Unirest
.get(String.format("https://mailsac.com/api/addresses/%s/messages", mailsacToAddress))
.header("Mailsac-Key", mailsacAPIKey)
.asString();
// Parse JSON
ObjectMapper objectMapper = new ObjectMapper();
Object[] messagesArray = objectMapper.readValue(response.getBody(), Object[].class);
System.out.printf("Fetched %d messages from Mailsac for address %s\n", messagesArray.length,
mailsacToAddress);
eachMessage: {
for (int m = 0; m < messagesArray.length; m++) {
// Convert object into JSON to fetch a field
JsonNode thisMessage = objectMapper.convertValue(messagesArray[m], JsonNode.class);
// After a message is found, the JSON object is checked to see if the link was
// sent correctly
assertTrue(thisMessage.get("links").toString().contains("https://example.com"),
"Missing / Incorrect link in email");
System.out.printf("Message id %s contained the correct link\n",
thisMessage.get("_id").asText());
return; // end the tests
}
}
System.out.println("Message not found yet, waiting 5 secs");
Thread.sleep(5000);
}
// Fail the test if we haven't reached assertTrue above
fail("Never received expected message!");
}
}
}