blog
Email Verification Code API for OTP Extraction from Inbound Email
Extract an email OTP with the MailSlurp API, handle missing or ambiguous codes, and use the result to check the complete sign-in flow.
Email verification looks simple from a user perspective: submit an email, receive a code, enter the code, continue.
Automating that journey gets harder when templates change or several numbers appear in the same message. A test needs the code for the current request, not an order number or yesterday's login email.
MailSlurp gives you programmable inboxes plus API endpoints for message retrieval and parsing. For verification code extraction from inbound email, use:
POST /emails/{emailId}/codes
This endpoint extracts a one-time passcode (OTP) from an email that has already arrived. It returns a candidate code and extraction details. Your application issues the code and decides whether it is valid; the test finishes by submitting the extracted value and checking the resulting account state.
Receive the verification email first
Create a MailSlurp inbox and use its address in your application's verification flow. Wait for the delivered email before calling the extraction endpoint; the API needs an existing message ID. The receive-email example shows a bounded message wait, while the Playwright guide carries the extracted OTP back into the browser.
Connect to the code extraction API
MailSlurp API base URL:
https://api.mailslurp.com
Authentication header:
x-api-key: YOUR_API_KEY
Suggested shell setup:
export MAILSLURP_API_KEY="your-mailslurp-api-key"
Match the email to the current request
A typical auth automation flow:
- Trigger signup, login challenge, or password reset in your app.
- Wait for inbound email in a MailSlurp inbox.
- Get the
emailIdfor that message. - Call
/emails/{emailId}/codes. - Check the extraction result, submit the code to your application's verify step, and confirm the correct account is signed in.
Use a fresh inbox for the test or match the message to the specific account and request. "Latest email" in a shared inbox can belong to another test. Keep codes as strings so a value such as 004281 retains its leading zeros.
Set the code extraction options
Supply options that match your application's template. This request allows the service to choose the extraction method and constrains candidates to six characters:
{
"method": "AUTO",
"allowFallback": true,
"minLength": 6,
"maxLength": 6,
"maxCandidates": 5,
"customPatterns": ["verification code[: ]+(\\d{6})"]
}
Choose extraction rules for your template
method: extraction strategy.AUTOlets the service select a method.allowFallback: permits fallback to deterministic pattern extraction when the selected method is unavailable. InspectmethodUsedandwarningsto see what actually ran.minLengthandmaxLength: limit candidates to the lengths your application issues.maxCandidates: keeps output manageable for deterministic assertions.customPatterns: useful when your template phrasing is stable and known. Each regex should capture the code in one group or match the full code directly. Escape backslashes when sending patterns in JSON.
For a stable six-digit template, PATTERN with exact length constraints makes the intended method explicit. AUTO can be useful when you want method selection handled by the service. Selecting LLM or OCR alone does not establish which path ran; check the returned method and fallback notes.
Extract a code with cURL
Set EMAIL_ID to the received message ID from your test, then request its codes:
curl --fail-with-body -sS -X POST "https://api.mailslurp.com/emails/$EMAIL_ID/codes" \
-H "x-api-key: $MAILSLURP_API_KEY" \
-H "content-type: application/json" \
-d '{
"method": "AUTO",
"allowFallback": true,
"minLength": 6,
"maxLength": 6
}'
Use the result in a JavaScript test
Save this helper as extract-code.mjs and import it from your Node.js test. It uses built-in fetch, keeps the code as text, and stops when the API fails or returns ambiguous candidates. Supply the received emailId from the wait step above.
export async function extractSixDigitCode(emailId, {
apiKey = process.env.MAILSLURP_API_KEY,
fetchImpl = fetch,
} = {}) {
if (!apiKey || !emailId) throw new Error("API key and emailId are required");
const response = await fetchImpl(
`https://api.mailslurp.com/emails/${encodeURIComponent(emailId)}/codes`,
{
method: "POST",
headers: { "x-api-key": apiKey, "content-type": "application/json" },
body: JSON.stringify({
method: "PATTERN", allowFallback: false,
minLength: 6, maxLength: 6, maxCandidates: 5,
}),
signal: AbortSignal.timeout(30_000),
},
);
if (!response.ok) throw new Error(`Code extraction HTTP ${response.status}`);
const result = await response.json();
if (result.found !== true || typeof result.code !== "string" ||
!/^[0-9]{6}$/.test(result.code) || !Array.isArray(result.candidates)) {
throw new Error("No usable six-digit code found");
}
const candidates = new Set(result.candidates.map(candidate => candidate.code));
if (candidates.size !== 1 || !candidates.has(result.code)) {
throw new Error("Ambiguous code candidates; inspect the test email");
}
return result.code;
}
After calling const code = await extractSixDigitCode(email.id), submit code through your application's test flow. Avoid printing usable codes or whole email bodies in shared CI logs. For diagnosis, retain the email ID and method details with appropriate access controls.
Read the extraction result
This illustrative response shows the result shape, not a live code or a measured extraction score:
{
"found": true,
"code": "734921",
"methodUsed": "PATTERN",
"candidates": [
{
"code": "734921",
"confidence": 0.95,
"method": "PATTERN",
"source": "RAW_TEXT_PART",
"context": "Your verification code is 734921."
}
],
"warnings": []
}
Use found and candidates to distinguish a missing code from an ambiguous message. Inspect methodUsed and warnings when diagnosing a fallback; a candidate's confidence value does not establish that the application will accept it.
Finish the email OTP verification test
The verification request belongs to your application. Pass the extracted code with the same account and purpose used when requesting it: confirming an email address, signing in and resetting a password may be different operations. Keep the application's response and authenticated session separate from the MailSlurp extraction response.
For example, after requesting email confirmation, submit the received code to that confirmation operation and assert the account's verified state. If the application then requires login, perform it and inspect the expected user. Calling a sign-in operation with the same-shaped code is a different test, even when both accept six digits.
An extracted code is one step in the sign-in journey. The application test should also establish that:
- The code opens the expected test account, not just a generic success page.
- An incorrect code is rejected.
- A used code cannot be used again.
- An expired code fails under the application's actual expiry rule.
- A resend behaves as your product promises, including whether it invalidates the earlier code.
- A code issued for a different purpose or account cannot complete this challenge under your application's policy. Test these with controlled fixtures, not a guessed numeric value that could happen to match.
Use the OTP testing guide for the broader test plan. If copy or languages change, the separate AI email OTP review demonstrates how to check instructions and ambiguity before attempting sign-in.
Diagnose a rejected email OTP
- Wrong numeric token selected: set exact length constraints and add a template-specific pattern.
- Template wording changed:
update
customPatternsand monitorwarningsfor drift signals. - HTTP error: check the API key, message ownership, and response status before interpreting an extraction result. A permission error is not "no code found."
- Correctly formatted code rejected by the app: check the message's account, request, age, and resend history. Extraction does not establish validity.
- Intermittent failures in CI: isolate test inboxes and correlate the message with the request; retain method details without exposing usable codes.
Does extracting a code verify the email address?
It gives your test the code to submit. Your application's successful verification step establishes control of the mailbox for that flow. Checking whether an address can receive mail is a separate task covered by email address verification.
For the browser assertion after extraction, see submitting an email OTP in Playwright.