API для отримання коду з пошти: приклад на Python для тестів

Щоб отримати код підтвердження з пошти в скрипті на Python, достатньо трьох HTTP-запитів: орендувати скриньку, опитувати замовлення, доки не з'явиться код, і скасувати замовлення, якщо чекати більше не хочете. Нижче — робочий приклад саме такого сценарію з бібліотекою requests і стандартною бібліотекою, на справжньому API OTPGmail.

Типовий читач цього посібника — розробник чи QA-інженер, якому треба автоматично пройти реєстрацію з підтвердженням пошти: у тестах, у CI чи під час перевірки власної форми. Скринька тут справжня — @gmail.com або @icloud.com, тож сайти сприймають її як звичайну адресу.

Що має робити скрипт

Кожен акаунт OTPGmail має власний ключ API на сторінці «Акаунт»; передавайте його в заголовку Authorization: Bearer <ключ_API>. Увесь сценарій такий:

  1. POST /v1/orders — орендувати адресу для конкретного сервісу.
  2. GET /v1/orders/{orderId} кожні кілька секунд, доки в полі otp не з'явиться запис.
  3. POST /v1/orders/{orderId}/cancel, якщо чекати більше не хочете: доки код не надійшов, кошти повертаються повністю.

Навіть якщо нічого не робити, замовлення без коду скасується автоматично й поверне кошти через 25 хвилин, тож третій крок — це ввічливість, а не обов'язок.

Ключ не варто зберігати в коді: читайте його зі змінної середовища, як у прикладах нижче.

Оренда скриньки

import os
import uuid
import requests

HOST = "otpgmail.net"
HEADERS = {"Authorization": f"Bearer {os.environ['OTPGMAIL_API_KEY']}"}


def rent(service, domain="gmail.com"):
    resp = requests.post(
        f"https://{HOST}/v1/orders",
        json={"service": service, "domain": domain},
        headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
        timeout=15,
    )
    body = resp.json()
    if not body.get("success"):
        raise RuntimeError(body["error"]["code"])
    return body["data"][0]  # data — список, по одному запису на кожну скриньку

Параметр domain необов'язковий, типово це gmail.com; передайте "icloud.com", якщо сервіс його пропонує — iCloud зазвичай дешевший за Gmail, залежно від сервісу. Заголовок Idempotency-Key важливіший, ніж здається: створюйте новий UUID для кожного нового замовлення, а якщо запит обірвався за тайм-аутом, повторіть його з тим самим ключем — API поверне вже створене замовлення замість того, щоб списати кошти вдруге.

Використовуйте requests, а не urllib зі стандартної бібліотеки: його типовий user agent Python-urllib CDN перед API відхиляє з помилкою HTTP 403.

Очікування коду

import time


def wait_for_code(order_id, max_wait=600, interval=4):
    deadline = time.time() + max_wait
    while time.time() < deadline:
        resp = requests.get(f"https://{HOST}/v1/orders/{order_id}", headers=HEADERS, timeout=15)
        order = resp.json()["data"]
        if order["otp"]:
            return order["otp"][-1]["code"]  # найновіший код — останній
        if order["status"] == "cancelled":
            return None
        time.sleep(interval)
    # Здаємося раніше за тайм-аут API — скасовуємо, щоб одразу повернути кошти
    requests.post(f"https://{HOST}/v1/orders/{order_id}/cancel", headers=HEADERS, timeout=15)
    return None

Інтервал 3–5 секунд — золота середина: достатньо часто, щоб не гальмувати тест, і достатньо рідко, щоб не перевищити ліміт запитів. Список otp упорядкований від найстарішого, тож otp[-1] — завжди найновіший код. Це знадобиться, якщо те саме замовлення згодом отримає другий код (вхід, підтвердження пристрою), поки ще може приймати листи — діють ліміт кодів сервісу й вікно джерела.

Збираємо все разом

try:
    order = rent("git", domain="icloud.com")
except RuntimeError as e:
    if str(e) in ("DOMAIN_UNAVAILABLE", "NO_MAILS_AVAILABLE"):
        order = rent("git", domain="gmail.com")  # запасний варіант — Gmail
    else:
        raise

print("Адреса:", order["email"])
# ...тут ваш тест заповнює форму реєстрації адресою order["email"] і надсилає її...
code = wait_for_code(order["orderId"])
print("Код:", code or "не надійшов")

git — код сервісу GitHub із GET /v1/services; замініть його на код іншого сервісу, щоб тестувати іншу реєстрацію. Заповніть форму сервісу адресою order["email"], надішліть її і лише тоді починайте опитування — до відправлення форми коду ще не існує.

Обробка помилок

rent() кидає виняток, коли success дорівнює false. Перехоплюйте конкретні коди помилок, а не всі винятки поспіль, щоб скрипт реагував осмислено:

Ліміти запитів, повна таблиця помилок і структура відповідей — у документації API.

У тестах: pytest, Playwright, Cypress

У наборі автотестів оренду зручно винести у фікстуру: вона орендує скриньку перед тестом і скасовує замовлення в teardown, якщо код так і не знадобився. Для паралельного запуску кожен тест отримує власну адресу, а Idempotency-Key захищає від подвійної оренди під час повторних спроб. Якщо браузерну частину пише Playwright чи Cypress, логіка та сама: тест заповнює форму, а окремий крок опитує API й вставляє код у поле підтвердження.

Кілька практичних порад:

Коли код не надходить навіть у ручному режимі, причина зазвичай на боці сайту — капча чи перевірка ризиків. Перелік причин — у посібнику не приходить код підтвердження на пошту. Чим відрізняються скриньки двох типів, пояснює Gmail чи iCloud для кодів підтвердження.

Тестові акаунти створюйте для перевірки власних продуктів або там, де це дозволяють умови платформи.

Поширені запитання

Навіщо запиту заголовок Idempotency-Key?

Щоб повторний запит після обірваного з'єднання не орендував другу скриньку. Використовуйте той самий UUID лише для повтору того самого замовлення, а для кожного нового — новий.

Яким має бути max_wait?

Залежить від сервісу: у GitHub типовий час очікування — приблизно 1 хвилина, у ChatGPT — приблизно 1 хвилина, а іноді й довше. Більше ніж 25 хвилин ставити немає сенсу: після цього API однаково скасує замовлення без коду й поверне кошти.

Чи можна орендувати кілька скриньок одним запитом?

Так, полем quantity у тілі запиту (типово 1, до 200). Тоді data містить по запису на кожну скриньку, а не лише data[0].

Що поверне order["otp"][-1]["code"], поки коду немає?

IndexError, бо до першого коду otp — порожній список. Саме тому wait_for_code спершу перевіряє if order["otp"]:.

Схожі посібники

Отримайте код підтвердження просто зараз

Реєстрація нічого не коштує. Кошти списуються лише тоді, коли скриньку видано; немає коду за 25 хвилин — 100% коштів повертається автоматично.

Не знайшли потрібний сервіс? Натисніть Додати сервіс на сторінці оренди, і ми додамо його, якщо це дозволяє наша інфраструктура.

Потрібен акаунт Gmail, до якого можна увійти, а не лише код? Дивіться купівлю короткочасного Gmail · Повернення коштів і гарантія