We have a test case that needs to receive an email that was generated by our site. We accomplished this using the Gmail Java API described in this tutorial.
Ignore the gradle prerequisite in the tutorial. Do Step 1 as described in the tutorial to create your credentials. Instead of Steps 2 and 3, run your Katalon test using the custom keyword, below. The first time you run it, it will interactively ask you to confirm the permissions tokens by logging onto Gmail and confirming a series of pages. After that, your test will run without being interactive.
We stored the Gmail credentials and permission tokens under the Katalon project Data files:
/Data Files/gmail/credentials.json
/Data Files/gmail/tokens
Below are our custom keywords for clearing out the Inbox at the start of the test, and for checking for an email by subject line.
Note that our logic waits up to 60 seconds for the mail to arrive, checking at 10 second intervals. So far it has been verify effective and reliable.
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.repackaged.org.apache.commons.codec.binary.Base64
import com.google.api.client.repackaged.org.apache.commons.codec.binary.StringUtils
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.GmailScopes;
import com.google.api.services.gmail.model.ListMessagesResponse;
import com.google.api.services.gmail.model.Message;
import com.google.api.services.gmail.model.MessagePartHeader
import com.kms.katalon.core.annotation.Keyword
import com.kms.katalon.core.configuration.RunConfiguration
import com.kms.katalon.core.util.KeywordUtil
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
public class GmailUtil {
private static final int MAX_WAIT_SEC = 60;
private static final String APPLICATION_NAME = "Gmail API Java Quickstart";
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final String USER = "me";
/**
* Global instance of the scopes required by this quickstart.
* If modifying these scopes, delete your previously saved tokens/ folder.
*/
private static final List<String> SCOPES = Collections.singletonList(GmailScopes.MAIL_GOOGLE_COM);
@Keyword
public void deleteAllEmail() {
Gmail service = logonToGmail();
ListMessagesResponse listResponse = service.users().messages().list(USER).execute();
List<Message> messages = listResponse.getMessages();
for (Message message in messages) {
service.users().messages().delete(USER, message.getId()).execute();
}
}
@Keyword
public String getEmailLink(String subjectPrefix) {
Gmail service = logonToGmail();
Message message = getFirstRelevantMessage(service, subjectPrefix);
return parseMessage(message);
}
private Gmail logonToGmail() {
// Build a new authorized API client service.
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
return new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
.setApplicationName(APPLICATION_NAME)
.build();
}
private Message getFirstRelevantMessage(Gmail service, String subjectPrefix) {
int waitSec = 10;
int totalWaitSec = 0;
while(totalWaitSec < MAX_WAIT_SEC) {
ListMessagesResponse listResponse = service.users().messages().list(USER).execute();
List<Message> messages = listResponse.getMessages();
if (messages) {
for(Message message in messages) {
message = service.users().messages().get(USER, message.getId()).execute();
if(isRelevant(service, message, subjectPrefix)) {
return message;
}
}
}
println String.format('No relevant Gmail found, checking again after %d seconds...', waitSec)
WebUI.delay(waitSec);
totalWaitSec += waitSec;
}
KeywordUtil.markErrorAndStop(String.format('No Gmail found after %d seconds with subject %s', totalWaitSec, subjectPrefix))
}
private boolean isRelevant(Gmail service, Message message, String subjectPrefix) {
List<MessagePartHeader> headers = message.getPayload().getHeaders()
for(MessagePartHeader header in headers) {
if('Subject'.equals(header.getName())) {
String subject = header.getValue();
if(subject && subject.startsWith(subjectPrefix)) {
return true;
}
}
}
return false;
}
private String parseMessage(Message message) {
String data = message.getPayload().getBody().getData();
if(data) {
return StringUtils.newStringUtf8(Base64.decodeBase64(data));
}
KeywordUtil.markErrorAndStop(String.format('Gmail no body data, message ID %s'), message.getId())
}
private Credential getCredentials(NetHttpTransport HTTP_TRANSPORT) {
'CAUTION: If you change user scopes, delete the previously saved tokens folder.'
String tokensPath = RunConfiguration.getProjectDir() + '/Data Files/gmail/tokens'
String credentialsPath = RunConfiguration.getProjectDir() + '/Data Files/gmail/credentials.json'
InputStream input = new FileInputStream(new File(credentialsPath))
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(input));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(tokensPath)))
.setAccessType("offline")
.build();
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
}
}