[C28-28] feat(email-relay): HTTP→SMTP релей для коопов с закрытым SMTP #115

Merged
ant merged 2 commits from feature/C28-28-email-relay into dev 2026-06-09 07:54:58 +00:00
Owner

Зачем

Хостинги коопов режут исходящий SMTP → письма controller'а уходят в connection timeout (видно в журнале уведомлений). Раньше хабом отправки был Novu — после удаления коопы шлют SMTP напрямую и упираются в закрытые порты.

Решение

Минимальный HTTP→SMTP релей @coopenomics/email-relay. Коопы шлют письма ему по HTTPS (Bearer-токен), он стоит на сервере с открытыми портами (voskhod) и форвардит по SMTP.

Что в PR

  • 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.yaml — дев-сервисы email-relay + mailpit (SMTP-перехватчик для E2E).
  • release.yaml — сборка образа dicoop/email-relay.

Аутентификация

Статичный Bearer-токен поверх TLS (nginx + Let's Encrypt). Server-to-server, один секрет, ротация = смена env. mTLS отвергнут (раздача сертификатов по N коопам — боль за уже имеющимся TLS).

Тест

E2E локально (изолированно, рабочий стек не трогался): формат письма controller'а → релей → SMTP → mailpit. Тело с
и заголовки целы; 401 на отсутствие/неверный токен, 400 на пустое тело, /health 200.

Деплой (отдельно)

Плейбук playbooks/email-relay/setup.yaml (nginx TLS + docker compose pull/up образа dicoop/email-relay) — по образцу matrix-sender. Коопам в controller/.env: EMAIL_RELAY_URL + EMAIL_RELAY_TOKEN.

Generated with Claude Code

## Зачем Хостинги коопов режут исходящий SMTP → письма controller'а уходят в connection timeout (видно в журнале уведомлений). Раньше хабом отправки был Novu — после удаления коопы шлют SMTP напрямую и упираются в закрытые порты. ## Решение Минимальный HTTP→SMTP релей @coopenomics/email-relay. Коопы шлют письма ему по HTTPS (Bearer-токен), он стоит на сервере с открытыми портами (voskhod) и форвардит по SMTP. ## Что в PR - 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.yaml — дев-сервисы email-relay + mailpit (SMTP-перехватчик для E2E). - release.yaml — сборка образа dicoop/email-relay. ## Аутентификация Статичный Bearer-токен поверх TLS (nginx + Let's Encrypt). Server-to-server, один секрет, ротация = смена env. mTLS отвергнут (раздача сертификатов по N коопам — боль за уже имеющимся TLS). ## Тест E2E локально (изолированно, рабочий стек не трогался): формат письма controller'а → релей → SMTP → mailpit. Тело с <br> и заголовки целы; 401 на отсутствие/неверный токен, 400 на пустое тело, /health 200. ## Деплой (отдельно) Плейбук playbooks/email-relay/setup.yaml (nginx TLS + docker compose pull/up образа dicoop/email-relay) — по образцу matrix-sender. Коопам в controller/.env: EMAIL_RELAY_URL + EMAIL_RELAY_TOKEN. Generated with Claude Code
claude added 1 commit 2026-06-09 07:43:11 +00:00
[C28-28][@ant] feat(email-relay): HTTP→SMTP релей для коопов с закрытым SMTP
Typecheck / desktop (pull_request) Has been cancelled
Typecheck / controller (pull_request) Has been cancelled
7e2b26a02e
Хостинги коопов режут исходящий 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>
claude added 1 commit 2026-06-09 07:52:02 +00:00
[C28-28][@ant] fix(email-relay): убрать mailpit из compose, env_file как coopback
Typecheck / desktop (pull_request) Successful in 13m51s
Typecheck / controller (pull_request) Has been cancelled
468c946610
mailpit был только локальным SMTP-перехватчиком для теста — в поставке не нужен.
email-relay сам ходит в реальный SMTP через nodemailer; конфиг (RELAY_TOKEN,
SMTP_*) выносим в components/email-relay/.env по образцу coopback, без отдельного
контейнера и inline-параметров.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ant approved these changes 2026-06-09 07:54:53 +00:00
ant merged commit f728563bdb into dev 2026-06-09 07:54:58 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: C9S/mono#115