API для получения кода из почты: пример на Python
Чтобы получить код из письма в Python-скрипте, нужны три HTTP-запроса к API OTPGmail: создать заказ и получить адрес, опрашивать заказ, пока не появится код, и отменить заказ, если код больше не нужен. Ниже — готовый код на requests, разбор ошибок и пример фикстуры для автотестов.
Это не Gmail API от Google: вы не работаете со своим ящиком через OAuth, а арендуете настоящий адрес @gmail.com или @icloud.com, и сервис сам достаёт из входящего письма код или ссылку подтверждения. Общее описание API — на странице API для почты.
Что понадобится
- Ключ API. Он есть у каждого аккаунта на странице «Профиль» и начинается с
og_. Там же ключ можно перевыпустить, если он попал в чужие руки. - Баланс. Деньги списываются только при выдаче ящика; пополнить баланс можно в USDT или USDC.
- Python 3 и библиотека
requests. Если используетеurllib, задайте свой заголовокUser-Agent: запросы со стандартным заголовком библиотеки может отклонять защита сайта.
Ключ передаётся в заголовке 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.
Обработка ошибок
NO_MAILS_AVAILABLEилиOUT_OF_STOCK— ящики для сервиса закончились; деньги не списаны. Повторите позже или сменитеdomain.DOMAIN_UNAVAILABLE— у сервиса нет варианта iCloud или он временно выключен. Повторите сgmail.com.INSUFFICIENT_BALANCE— пополните баланс.VALIDATION_ERROR— неверный код сервиса или параметр; сверьтесь сGET /v1/services.RATE_LIMITED(HTTP 429) — превышен лимит (по умолчанию 20 запросов в секунду и 900 в минуту на ключ); подождите столько секунд, сколько указано вRetry-After.ORDER_NOT_CANCELLABLE— код уже пришёл, после этого заказ не отменяется и не возвращается.
Полная таблица полей и ошибок, включая выбор источника параметром 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.
