REST API Mailexam®¶
REST API Mailexam® позволяет программно работать с проектами, почтовыми ящиками и письмами — удобно для автотестов, QA и CI/CD. Типичный сценарий: приложение отправляет письмо по SMTP, тест через API проверяет, что оно дошло до sandbox, и сверяет тему, тело или вложения.
Полная спецификация OpenAPI доступна в Swagger UI.
Базовый URL¶
| Параметр | Значение |
|---|---|
| Базовый адрес | https://mailexam.ru/api/v1 |
| Формат | JSON |
| Методы | GET, POST, PUT, DELETE |
Домены
| Регион | API |
|---|---|
| Россия | mailexam.ru |
| Китай | mailexam.cn |
| Международный | mailexam.io |
Пути и формат запросов совпадают; меняется только хост.
Авторизация¶
Все запросы требуют API-токен — его можно получить в личном кабинете Mailexam®.
Токен передаётся query-параметром token:
Секреты в CI/CD
Не храните токен в коде репозитория. Добавьте переменную MAILEXAM_API_TOKEN в секреты GitLab CI, GitHub Actions или другого pipeline.
| Код ответа | Значение |
|---|---|
200 / 201 |
Успешная операция |
403 |
Недостаточно прав или неверный токен |
404 |
Объект по UUID не найден |
Типичный сценарий в CI/CD¶
- Отправить письмо из приложения через SMTP (см. примеры интеграции).
- Подождать доставку — обычно 1–5 секунд.
- Получить список проектов → почтовых ящиков → писем через API.
- Найти письмо по теме или получателю и проверить содержимое.
sequenceDiagram
participant App as Приложение
participant SMTP as SMTP Mailexam
participant API as REST API
participant Test as Автотест
App->>SMTP: sendMail()
Note over SMTP: Письмо в sandbox
Test->>API: GET /project
Test->>API: GET /inbox?project=...
Test->>API: GET /email?inbox=...
Test->>Test: assert subject, body
Справочник эндпоинтов¶
Проекты (/project)¶
| Метод | Путь | Описание |
|---|---|---|
GET |
/project |
Список проектов |
POST |
/project/store |
Создание проекта |
GET |
/project/{uuid} |
Информация о проекте |
PUT |
/project/{uuid}/update |
Обновление проекта |
DELETE |
/project/{uuid}/delete |
Удаление проекта |
Тело запроса при создании и обновлении:
Пример ответа (ProjectResponse):
{
"uuid": "536a47df-5aad-44d0-8163-a39bb55abe0b",
"name": "Мой проект",
"description": null,
"user": {
"uuid": "984f1f70-21e1-4244-bbb7-734ac151dcdc",
"name": "Служба поддержки Mailexam",
"email": "support@mailexam.ru"
}
}
Почтовые ящики (/inbox)¶
| Метод | Путь | Описание |
|---|---|---|
GET |
/inbox?project={uuid} |
Список ящиков проекта |
POST |
/inbox/store |
Создание ящика |
GET |
/inbox/{uuid} |
Информация о ящике |
PUT |
/inbox/{uuid}/default |
Ящик «по умолчанию» |
PUT |
/inbox/{uuid}/update |
Обновление ящика |
DELETE |
/inbox/{uuid}/delete |
Удаление ящика |
Тело запроса при создании (InboxRequest):
{
"project_uuid": "536a47df-5aad-44d0-8163-a39bb55abe0b",
"name": "Все письма",
"has_autorelay": false,
"relay_host": null,
"relay_port": null,
"relay_pass": null
}
Письма (/email)¶
| Метод | Путь | Описание |
|---|---|---|
GET |
/email?inbox={uuid} |
Список писем в ящике |
GET |
/email/{uuid} |
Полное письмо (тело, заголовки) |
GET |
/email/{uuid}/attachment?cid={id} |
Вложение |
PUT |
/email/{uuid}/unread |
Признак «не прочитано» |
PUT |
/email/{uuid}/like |
Признак «нравится» |
PUT |
/email/{uuid}/dislike |
Признак «не нравится» |
PUT |
/email/{uuid}/relay |
Отправка на сервер ретрансляции |
DELETE |
/email/{uuid}/delete |
Удаление письма |
Краткий формат письма (EmailShort):
{
"uuid": "e2f9a506-d766-4935-be11-c413384de020",
"from": "\"Mailexam\" <support@mailexam.ru>",
"to": "Служба поддержки Mailexam <support@mailexam.ru>",
"cc": null,
"subject": "Параметры подключения к Mailexam",
"human_size": "113 Байт",
"date": "2025-03-01T08:58:49.000000Z",
"attachments": true,
"unread": false,
"like": true,
"dislike": false
}
Полный формат (EmailDetailed) дополнительно содержит поля body (html, text, raw, attachments), headers и relay.
Пример: проверка письма через curl¶
Переменные окружения:
Пример: автотест на Python¶
Сценарий: после SMTP-отправки найти письмо по теме и проверить текст.
import os
import time
import urllib.parse
import urllib.request
import json
API_BASE = os.environ.get("MAILEXAM_API_BASE", "https://mailexam.ru/api/v1")
TOKEN = os.environ["MAILEXAM_API_TOKEN"]
PROJECT_UUID = os.environ["MAILEXAM_PROJECT_UUID"]
EXPECTED_SUBJECT = "Проверка CI"
def api_get(path, params=None):
params = dict(params or {})
params["token"] = TOKEN
url = f"{API_BASE}{path}?{urllib.parse.urlencode(params)}"
with urllib.request.urlopen(url) as resp:
return json.loads(resp.read().decode())
def wait_for_email(subject, timeout=30, interval=2):
inboxes = api_get("/inbox", {"project": PROJECT_UUID})
inbox_uuid = inboxes[0]["uuid"]
deadline = time.time() + timeout
while time.time() < deadline:
emails = api_get("/email", {"inbox": inbox_uuid})
for item in emails:
if item["subject"] == subject:
return api_get(f"/email/{item['uuid']}")
time.sleep(interval)
raise TimeoutError(f"Письмо с темой «{subject}» не найдено за {timeout} с")
if __name__ == "__main__":
# ... здесь отправка письма через SMTP вашего приложения ...
time.sleep(3)
email = wait_for_email(EXPECTED_SUBJECT)
body_text = (email.get("body") or {}).get("text") or ""
assert "Привет" in body_text, "Текст письма не совпадает"
print("OK")
Зависимости не нужны — используется стандартная библиотека Python 3. Для HTTP удобнее requests или httpx, если они уже есть в проекте.
Пример: автотест на Node.js¶
const TOKEN = process.env.MAILEXAM_API_TOKEN;
const API_BASE = process.env.MAILEXAM_API_BASE || 'https://mailexam.ru/api/v1';
const PROJECT_UUID = process.env.MAILEXAM_PROJECT_UUID;
const EXPECTED_SUBJECT = 'Проверка CI';
async function apiGet(path, params = {}) {
const query = new URLSearchParams({ ...params, token: TOKEN });
const res = await fetch(`${API_BASE}${path}?${query}`);
if (!res.ok) throw new Error(`${res.status} ${path}`);
return res.json();
}
async function waitForEmail(subject, timeoutMs = 30000, intervalMs = 2000) {
const inboxes = await apiGet('/inbox', { project: PROJECT_UUID });
const inboxUuid = inboxes[0].uuid;
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const emails = await apiGet('/email', { inbox: inboxUuid });
const match = emails.find((item) => item.subject === subject);
if (match) return apiGet(`/email/${match.uuid}`);
await new Promise((r) => setTimeout(r, intervalMs));
}
throw new Error(`Письмо «${subject}» не найдено за ${timeoutMs / 1000} с`);
}
(async () => {
// ... отправка через SMTP ...
await new Promise((r) => setTimeout(r, 3000));
const email = await waitForEmail(EXPECTED_SUBJECT);
const text = email.body?.text || '';
if (!text.includes('Привет')) throw new Error('Текст письма не совпадает');
console.log('OK');
})().catch((err) => {
console.error(err);
process.exit(1);
});
Node.js 18+ — встроенный fetch.
GitLab CI¶
integration_test:
stage: test
variables:
MAILEXAM_API_BASE: "https://mailexam.ru/api/v1"
MAILEXAM_PROJECT_UUID: "536a47df-5aad-44d0-8163-a39bb55abe0b"
script:
- python send_and_verify.py
# MAILEXAM_API_TOKEN, MAILEXAM_LOGIN, MAILEXAM_PASSWORD — в CI/CD Variables
SMTP-секреты (MAILEXAM_LOGIN, MAILEXAM_PASSWORD) и API-токен — разные значения: первые для отправки, второй для чтения через REST.
Сравнение с Mailtrap API¶
При миграции с Mailtrap замените вызовы Sandbox API:
| Задача | Mailtrap | Mailexam® |
|---|---|---|
| Список писем | Sandbox API | GET /email?inbox={uuid} |
| Одно письмо | Sandbox API | GET /email/{uuid} |
| Вложение | Sandbox API | GET /email/{uuid}/attachment?cid={id} |
| Управление sandbox | Sandboxes API | GET /project, /inbox |
Типичные проблемы¶
403 Forbidden
- Проверьте, что токен скопирован полностью и передан как
?token=.... - Токен привязан к аккаунту — убедитесь, что проект принадлежит этому пользователю.
Пустой список писем
- Письмо могло попасть в другой проект или ящик — сверьте SMTP-логин с нужным проектом.
- Увеличьте паузу после SMTP-отправки (2–5 с) или используйте polling с таймаутом.
Письмо есть в кабинете, но тест его не находит
- Фильтруйте по точной теме или проверяйте последние письма по дате (
dateв ответе API). - Для вложений сначала получите
EmailDetailed, затем скачайте файл поcid.