Хостинги коопов режут исходящий SMTP → письма controller'а уходят в timeout (раньше хабом был Novu, его убрали). Новый компонент @coopenomics/email-relay принимает письма по HTTPS с Bearer-токеном и форвардит по SMTP. Ставится на сервер с открытыми портами (плейбук в playbooks/email-relay). - components/email-relay: express + nodemailer, POST /send + GET /health, Bearer-токен (constant-time), опц. IP-allowlist, конфиг из ENV - controller: email-channel.adapter получил relay-режим — если задан EMAIL_RELAY_URL, письмо уходит POST'ом на релей; иначе прямой SMTP как раньше (opt-in, без регрессии) - docker-compose: дев-сервисы email-relay + mailpit (SMTP-перехватчик для E2E) - release.yaml: сборка образа dicoop/email-relay E2E проверен локально: controller-формат письма → релей → SMTP → mailpit, тело с <br> и заголовки целы; 401 на отсутствие/неверный токен, 400 на пустое тело. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.3 KiB
@coopenomics/email-relay
Минимальный HTTP→SMTP релей. Принимает письма по HTTPS с Bearer-токеном и отправляет их по SMTP.
Зачем
На хостингах многих кооперативов закрыт исходящий SMTP (25/465/587) — письма из
controller уходят в connection timeout. Открывать порты по тикету на каждом
сервере неудобно. Решение: один релей на сервере с открытыми портами (voskhod),
все коопы шлют письма ему по HTTPS, он форвардит по SMTP.
Раньше эту роль выполнял Novu — после его удаления нужен свой сервис.
API
GET /health→{ "status": "ok" }POST /send(требуетAuthorization: Bearer <RELAY_TOKEN>){ "from": "...", "to": "...", "subject": "...", "html": "...", "text": "..." }fromнеобязателен (берётсяEMAIL_FROM_DEFAULT); нужно телоhtmlилиtext. Ответ:{ "delivered": true, "messageId": "..." }либо502сerror.
Аутентификация
Статичный Bearer-токен поверх TLS (nginx + Let's Encrypt). Сравнение токена —
constant-time. Опционально IP-allowlist (RELAY_IP_ALLOWLIST). Ротация = смена
RELAY_TOKEN на релее и у всех коопов.
Запуск
cp .env.example .env # заполнить RELAY_TOKEN + SMTP_*
pnpm -F @coopenomics/email-relay dev # разработка
pnpm -F @coopenomics/email-relay start # прод
ENV — см. .env.example.
Интеграция с controller
В controller/.env кооператива:
EMAIL_RELAY_URL=https://mail-relay.coopenomics.world/send
EMAIL_RELAY_TOKEN=<тот же RELAY_TOKEN>
Если EMAIL_RELAY_URL не задан — controller шлёт напрямую по SMTP (старое
поведение, без изменений).
Деплой
- Образ:
dicoop/email-relay(release-пайплайн, как остальные mono-сервисы). - Плейбук:
playbooks/email-relay/setup.yaml(nginx TLS + docker compose).