---
title: "Ring Mailer і RingdomX Mail"
description: "Власний Auth SMTP (OTP, magic link, скидання пароля) через lib/mailer.ts — окремо від CRM channel SMTP; фірмовий RingdomX Mail (хостинг MX або BYO)"
locale: "uk"
---
# Ring Mailer і RingdomX Mail

> **Info**
> Використовуйте вкладки **Founder** / **Developer** на бічній панелі документації, щоб відфільтрувати цю сторінку. Спільні розділи стосуються обох аудиторій.

Ring надсилає **пошту для входу** через **Ring Mailer** — Nodemailer у `lib/mailer.ts` (`SMTP_*` / `EMAIL_MODE`). Вхід без пароля використовує **OTP** або **magic links** (`/verify#token=…`) із хешованими токенами в Postgres (`email_login_tokens`). Провайдера **Resend немає**. **Відповіді CRM** працюють в іншому контурі: SMTP для кожного каналу через `EmailSenderService` + `ring-config.emailCrm.channels` — див. [Email AI-CRM](/docs/features/email-ai-crm.md).

  
- **[Функція автентифікації](/docs/features/authentication.md)** — Модель сесій Auth.js, OAuth, гаманці, онбординг vitals.

  
- **[Архітектура Auth](/docs/architecture/authentication.md)** — Провайдери в `auth.ts`, адаптери, JWT-сесії.

  
- **[Email AI-CRM](/docs/features/email-ai-crm.md)** — Публічна скринька — CRM channel SMTP, а не Auth SMTP_*.

  
- **[Середовище](/docs/deployment/environment.md)** — Довідка `SMTP_*`, `EMAIL_MODE`, `OTP_HMAC_SECRET`.

## Що постачається

| Поверхня | Роль |
|---------|------|
| **Auth transport** | `lib/mailer.ts` — пул Nodemailer; `sendMail()` |
| **CRM outbound** | `features/email-crm/pipeline/smtp/email-sender.ts` — SMTP **для кожного каналу** (не Auth pool) |
| **Auth actions** | `app/_actions/auth-email-actions.ts` — OTP, magic link, forgot/reset |
| **Credentials** | Auth.js `email-otp`, `email-magic`, `credentials` (пароль) у `auth.ts` |
| **UI** | Форма пошти для входу; `/verify`, `/forgot-password`, `/reset-password` |
| **Templates** | `emails/OTPEmail.tsx`, `emails/MagicLinkEmail.tsx` (`@react-email`) |
| **Tokens** | `lib/auth/email-tokens.ts` + `features/auth/services/email-login-tokens.ts` |
| **Cleanup cron** | `POST/GET /api/cron/cleanup-email-tokens` — **fail-closed** `CRON_SECRET` |
| **Migration** | `data/migrations/038_email_login_tokens.sql` |

Auth.js і надалі володіє сесіями (`auth()`, `useSession`, `/api/auth/*`). Ring Mailer лише доставляє **auth**-пошту та живить Credentials-провайдери.

Не спрямовуйте Auth `SMTP_*` на CRM-скриньку `info@` для OTP, якщо цього можна уникнути. У prod ring-platform.org Auth використовує `mail.subiworx.com` / `noreply@ring-platform.org`; основний CRM — `mail.ringdom.org` / `info@ringdom.org`. Див. `RING-MAILER-OPS.md` і `EMAIL-CRM-OPS.md`.

```mermaid
sequenceDiagram
    participant U as Користувач
    participant A as auth-email-actions
    participant M as lib/mailer sendMail
    participant DB as email_login_tokens
    participant Auth as Auth.js Credentials

    U->>A: requestLoginCode / magic link
    A->>DB: insert hashed token
    A->>M: SMTP or Ethereal
    M-->>U: OTP email or /verify#token
    U->>Auth: signIn email-otp or email-magic
    Auth->>DB: consume token
    Auth-->>U: JWT session cookie
```

### For founders

## Навіщо володіти auth-поштою замість SaaS-ключа

Сторонній SaaS для magic link прив’язує кожен клон до зовнішнього API-ключа та щомісячної оплати. Ring Mailer залишає **пошту для входу на вашому домені** (або на MX Ringdom), тому учасники бачать `noreply@your-domain`, SPF/DKIM залишаються під вашим контролем, а white-label-клони не ділять обліковий запис Resend маркетплейсу.

### RingdomX Mail (калькулятор)

У калькуляторі проєкту зовнішній додаток **`mail`** має назву **RingdomX Mail**:

| Режим | Що ви отримуєте |
|------|----------------|
| **Hosted (`MAIL_MODE=ringdom`)** | MX/SPF/DKIM клону спрямовуються до пошти Ringdom (шлях `mail.ringdom.org`). Облікові дані зберігаються в секретах власника супутника. |
| **Bring your own (`MAIL_MODE=byo`)** | Ви задаєте Auth `SMTP_*` у секретах власника. Налаштовуйте CRM-канали окремо в `emailCrm` / `CRM_CHANNEL_*`. |

Ціни та id пресетів: зовнішній id `mail` у `features/calculator/presets/project.ts`; копія — у `locales/*/calculator.json`.

  
  
  

### Чекліст оператора

