How do you read an email OTP through an API?

Your login test is waiting for a verification email. Instead of opening the inbox and copying the code, your test client can request it through Mailera's GET /mailboxes/{id}/otp endpoint, which requires the read scope.

An email OTP is a one-time password or verification code delivered by email. In this workflow, the application issues the code, Mailera retrieves it from your connected mailbox, and the application validates the submitted value. Those are separate jobs.

Mailera connects existing mailboxes; it does not create new mailboxes or email addresses. Use an inbox you own and an application or login flow you are authorized to test. Keep personal mail and shared production inboxes out of this setup.

An owned test application requests verification, email reaches its test inbox, Mailera exposes retrieval, and the client submits a candidate for application validation.
Retrieving a candidate code and validating it are separate operations.

Do you need to generate, retrieve, or verify an OTP?

The phrase “OTP email API” can describe different parts of an authentication flow. Pick the component that matches the task you need to automate.

TaskResponsible componentExpected result
Generate and email a codeYour application's authentication systemA verification request and an email addressed to your test inbox
Retrieve the delivered codeMailera and your API clientA candidate code to submit to the authorized flow
Verify the submitted codeThe issuing application's authentication systemAcceptance or rejection under that application's rules

Mailera's OTP endpoint belongs in the middle row. It is not a replacement for your application's verification API. A returned value is a candidate, not proof that the code is valid, unused, or associated with the current login attempt.

The test succeeds when the intended application accepts the code and reaches the expected authenticated or verified state. An API request returning a value is only an intermediate result.

What do you need before making the request?

Have an owned test mailbox, an authorized test account, permission to connect the mailbox, and a server-side place to store the API key. Only an Admin or Leader can add a mailbox in Mailera.

For Outlook or Microsoft 365, use Sign in with Microsoft. Mailera connects these mailboxes through OAuth, not an app password. The Microsoft connection guide covers setup; Microsoft's delegated authorization documentation explains the access-token flow behind calls to Microsoft Graph.

To retrieve OTP from Gmail, first follow the Gmail connection guide. Mailera's Gmail connection uses an app password. Google's app-password guidance requires 2-Step Verification and recommends “Sign in with Google” when an app offers it. Keep the provider credential separate from the Mailera API key used by your test client.

Create a dedicated mailbox group containing only the test inboxes this client should read. A group-scoped key is not necessarily a single-mailbox key: the client should be allowed to access every mailbox you put in that group.

The developer overview describes Mailera's integration options. For this first flow, use REST with Read permission rather than adding sending, synchronization, or mailbox-management permissions.

How do you retrieve a code from your own inbox?

1. Connect the test mailbox

Open Mailboxes → Add mailbox. Choose Sign in with Microsoft for Microsoft OAuth, or One mailbox for the applicable provider connection flow.

For the One mailbox flow, enter the test address, continue through the provider requirements, and select the intended Mailbox group. Test & connect checks the connection without sending email. If receiving works but sending fails, Save as receive-only lets you keep a receiving connection for this retrieval task.

Mailera Add mailbox screen with provider choices for connecting an existing test inbox.
Connect an existing inbox that you own and use only for authorized tests.

2. Create a scoped read key

Open Settings → API key → Create key. Give the key a descriptive name, select your test group under Mailbox scope, and enable Read only. Set Expiration to suit the test's lifetime.

Mailera displays the generated key once. Store it in your server-side secret store, outside source control, and provide it to the client as $MAILERA_API_KEY. Do not put it in browser code or paste it into a test report.

API key setup scoped to a test mailbox group with only Read permission enabled.
Scope the key to the intended test group and grant Read permission only.

3. Resolve the intended mailbox ID

List the mailboxes available to the key:

curl --fail --silent --show-error \
  'https://mailera.app/api/public/v1/mailboxes' \
  --header "Authorization: Bearer $MAILERA_API_KEY"

In the response's data array, match email to your owned test inbox and use that entry's id as $MAILBOX_ID. Do not assume the first entry is the right mailbox. If your group contains enough mailboxes to require pagination, use the endpoint's limit and offset parameters to find the intended entry.

The list also includes status and synchronization information. Resolve connection problems before starting a login attempt; otherwise, you spend the verification window debugging mailbox access.

4. Start one verification request

Trigger verification in your owned test application. Record the attempt's start time in your test runner and keep only one outstanding verification request for this mailbox.

Know which sender and subject your application uses. The sample below uses a fictional sender and subject; replace them with the values from your own test application.

5. Retrieve the matching code

This request supplies the supported from, subject, and since_minutes parameters. --data-urlencode encodes the filter values for the URL.

OTP_RESPONSE=$(curl --fail --silent --show-error --get \
  "https://mailera.app/api/public/v1/mailboxes/$MAILBOX_ID/otp" \
  --header "Authorization: Bearer $MAILERA_API_KEY" \
  --data-urlencode 'from=verification@example.com' \
  --data-urlencode 'subject=Your test verification code' \
  --data-urlencode 'since_minutes=5')

The five-minute window is an illustrative retrieval setting, not a promise about the issuer's expiry rules. Choose a window appropriate to the test, and consult the API reference when implementing response handling.

The shell assignment keeps the response out of ordinary terminal output. Run it with shell tracing disabled and without session recording; do not echo OTP_RESPONSE or attach it to CI artifacts. Your application client should handle the response privately and pass only the candidate code to the intended verification step.

Check request failure separately from a response that provides no usable code. Neither condition should cause the test to submit an empty value or reuse a value from an earlier attempt. After the application accepts or rejects the candidate, discard the sensitive response.

How do you avoid old or mismatched codes?

