---
title: "OTP email API: retrieve a code from your own test inbox"
description: "Retrieve email verification codes from an owned test inbox with Mailera's API. Use read-only access, sender filters, bounded polling, and safe failure handling."
url: https://mailera.app/en/blog/otp-email-api-test-inbox
published: 2026-10-25
updated: 2026-10-25
---

# OTP email API: retrieve a code from your own test inbox

Read a delivered verification code from an existing mailbox with a scoped API key. Keep retrieval separate from validation, and stop the test when the result is missing or ambiguous.

## 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](https://mailera.app/en/product); 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.](https://mailera.app/media/f34f649346c1e316/otp-email-api-retrieve-a-code-from-your-own-test-inbox-otp-en-1200.jpg)
_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.

| Task | Responsible component | Expected result |
| --- | --- | --- |
| Generate and email a code | Your application's authentication system | A verification request and an email addressed to your test inbox |
| Retrieve the delivered code | Mailera and your API client | A candidate code to submit to the authorized flow |
| Verify the submitted code | The issuing application's authentication system | Acceptance 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](https://mailera.app/en/providers/microsoft) covers setup; Microsoft's [delegated authorization documentation](https://learn.microsoft.com/en-us/graph/auth-v2-user) explains the access-token flow behind calls to Microsoft Graph.

To retrieve OTP from Gmail, first follow the [Gmail connection guide](https://mailera.app/en/providers/gmail). Mailera's Gmail connection uses an app password. Google's [app-password guidance](https://support.google.com/accounts/answer/185833) 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](https://mailera.app/en/developers) 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.](https://mailera.app/media/d8e9591c875d36fe/email-app-passwords-connect-your-mailbox-to-an-ai-agent-add-en-1200.jpg)
_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.](https://mailera.app/media/047ef7ca00571d35/email-human-in-the-loop-an-approval-workflow-for-ai-agents-en-1200.jpg)
_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:

```bash
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.

```bash
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](https://mailera.app/en/docs) 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:

| Control | Purpose | What it does not establish |
| --- | --- | --- |
| Specific mailbox ID | Select the intended test inbox | Which login attempt produced a message |
| `from` | Filter by the expected sender | Sender authenticity |
| `subject` | Filter for the expected message | A unique request-to-message relationship |
| `since_minutes` | Limit retrieval recency | Issuer-side expiry, validity, or non-reuse |
| One outstanding request | Reduce overlapping candidates | Acceptance 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](https://learn.microsoft.com/en-us/graph/outlook-change-notifications-overview) 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.

| Symptom | Check | Next action |
| --- | --- | --- |
| No usable code arrives | Mailbox ID, expected sender and subject, retrieval window | Correct the request; continue only within the waiting deadline |
| The message is absent from Mailera | Connection status and latest synchronization | Inspect mailbox status before requesting another verification email |
| The message is in Junk | Junk folder or `GET /mailboxes/{id}/placement` | Inspect the matching message and treat placement separately from code extraction |
| A candidate belongs to an older attempt | Overlapping verification requests and message receipt time | End the ambiguous attempt; serialize requests for that inbox |
| The application rejects the candidate | Correct application session, outstanding request, issuer expiry rules | Follow the application's retry flow or request a fresh code when appropriate |
| Synchronization or moving a message is denied | Key permissions | Keep those operations outside the default read-only client |
| Gmail stops connecting after a password change | Provider credential | Reconnect 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](https://www.rfc-editor.org/info/rfc6750/) requires protection against disclosure in storage and transport. Mailera's [security page](https://mailera.app/en/security) 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](https://mailera.app/en/blog/email-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](https://mailera.app/en/blog/mailera-mcp-tools) 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](https://mailera.app/en/pricing) 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](https://mailera.app/en/docs)
