FastAPI¶
Инструкция для приложений на FastAPI (Python 3.10+). Mailexam подключается как SMTP-сервер через smtplib; отправку можно вынести в отдельный модуль и вызывать из async-обработчика.
Что понадобится¶
- Аккаунт Mailexam и проект с SMTP-учётными данными.
- Python 3.10+ и виртуальное окружение.
Скопируйте из приветственного письма (или кабинета) для вашего проекта:
ВАШ_ЛОГИН— SMTP-логин (например,xxxxx);ВАШ_ПАРОЛЬ— SMTP-пароль (уникальная пара к логину);- хост —
ВАШ_ЛОГИН.mailexam.ru(совпадает с логином).
1. Зависимости¶
python3 -m venv .venv
source .venv/bin/activate
pip install fastapi uvicorn python-dotenv email-validator
Файл requirements.txt:
2. Переменные окружения¶
Файл .env в корне проекта (не коммитьте пароли в git):
MAILEXAM_LOGIN=ВАШ_ЛОГИН
MAILEXAM_PASSWORD=ВАШ_ПАРОЛЬ
MAILEXAM_PORT=587
MAIL_FROM=noreply@example.test
Хост собирается из логина: {MAILEXAM_LOGIN}.mailexam.ru.
Адрес отправителя
MAIL_FROM может быть любым тестовым адресом — письмо попадёт в Mailexam, а не реальному получателю.
Альтернативные порты¶
3. Модуль отправки почты¶
Тот же подход, что в Flask:
# mail.py
import os
import smtplib
from email.message import EmailMessage
def smtp_host() -> str:
login = os.environ["MAILEXAM_LOGIN"]
return f"{login}.mailexam.ru"
def send_test(*, to: str, subject: str, body: str) -> None:
login = os.environ["MAILEXAM_LOGIN"]
password = os.environ["MAILEXAM_PASSWORD"]
port = int(os.environ.get("MAILEXAM_PORT", "587"))
mail_from = os.environ.get("MAIL_FROM", "noreply@example.test")
msg = EmailMessage()
msg["From"] = mail_from
msg["To"] = to
msg["Subject"] = subject
msg.set_content(body)
with smtplib.SMTP(smtp_host(), port, timeout=30) as smtp:
if port in (587, 2525):
smtp.starttls()
smtp.login(login, password)
smtp.send_message(msg)
smtplib синхронный — в async-приложении вызывайте его через asyncio.to_thread, чтобы не блокировать event loop.
4. Маршрут FastAPI¶
# main.py
import asyncio
from dotenv import load_dotenv
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
from mail import send_test
load_dotenv()
app = FastAPI()
class SendRequest(BaseModel):
to: EmailStr = "user@example.test"
subject: str = "FastAPI + Mailexam"
body: str = "Тест Mailexam из FastAPI"
@app.post("/mail/test")
async def mail_test(payload: SendRequest):
await asyncio.to_thread(
send_test,
to=str(payload.to),
subject=payload.subject,
body=payload.body,
)
return {"status": "ok"}
Запуск и проверка:
curl -X POST http://127.0.0.1:8000/mail/test \
-H 'Content-Type: application/json' \
-d '{"to":"user@example.test","subject":"Проверка","body":"Привет"}'
Документация REST API: http://127.0.0.1:8000/docs
Письмо появится в кабинете Mailexam → ваш проект → входящие.
5. Локальная разработка и CI¶
| Среда | Рекомендация |
|---|---|
local |
.env с личным проектом Mailexam |
| CI | Секреты MAILEXAM_LOGIN, MAILEXAM_PASSWORD в GitLab CI/CD Variables |
Пример для .gitlab-ci.yml:
variables:
MAILEXAM_LOGIN: $MAILEXAM_LOGIN
MAILEXAM_PASSWORD: $MAILEXAM_PASSWORD
MAILEXAM_PORT: "587"
MAIL_FROM: "noreply@example.test"
После интеграционного теста с отправкой письма проверьте доставку через API Mailexam.
6. Типичные проблемы¶
Ошибка TLS или подключения
- Хост должен быть
{логин}.mailexam.ru, где{логин}— то же значение, чтоMAILEXAM_LOGINиз письма. - Логин и пароль — пара из письма; не комбинируйте данные разных проектов.
- Для порта 587 вызывайте
smtp.starttls()передlogin().
Письмо не в кабинете
- Убедитесь, что смотрите входящие того же проекта Mailexam.
- Проверьте ответ
/mail/testи логи uvicorn.
Блокировка event loop
- Не вызывайте
send_test()напрямую вasync def— используйтеasyncio.to_thread()или фоновую задачу.
Переменные окружения не подхватываются
- Вызовите
load_dotenv()при старте приложения. - При запуске через systemd/Docker передайте переменные в окружение контейнера.
См. также¶
- Каталог примеров
- Пример реализации (FastAPI)
- Flask — тот же модуль
mail.py, синхронный маршрут - Документация REST API Mailexam
- Документация FastAPI