Виберіть **RingdomX hosted** або **BYO SMTP** для **Auth**. CRM-канали налаштовуйте незалежно (див. [Email AI-CRM](/docs/features/email-ai-crm.md)).

Переконайтеся, що міграцію `038_email_login_tokens.sql` застосовано до Postgres клону.

Перевірте: запитайте OTP з `/login`, підтвердьте доставку (або перегляньте preview Ethereal у логах) і завершіть вхід. Окремо затвердьте одну чернетку CRM, щоб підтвердити channel SMTP.

### For developers

## Локальна розробка (Auth SMTP або Ethereal)

Облікового запису Resend немає. Виберіть один варіант для **пошти входу**:

| Режим | Env | Поведінка |
|------|-----|----------|
| **Ethereal (зручний за замовчуванням)** | `EMAIL_MODE=ethereal` | Тестовий обліковий запис Nodemailer; URL preview записується як `[RingMailer] Ethereal preview` |
| **Справжній SMTP** | `SMTP_HOST`, `SMTP_USER`, `SMTP_PASSWORD` (або `SMTP_PASS`), необов’язково `SMTP_PORT` / `SMTP_SECURE` / `SMTP_FROM` | Auth надсилає пошту через цей сервер |

Також задайте `OTP_HMAC_SECRET` (секрет ≥32 байти) або використовуйте `AUTH_SECRET` (мінімум 16 символів) для хешування токенів.

{`# EMAIL_MODE=ethereal
# OTP_HMAC_SECRET=generate-a-32-byte-hex-secret

# SMTP_HOST=mail.example.com
# SMTP_PORT=587
# SMTP_SECURE=false
# SMTP_USER=noreply@example.com
# SMTP_PASSWORD=
# SMTP_FROM=Ring Platform <noreply@example.com>
# Alias accepted: SMTP_PASS=`}

`isRingMailerConfigured()` дорівнює true, коли задано `EMAIL_MODE=ethereal`, користувача/пароль Ethereal або host+user+password.

### Cron очищення токенів

`/api/cron/cleanup-email-tokens` видаляє прострочені `email_login_tokens` (разом із grace). **Fail-closed**: відсутній або невідповідний `CRON_SECRET` → `401` (узгоджено з `email-processor`).

### Міграція

{`psql "$DATABASE_URL" -f data/migrations/038_email_login_tokens.sql`}

Нотатки для ops: `data/migrations/RING-MAILER-OPS.md` (Auth host = `mail.subiworx.com` для prod ring-platform.org).

### Auth-потоки (перевірено)

| Потік | Action / route | Credentials id |
|------|----------------|----------------|
| Вхід через OTP | `requestLoginCode` → UI → `signIn('email-otp')` | `email-otp` |
| Magic link | `requestMagicLink` → `/verify#token=…` → `signIn('email-magic')` | `email-magic` |
| Підтвердження email | те саме споживання magic із потоком `email_verify` | `email-magic` |
| Забутий пароль | `requestPasswordReset` → `/reset-password#token=…` | споживання + встановлення пароля |
| Вхід за паролем | `signIn('credentials')` | `credentials` |

Сторінки: `app/[locale]/verify/page.tsx`, `forgot-password`, `reset-password`. UI: `features/auth/components/email-login-form.tsx`. UI **реєстрації** за паролем знижено в пріоритеті — `/register` перенаправляє на `/login`.

### Застаріле — не використовуйте

| Видалено | Заміна |
|---------|--------|
| `AUTH_RESEND_KEY` / `AUTH_RESEND_FROM` | `SMTP_*` / `EMAIL_MODE` / `SMTP_FROM` |
| `next-auth/providers/resend` | Credentials `email-otp` / `email-magic` + `lib/mailer.ts` |
| `signIn('resend')` | `requestLoginCode` / magic link → Credentials |
| CRM replies via `lib/mailer.ts` | `EmailSenderService` + `CRM_CHANNEL_*` |

### Мапа коду

| Шлях | Роль |
|------|------|
| `lib/mailer.ts` | SSOT auth-транспорту |
| `app/_actions/auth-email-actions.ts` | Server Actions для запиту/надсилання |
| `lib/auth/email-tokens.ts` | Хелпери OTP / HMAC / magic URL |
| `features/auth/services/email-login-tokens.ts` | CRUD Postgres-токенів + rate limit |
| `app/api/cron/cleanup-email-tokens/route.ts` | Fail-closed очищення токенів |
| `auth.ts` | Credentials-провайдери |
| `emails/*.tsx` | Шаблони React Email |

## Пов’язана документація

  
- [features/authentication](/docs/features/authentication.md) — Наступний крок: повна поверхня провайдерів Auth.js, vitals gate і /register → /login.

  
- [features/email-ai-crm](/docs/features/email-ai-crm.md) — Залежність: відповіді CRM використовують channel SMTP — тримайте Auth SMTP_* окремо.

  
- [examples/authentication](/docs/examples/authentication.md) — Той самий процес: патерни інтегратора для OAuth + Ring Mailer.

  
- [architecture/authentication](/docs/architecture/authentication.md) — Поглиблення: розділення файлів Auth.js і JWT callbacks.

  
- [deployment/environment](/docs/deployment/environment.md) — Див. також: повна довідка env для SMTP і EMAIL_MODE.
