C

Celery

Темы: celery Python smtp
+ ещё 2
Пример отправки писем через SMTP Mailexam с использованием Celery (Python, Redis, фоновая задача).

Celery + Mailexam

Минимальный пример Celery, который отправляет тестовое письмо через SMTP Mailexam с помощью фонового worker и smtplib.

Основан на руководстве Mailexam для Celery.

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

  • Аккаунт Mailexam и проект с SMTP-учётными данными.
  • Python 3.10+ и pip.
  • Брокер сообщений — Redis (включён в Docker Compose ниже).

Из приветственного письма или личного кабинета Mailexam:

Переменная Описание
MAILEXAM_LOGIN SMTP-логин (например, xxxxx)
MAILEXAM_PASSWORD SMTP-пароль (пара к логину)
Хост {MAILEXAM_LOGIN}.mailexam.ru (формируется в mail.py)

Быстрый старт (на хосте)

  1. Создайте виртуальное окружение и установите зависимости:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
  1. Скопируйте пример файла окружения и заполните учётные данные:
cp .env.example .env
  1. Отредактируйте .env:
CELERY_BROKER_URL=redis://localhost:6379/0
MAILEXAM_LOGIN=ВАШ_ЛОГИН
MAILEXAM_PASSWORD=ВАШ_ПАРОЛЬ
MAILEXAM_PORT=587
MAIL_FROM=noreply@example.test
  1. Запустите Redis (если ещё не запущен):
docker run -d --name redis -p 6379:6379 redis:7-alpine
  1. Запустите Celery worker (терминал 1):
celery -A celery_app worker --loglevel=info
  1. Запустите HTTP-приложение (терминал 2):
python app.py

По умолчанию приложение слушает http://127.0.0.1:5000.

  1. Отправьте тестовое письмо (ставит задачу в очередь Celery):
curl -X POST http://127.0.0.1:5000/mail/test \
  -H 'Content-Type: application/json' \
  -d '{"to":"user@example.test","subject":"Тест","body":"Привет"}'

Worker отправит письмо; оно появится в личном кабинете Mailexam → ваш проект → входящие.

Постановка в очередь без HTTP

python -c "from tasks import send_test_email; print(send_test_email.delay().id)"

Или из shell Celery:

celery -A celery_app shell
from tasks import send_test_email
send_test_email.delay(
    to="user@example.test",
    subject="Тест",
    body="Привет из очереди",
)

Переменные окружения

Переменная Обязательна По умолчанию Описание
CELERY_BROKER_URL нет redis://localhost:6379/0 URL брокера Redis
MAILEXAM_LOGIN да SMTP-логин; также используется для формирования имени хоста
MAILEXAM_PASSWORD да SMTP-пароль
MAILEXAM_PORT нет 587 SMTP-порт (587, 2525 или 25)
MAIL_FROM нет noreply@example.test Адрес отправителя (подойдёт любой тестовый)
HTTP_HOST нет 127.0.0.1 Адрес привязки HTTP
HTTP_PORT нет 5000 Порт HTTP

Для порта 587 worker вызывает starttls() перед входом. Для порта 25 подключение без STARTTLS.

Структура проекта

.
├── requirements.txt
├── mail.py              # транспорт smtplib и send_test()
├── celery_app.py        # приложение Celery
├── tasks.py             # задача mail.send_test
├── app.py               # POST /mail/test (ставит задачу в очередь)
├── .env.example
├── Dockerfile           # только для локальной отладки
└── docker-compose.yml   # redis + worker + app

Docker (отладка)

Docker предназначен для локальной отладки. Для повседневной разработки запускайте Redis, worker и приложение на хосте (см. выше).

cp .env.example .env
# отредактируйте .env с учётными данными

docker compose up --build

Затем вызовите тот же endpoint на проброшенном порту:

curl -X POST http://127.0.0.1:5000/mail/test \
  -H 'Content-Type: application/json' \
  -d '{"to":"user@example.test","subject":"Тест","body":"Привет"}'

Compose запускает Redis, Celery worker и HTTP-приложение на порту 5000.

CI

Задайте эти секреты в окружении CI:

variables:
  CELERY_BROKER_URL: redis://redis:6379/0
  MAILEXAM_LOGIN: $MAILEXAM_LOGIN
  MAILEXAM_PASSWORD: $MAILEXAM_PASSWORD
  MAILEXAM_PORT: "587"
  MAIL_FROM: "noreply@example.test"

Для тестов без брокера и SMTP:

app.conf.task_always_eager = True

После отправки письма в тесте проверьте доставку через API Mailexam.

Типичные проблемы

Задача зависла в PENDING

  • Убедитесь, что worker запущен: celery -A celery_app worker --loglevel=info.
  • Проверьте, что CELERY_BROKER_URL совпадает у worker и клиента, и Redis доступен.

Ошибка SMTP в логах worker

  • Хост должен быть {логин}.mailexam.ru; логин и пароль должны быть из одного проекта Mailexam.
  • Worker загружает .env через load_dotenv() в celery_app.py.

Письмо не в кабинете

  • Откройте входящие того же проекта Mailexam.
  • Проверьте результат задачи: celery -A celery_app result <task_id>.

См. также

Лицензия

Apache 2.0