Email Verification — Gmail helper utility

Lots of applications have a set of processes or operations that include sending emails to customers. This could be related to registration, resetting passwords, or notifications… Sometimes, teams choose to avoid the automation testing of email verifications and stick to testing it manually at the implementation time. This might be a fair choice if the area that is being tested isn’t going to be updated in the future, or isn’t impacting the business progress or success.

To automate or not to automate? Ask yourself the following couple of questions:

  • Is this an important part of the business, would it cost us money if an email wasn’t sent properly, or sent with incorrect contents/links? — Most of the time, the answer is yes.

Automating this test would enable us to validate that multiple systems that integrate together are working properly. For example, the front-end that is requesting the operation, the API/service that is performing the operation of sending an email, the email server setup, the proper links or contents submitted in the emails, etc.

If emails related services are developed/configured internally without integration with a third party, then it’s easier to use tools such as mailhog to perform the testing. Also, it’s faster as you won’t need to use the internet to check the receipt of an email. However, sometimes, we use external services for authentication & authorization (e.g. auth0). In this case, it would be better to use Gmail to test emails, as it might be tricky to expose your mailhog server to the public for it to receive an email from a third party service on the internet.

This post shows how to integrate with Gmail using typescript. This utility can be used when testing email verification.

Pre-requisites

Setup

  • Create a new repository on your local environment and navigate to it: mkdir gmail-helper && cd gmail-helper

* Click the “Download client configuration” button, this will download a credentials.json file, which we will use for authentication

* Copy the credentials.json file to the gmail-helper folder created earlier

  • Copy the example from the quickstart page into a new index.js file in the gmail-helper folder

* In the index.js script, search for the SCOPES array, and change it from ’https://www.googleapis.com/auth/gmail.readonly’ to ’https://mail.google.com/’, which will give full access to the account — Be careful if you’re using this for anything other than testing

* when running this script for the first time it will generate a token.json file, containing the user’s access and refresh tokens; we will use these tokens to perform operations related to the gmail account, such as getting email messages, deleting messages, etc. This means we will only need the index.js file for this first single run only — Check more details in the table below

* Run the script: node index.js

** Navigate to the link returned, and grant access to the application

** A new page opens showing an authorization code. Copy it to the terminal where you ran node index.js

** Notice the token.json file created — The index.js will no longer be needed unless the tokens.js file was deleted, or the user revoked the access granted manually in Google Console.

Make sure not to upload your tokens and credentials to a public repository, as this provides access to anyone to fully control your account.

How does the authorization work?

If you are familiar with how the authorization works you could skip this section (this is an explanation of the steps we’ve done in the setup).

  • Obtain OAuth2.0 client credentials from google console (the same one we got when we enabled the GMAIL API) — ClientId and ClientSecret

* Before our app can access private data using Google API, it must obtain an access token that grants access to that API.

* During this token request process, the application sends one or more values in the scope parameter (the one we updated in the SCOPES array in the setup section). This is mainly our application identifying the permissions it needs. In this step the user also consents to give grant permissions to the gmail account used.

* The Google authorization server sends an authorization code, which the application can exchange for an access token.

* Authorization information is stored on the file system, so subsequent executions will not prompt for authorization.

  • Later when we need to interact with Google API, we rely on this token, which is stored in token.js file in our case

For more information, have a look at https://developers.google.com/identity/protocols/oauth2#webserver

Implementation

  • Create a new file gmailHelper.ts
import * as fs from 'fs';
import * as path from 'path';
import { google } from 'googleapis';
  • The following instructions get the path of credentials.json and tokens.json, and throw an error if they didn’t exist:
const credentialsPath = path.join(__dirname, 'credentials.json');
const tokenPath = path.join(__dirname, 'token.json');

if (!fs.existsSync(credentialsPath) || !fs.existsSync(tokenPath)) {
throw new Error('Could not find credentials.json or token.json in: ' + __dirname + '.
Please follow the steps at https://developers.google.com/gmail/api/quickstart/nodejs to generate them!');
}
  • The following instructions create an OAuth2 client and authorize the user to access the Google APIs:
const credentials = fs.readFileSync(path.resolve(__dirname, credentialsPath), 'utf8');const { client_secret, client_id, redirect_uris } = JSON.parse(credentials).installed;const oauth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);const token = fs.readFileSync(path.resolve(__dirname, tokenPath), 'utf8');oauth2Client.setCredentials(JSON.parse(token));

// set the authentication client at the service-level
const gmail = google.gmail({
version: 'v1',
auth: oauth2Client,
timeout: 10000
})

Now we can start creating functions that enable us to interact with Gmail

  • List the labels
export const listLabels = async () => {
try {
const res = await gmail.users.labels.list({
userId: 'me',
});
return res;
}
catch (e) {
throw new Error('Unable to retrieve the list of email messages: ' + e);
}
};

Let us try it: Add console.log(res); before the return in the listLabel function. Add listLabels(); at the end of the gmailHelper.ts file, and in your terminal run ts-node gmailHelper.ts

  • Get message content
export const getMessageContent = async (id: string) => {
try {
const messageContent = await gmail.users.messages.get({
id,
userId: 'me',
format: 'full'
});
return messageContent;
} catch (e) {
throw new Error('Unable to retrieve message content: ' + e);
}
};

You can use the result of this function to parse the content of the message, and open or verify the link that you need.

These functions can be called in the steps definitions. Check the full source code at: https://github.com/AHaydar/gmail-helper, it contains some additional functions that might be helpful.

Thanks for reading. Please let me know your feedback :)

This post is inspired by the following article written by Angie Jones: http://angiejones.tech/test-automation-to-verify-email/.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store