API для получения кода из почты: пример на Python

Чтобы получить код из письма в Python-скрипте, нужны три HTTP-запроса к API OTPGmail: создать заказ и получить адрес, опрашивать заказ, пока не появится код, и отменить заказ, если код больше не нужен. Ниже — готовый код на requests, разбор ошибок и пример фикстуры для автотестов.

Это не Gmail API от Google: вы не работаете со своим ящиком через OAuth, а арендуете настоящий адрес @gmail.com или @icloud.com, и сервис сам достаёт из входящего письма код или ссылку подтверждения. Общее описание API — на странице API для почты.

Что понадобится

Ключ передаётся в заголовке Authorization: Bearer <ключ>. Каждый ответ имеет вид {"success": true, "data": ...} или {"success": false, "error": {"code": ..., "message": ...}}, поэтому ошибки удобно разбирать в одном месте.

Шаг 1. Создаём заказ

import time
import uuid

import requests

HOST = "otpgmail.net"
API = f"https://{HOST}/v1"
API_KEY = "og_ваш_ключ"  # ключ со страницы «Профиль»
HEADERS = {"Authorization": f"Bearer {API_KEY}"}


class OtpGmailError(Exception):
    """Ошибка API: в .code — машинный код вроде NO_MAILS_AVAILABLE."""

    def __init__(self, code, message=""):
        super().__init__(f"{code}: {message}")
        self.code = code


def call(method, path, **kwargs):
    headers = {**HEADERS, **kwargs.pop("headers", {})}
    for _ in range(3):
        resp = requests.request(method, API + path, headers=headers, timeout=15, **kwargs)
        if resp.status_code == 429:  # превышен лимит запросов — ждём и повторяем
            time.sleep(int(resp.headers.get("Retry-After", "1")))
            continue
        body = resp.json()
        if not body.get("success"):
            err = body.get("error") or {}
            raise OtpGmailError(err.get("code", f"HTTP_{resp.status_code}"), err.get("message", ""))
        return body["data"]
    raise OtpGmailError("RATE_LIMITED")


def rent(service, domain="gmail.com", key=None):
    """Арендует один ящик. key — Idempotency-Key: при повторе после обрыва передайте тот же."""
    orders = call(
        "POST", "/orders",
        json={"service": service, "domain": domain},
        headers={"Idempotency-Key": key or str(uuid.uuid4())},
    )
    return orders[0]  # data — список: по элементу на каждый ящик

service — короткий код сервиса из GET /v1/services: например, git для GitHub или dr для ChatGPT. domain необязателен: по умолчанию gmail.com, для iCloud — icloud.com. В ответе есть orderId, email, status, otp (пока пустой список), price (цена в VND) и codeDeadlineAt — момент окончания ожидания в Unix-секундах.

Заголовок Idempotency-Key защищает от двойной аренды: если запрос оборвался по таймауту, повторите его с тем же ключом — API вернёт уже созданный заказ, а не выдаст второй ящик.

Шаг 2. Ждём код

def wait_for_code(order, poll_every=4, max_wait=None):
    """Опрашивает заказ, пока не придёт код или не закончится время ожидания."""
    deadline = order["codeDeadlineAt"] + 60
    if max_wait:
        deadline = min(deadline, time.time() + max_wait)
    while time.time() < deadline:
        current = call("GET", f"/orders/{order['orderId']}")
        if current["otp"]:
            return current["otp"][-1]["code"]  # последний полученный код — в конце списка
        if current["status"] == "cancelled":
            return None  # время вышло, деньги уже вернулись на баланс
        time.sleep(poll_every)
    return None


def cancel(order_id):
    """Отменяет заказ до прихода кода — 100 % возвращается на баланс."""
    try:
        call("POST", f"/orders/{order_id}/cancel")
    except OtpGmailError as e:
        if e.code != "ORDER_NOT_CANCELLABLE":  # код уже пришёл — отменять нечего
            raise

Опрашивайте заказ раз в 3–5 секунд: чаще бессмысленно — код придёт не раньше, чем его отправит сервис, а лимит запросов закончится быстрее. Статус waiting_code значит, что код ещё ждём, completed — код пришёл, cancelled — заказ отменён. Если кода нет за время ожидания (не более 25 минут), заказ отменяется сам и деньги возвращаются на баланс. У части сервисов вместо цифр приходит ссылка подтверждения — тогда ссылка окажется в поле code.