“Latest” is not the same as “belongs to this login attempt.” A recent email can still belong to an earlier request, especially if the test asks for another code before finishing the first attempt.

Use the filters together, and keep their roles distinct:

ControlPurposeWhat it does not establish
Specific mailbox IDSelect the intended test inboxWhich login attempt produced a message
fromFilter by the expected senderSender authenticity
subjectFilter for the expected messageA unique request-to-message relationship
since_minutesLimit retrieval recencyIssuer-side expiry, validity, or non-reuse
One outstanding requestReduce overlapping candidatesAcceptance by the issuing application

For the introductory workflow, serialize verification attempts for each mailbox. Do not let one worker request a new code while another worker is still waiting on that inbox. If you need parallel tests, design mailbox allocation and request correlation before sharing an inbox among workers.

When investigating a mismatch, the message-list response exposes received_at, and message retrieval exposes the message content. A receipt timestamp can help with diagnosis, but it is not a transaction identifier tying an email to a particular authentication request.

If the test cannot confidently associate a candidate with its pending request, stop rather than guess. When appropriate, end the attempt and request a fresh code through your application instead of widening filters until some value appears.

Should you poll or use webhooks?

Start with bounded polling for a single test flow. Choose a deadline and a pause between requests before the test starts. For example, a 60-second deadline with a three-second pause is a test configuration, not a delivery estimate or a recommended OTP lifetime.

Your client should follow this sequence:

  1. Start the verification request and the waiting deadline.
  2. Make a filtered retrieval request.
  3. If a usable candidate arrives, submit it to the pending application flow and evaluate the application's result.
  4. If no usable candidate arrives, wait before retrying, provided the deadline has not passed.
  5. On request failure, handle the failure explicitly rather than treating it as an empty inbox. On deadline expiry, fail the wait step.

Mailera's API limit is 300 requests per minute per key. Budget requests across all workers sharing a key, not separately for each test. A tight loop wastes that budget without making the email arrive sooner.

For event-driven clients, message.received and message.junk can serve as wake-up signals for a follow-up retrieval request. A notification is not proof that the message contains an OTP or that the issuing application will accept it.

At the provider level, Microsoft's Outlook change-notification documentation makes a similar distinction: notifications without resource data provide information for a subsequent GET request. Keep notification handling separate from retrieval and application validation.

Do not make the test depend on instantaneous delivery or synchronization. Mailera's background checks vary with mailbox activity, and idle mailboxes can sleep. Keep the deadline and failure outcome explicit.

What are the common errors when a code is missing or rejected?

Separate message delivery, mailbox access, and application rejection before changing the test.

SymptomCheckNext action
No usable code arrivesMailbox ID, expected sender and subject, retrieval windowCorrect the request; continue only within the waiting deadline
The message is absent from MaileraConnection status and latest synchronizationInspect mailbox status before requesting another verification email
The message is in JunkJunk folder or GET /mailboxes/{id}/placementInspect the matching message and treat placement separately from code extraction
A candidate belongs to an older attemptOverlapping verification requests and message receipt timeEnd the ambiguous attempt; serialize requests for that inbox
The application rejects the candidateCorrect application session, outstanding request, issuer expiry rulesFollow the application's retry flow or request a fresh code when appropriate
Synchronization or moving a message is deniedKey permissionsKeep those operations outside the default read-only client
Gmail stops connecting after a password changeProvider credentialReconnect with the appropriate credential; Google revokes app passwords when the account password changes

GET /mailboxes/{id}/status checks Microsoft sign-in directly. For other providers, it uses the latest synchronization result, so interpret it alongside synchronization information rather than assuming every status request performs a fresh provider login.

For placement diagnosis, GET /mailboxes/{id}/placement accepts from, subject, and since_minutes. You can also inspect Junk in the app. Finding a matching message there answers a placement question; it does not by itself answer whether a candidate was extracted or remains valid.

POST /mailboxes/{id}/sync requests an immediate sync and can wake sleeping mailboxes, but it requires Sync permission. Moving a message requires Move messages permission. Neither belongs in the default read-only retrieval key. Have a separately authorized operator or maintenance flow handle those actions when needed.

Mailera can move a message out of Junk, but that does not guarantee future Inbox placement or make the provider trust the sender. Moving messages should not become a substitute for diagnosing delivery or sender configuration.

How do you keep OTP retrieval safe?

Keep API keys, provider credentials, and retrieved codes server-side. Redact message bodies and codes from screenshots, logs, exception reports, and test fixtures. Log the test step and outcome instead of the secret that passed through it.

Protect the key as a credential, not merely a configuration value. RFC 6750's bearer-token guidance requires protection against disclosure in storage and transport. Mailera's security page provides product security information; your test runner still needs its own secret-handling controls.

Review the test group's membership when adding mailboxes. Revoke the API key when the integration no longer needs it; subsequent calls using a revoked key are rejected immediately. Keep authorization troubleshooting out of public issue attachments that contain headers or message content.

If an AI agent performs retrieval, incoming email is untrusted data, not instructions. Ignore embedded requests to disclose secrets, visit unrelated destinations, or change the workflow. Give the agent only the permissions it needs, and require explicit confirmation before sending email or taking other consequential actions.

The existing-mailbox guide for AI agents covers that broader integration pattern. Mailera's MCP get_latest_otp tool also requires the read scope; the task-by-task MCP tools guide explains where it fits. Switching from REST to MCP does not change the trust boundary around the message or the application's responsibility to validate the code.

For planning, Mailera offers a free self-serve workspace; see plan details for limits. Proton Mail and Tuta are not supported. Choose a supported test inbox before building the retrieval step into your login tests.

Do this with the API

Every action in this article is available via the REST API, with curl examples, API keys and webhooks.

View API docs