Answer
Automating OTP/Email Verification in Cucumber
Strategy Options
| Approach | Reliability | CI-Friendly | Speed |
|---|---|---|---|
| Mailosaur (disposable email API) | High | Yes | Fast |
| MailHog (local SMTP mock) | High | Yes | Fast |
| GreenMail (embedded mail server) | High | Yes | Fast |
| DB query for OTP | High | Yes | Fastest |
| Real email (Gmail API) | Medium | Yes (with OAuth) | Slow |
Recommended: Mailosaur (Best for Staging)
XML
<dependency>
<groupId>com.mailosaur</groupId>
<artifactId>mailosaur-java</artifactId>
<version>7.x</version>
</dependency>
Feature File
Gherkin
@regression @email-verification
Scenario: Register with email OTP verification
Given the user is on the registration page
When the user registers with a unique Mailosaur email
And the OTP is received in the inbox
And the user enters the received OTP on the verification page
Then the user account should be activated
And the welcome email should be received
Step Definitions
Java
package stepDefinitions;
import com.mailosaur.MailosaurClient;
import com.mailosaur.models.*;
public class OtpSteps {
private final ScenarioContext ctx;
private static final String MAILOSAUR_API_KEY = System.getenv("MAILOSAUR_API_KEY");
private static final String MAILOSAUR_SERVER_ID = System.getenv("MAILOSAUR_SERVER_ID");
public OtpSteps(ScenarioContext ctx) { this.ctx = ctx; }
@When("the user registers with a unique Mailosaur email")
public void registerWithMailosaurEmail() throws Exception {
// Mailosaur generates: <anything>@<server-id>.mailosaur.net
ctx.testEmail = "qa-" + System.currentTimeMillis()
+ "@" + MAILOSAUR_SERVER_ID + ".mailosaur.net";
ctx.registrationPage.enterEmail(ctx.testEmail);
ctx.registrationPage.enterPassword("Test@1234");
ctx.registrationPage.clickRegister();
}
@When("the OTP is received in the inbox")
public void waitForOtpEmail() throws Exception {
MailosaurClient mailosaur = new MailosaurClient(MAILOSAUR_API_KEY);
MessageSearchCriteria criteria = new MessageSearchCriteria()
.withSentTo(ctx.testEmail)
.withSubject("Your verification code");
// Wait up to 30 seconds for the email to arrive
Message email = mailosaur.messages().get(
MAILOSAUR_SERVER_ID,
criteria,
new MessageSearchOptions().withTimeout(30000)
);
// Extract OTP from email body (e.g., "Your OTP is: 847291")
String body = email.text().body();
ctx.otp = body.replaceAll(".*Your OTP is: (\\d{6}).*", "$1");
System.out.println("OTP received: " + ctx.otp);
}
@When("the user enters the received OTP on the verification page")
public void enterOtp() {
ctx.driver.findElement(By.id("otp-field")).sendKeys(ctx.otp);
ctx.driver.findElement(By.id("verify-btn")).click();
}
}
Alternative: DB Query for OTP (When DB Access Available)
Java
@When("the OTP is received in the inbox")
public void getOtpFromDatabase() {
// Wait for OTP to be written to DB
String otp = null;
for (int i = 0; i < 30; i++) {
otp = dbUtils.query(
"SELECT otp FROM otp_codes WHERE email = ? AND used = false ORDER BY created_at DESC LIMIT 1",
ctx.testEmail
);
if (otp != null) break;
Thread.sleep(1000);
}
ctx.otp = otp;
}
Alternative: MailHog (Local/Dev Environment)
Bash
# Start MailHog locally or in Docker
docker run -p 1025:1025 -p 8025:8025 mailhog/mailhog
Java
// Query MailHog REST API
Response response = given()
.baseUri("http://localhost:8025")
.when()
.get("/api/v1/messages");
String otp = response.jsonPath().getString("items[0].Content.Body")
.replaceAll(".*OTP: (\\d{6}).*", "$1");
ScenarioContext Fields Needed
Java
public class ScenarioContext {
public WebDriver driver;
public String testEmail;
public String otp;
// ...
}