Шаг 3. Собираем вместе

def rent_with_fallback(service):
    """Сначала iCloud (обычно дешевле), при нехватке — Gmail."""
    try:
        return rent(service, "icloud.com")
    except OtpGmailError as e:
        if e.code in ("DOMAIN_UNAVAILABLE", "NO_MAILS_AVAILABLE", "OUT_OF_STOCK"):
            return rent(service, "gmail.com")
        raise


if __name__ == "__main__":
    order = rent_with_fallback("git")
    print("Адрес:", order["email"])
    input("Вставьте адрес в форму регистрации, запросите код и нажмите Enter...")
    code = wait_for_code(order)
    print("Код:", code or "не пришёл — деньги вернутся на баланс автоматически")

Запускайте ожидание только после того, как форма отправлена: до этого письма просто нет. Как выглядит та же регистрация вручную, видно на странице почта для регистрации GitHub.

Обработка ошибок

Полная таблица полей и ошибок, включая выбор источника параметром warehouse, — в документации API.

Тесты: pytest и Playwright

Арендованный ящик удобен в автотестах регистрации: тест получает настоящий адрес, отправляет форму и проверяет, что письмо с кодом пришло. Для писем от вашего собственного приложения используйте код ot («Любой сервис»): его вариант Gmail принимает один код на ящик, iCloud — все новые письма в течение 24 часов.

import pytest

from otpgmail_client import cancel, rent, wait_for_code  # функции из примера выше


@pytest.fixture
def rented_inbox():
    order = rent("ot")
    yield order
    cancel(order["orderId"])  # если код не пришёл — сразу вернуть деньги


def test_signup_sends_code(page, rented_inbox):  # page — фикстура pytest-playwright
    page.goto("https://staging.example.com/signup")
    page.fill("input[name=email]", rented_inbox["email"])
    page.click("button[type=submit]")
    code = wait_for_code(rented_inbox, max_wait=180)
    assert code, "письмо с кодом не пришло за 3 минуты"
    page.fill("input[name=code]", code)

Несколько ящиков можно арендовать одним запросом: поле quantity (до 200 за запрос), тогда в data будет по элементу на каждый ящик. Проверяйте собственные приложения или сервисы, правила которых разрешают тестовые аккаунты; для автоматизации без кода есть разбор ZennoPoster и BAS.

Часто задаваемые вопросы

Это Gmail API от Google?

Нет. Gmail API от Google работает с вашим собственным ящиком через OAuth. API OTPGmail выдаёт арендованный адрес и возвращает код из пришедшего письма; входить в ящик не нужно.

Как часто опрашивать заказ?

Раз в 3–5 секунд. Более частые запросы не ускорят доставку, но быстрее исчерпают лимит (по умолчанию 20 запросов в секунду и 900 в минуту).

Можно ли получить второй код в том же заказе?

Да, если сервис отправляет больше одного кода на ящик и окно заказа ещё открыто: новые коды добавляются в конец списка otp. Многие сервисы присылают только один код; лимит и окно видны в описании источника.

Что делать, если скрипт упал после создания заказа?

Найдите заказ запросом GET /v1/orders/{id} по сохранённому orderId или в истории в приложении. Если кода нет, отмените заказ — или дождитесь автоматической отмены с возвратом.

Есть ли официальная библиотека для Python?

Отдельного пакета нет: API — обычный REST, и примера выше достаточно для старта. Ключ и баланс — в приложении OTPGmail.

Похожие материалы

Получите код подтверждения на настоящий Gmail

Регистрация ничего не стоит. Деньги списываются только при выдаче ящика; нет кода за время ожидания (не более 25 минут) — 100 % автоматически возвращается на баланс.

Нет нужного сервиса? Нажмите Добавить сервис на странице аренды — мы рассмотрим его добавление.

Нужен не только код, а Gmail-аккаунт, в который можно войти? Смотрите Gmail-аккаунты на короткий срок · Возврат и гарантия