# Почта MoonWell Для `support@moon-well.online` и `no-reply@moon-well.online` используется отдельный контейнер [Stalwart Mail Server](https://stalw.art/). Он предоставляет SMTP, IMAP, антиспам, DKIM и административный интерфейс. Данные и конфигурация хранятся в именованных Docker volumes и переживают пересоздание контейнера. ## Что требуется от сервера - постоянный публичный IPv4-адрес; - возможность принимать TCP-соединения на порты `25`, `465`, `587`, `993`; - разрешённый исходящий TCP-порт `25`; - PTR/rDNS для IP со значением `mail.moon-well.online`; - доступ к управлению DNS-зоной `moon-well.online`. Без корректного PTR исходящие сообщения часто попадают в спам. Некоторые хостинги блокируют исходящий порт 25 — это нужно проверить до настройки. ## Первый запуск ```bash ./scripts/mail-server.sh init ``` Проверь значения в `.env.mail`. Затем создай DNS-запись: ```text mail.moon-well.online. A <публичный IPv4 сервера> ``` Запусти сервер: ```bash ./scripts/mail-server.sh up ./scripts/mail-server.sh credentials ``` Административный HTTP-порт намеренно доступен только на loopback-интерфейсе. Открой туннель со своего компьютера: ```bash ssh -L 8081:127.0.0.1:8081 <пользователь>@<сервер> ``` После этого открой `http://127.0.0.1:8081/admin` и войди с временными реквизитами из команды `credentials`. ## Мастер Stalwart Используй следующие значения: - Server hostname: `mail.moon-well.online` - Default email domain: `moon-well.online` - Automatically obtain TLS certificate: включено - Generate email signing keys: включено - Storage: локальный RocksDB - Directory: Internal Directory - Logging: Console Если DNS размещён у поддерживаемого Stalwart провайдера, подключи его в последнем шаге. Тогда сертификат выпускается через DNS-01 без занятия публичного порта 443. Иначе понадобится отдельно передать серверу TLS-сертификат или временно предоставить ему порт 443 для ACME-проверки. Сохрани постоянные реквизиты администратора, показанные мастером, и перезапусти контейнер: ```bash ./scripts/mail-server.sh restart ``` Создай обычный пользовательский аккаунт `support@moon-well.online`. Административный аккаунт нельзя использовать в почтовом клиенте. Для приложения создай отдельный SMTP-аккаунт `no-reply@moon-well.online` с правом отправки от этого адреса. Laravel использует его для подтверждения email и восстановления пароля. Пароль хранится только в `.env` приложения; в репозиторий его добавлять не нужно. Ящик поддержки остаётся отдельным. В панели Stalwart открой `Management → Directory → Accounts` и создай обычный пользовательский аккаунт (роль User): - имя: `no-reply`; - домен: `moon-well.online`; - основной email: `no-reply@moon-well.online`; - отображаемое имя: `MoonWell`; - пароль: отдельный случайный пароль для SMTP. В версиях панели с полем полного логина укажи `no-reply@moon-well.online`. Названия полей могут отличаться между версиями; итоговый адрес и SMTP-логин должны быть `no-reply@moon-well.online`. Не выдавай этому аккаунту роль администратора. Отдельные MX/SPF/DKIM-записи для нового ящика не нужны — используется уже настроенный домен. [Создание аккаунтов в документации Stalwart](https://www.stalw.art/docs/faq/accounts/). ## DNS после мастера В панели Stalwart открой: `Management → Domains → Domains → moon-well.online → View DNS Zone file` Перенеси предложенные записи в DNS-панель. В обязательный минимум входят: - MX; - SPF; - DKIM; - DMARC; - записи автоконфигурации, которые предложит Stalwart. Значение DKIM нужно брать только из созданной установки: ключ генерируется индивидуально. Не копируй DKIM из примеров. ## Настройка почтового клиента ```text Адрес: support@moon-well.online IMAP-сервер: mail.moon-well.online IMAP-порт: 993 Шифрование IMAP: SSL/TLS SMTP-сервер: mail.moon-well.online SMTP-порт: 465 Шифрование SMTP: SSL/TLS SMTP-аутентификация: включена Логин: support@moon-well.online ``` ## Подключение Laravel После создания `no-reply@moon-well.online` укажи в production `.env`: ```dotenv APP_URL=https://moon-well.online MAIL_MAILER=smtp MAIL_SCHEME=smtps MAIL_HOST=mail.moon-well.online MAIL_PORT=465 MAIL_USERNAME=no-reply@moon-well.online MAIL_PASSWORD=<пароль ящика> MAIL_FROM_ADDRESS=no-reply@moon-well.online MAIL_FROM_NAME="${APP_NAME}" ``` Затем сбрось и пересобери кэш конфигурации: ```bash docker compose -f compose.prod.yaml exec -T --user app app php artisan optimize:clear docker compose -f compose.prod.yaml exec -T --user app app php artisan config:cache ``` Если используется SSH-туннель к БД ядра, добавь `-f compose.prod.ssh-tunnel.yaml` к обеим командам. Для Sail используй `docker compose exec -T laravel.test php artisan …`. `MAIL_HOST` — публичное имя с действительным TLS-сертификатом. Приложение может отправлять письма на опубликованный Stalwart порт 465, даже если его контейнер находится в другой Docker-сети. Не отключай проверку сертификата и не подменяй имя на `stalwart` при использовании публичного сертификата. При доставке нового кода выполни миграции (`php artisan migrate --force`). Новые регистрации на сайте и через API лаунчера требуют подтверждения почты; существующие и импортированные аккаунты сохраняют доступ. Подтверждение не требует предварительного входа. Повторное письмо доступно на `/email/verify`, восстановление — на `/forgot-password`. Обе ссылки действуют 60 минут; ссылка восстановления одноразовая. Пароль меняется в `web.users`, как при смене пароля в кабинете; игровые SRP-данные остаются под управлением механизма билетов лаунчера. Локально можно оставить `MAIL_MAILER=log`: тогда письма записываются в лог. Для проверки реальной доставки используй свой аккаунт: зарегистрируй его, подтверди почту, затем запроси восстановление. В обоих письмах отправитель должен быть `MoonWell `, а ссылки вести на `APP_URL`. ## Логотип сайта, писем и отправителя Иконки сайта находятся в `public/branding/`, многоразмерный favicon — в `public/favicon.ico`. Шаблон уведомлений использует `public/branding/moonwell-mail-logo.png` как встроенное CID-изображение: логотип прикрепляется к письму, а не загружается с чужого сервера. Для значка рядом с отправителем подготовлен векторный логотип SVG Tiny P/S: `https://moon-well.online/branding/moonwell-bimi.svg`. В DNS-панели REG.RU добавляется запись: ```text Тип: TXT Имя: default._bimi Значение: v=BIMI1; l=https://moon-well.online/branding/moonwell-bimi.svg; ``` Полное имя записи — `default._bimi.moon-well.online`. Нужен только один BIMI TXT для этого имени. Запись применяется ко всем отправителям домена, включая `support` и `no-reply`. Публиковать её следует после загрузки SVG на production. Текущая политика DMARC `p=reject` соответствует требованию BIMI; ослаблять её не требуется. Это самостоятельная BIMI-запись без сертификата: наличие записи не гарантирует отображение логотипа у получателя. Gmail требует дополнительно VMC или CMC от удостоверяющего центра. После выпуска сертификата его цепочка PEM размещается по HTTPS, а в TXT добавляется `a=https://…/certificate.pem`. Обычный TLS-сертификат сайта или SMTP не заменяет VMC/CMC. Требования: [Google Workspace](https://knowledge.workspace.google.com/admin/security/set-up-bimi), [формат SVG BIMI Group](https://bimigroup.org/creating-bimi-svg-logo-files/). Проверка после публикации DNS: ```bash dig +short TXT default._bimi.moon-well.online curl --fail --head https://moon-well.online/branding/moonwell-bimi.svg ``` ## Резервное копирование В бэкап должны попадать оба именованных volume: - `stalwart-config`; - `stalwart-data`. Перед восстановлением используй ту же minor-версию образа Stalwart, что указана в `compose.mail.yaml`. ## TLS на production-сервере На production сертификат выпускает системный Certbot через Nginx. Контейнер получает read-only каталог `MAIL_TLS_DIR` и использует: ```text /run/stalwart-tls/fullchain.pem /run/stalwart-tls/privkey.pem ``` Deploy-hook Certbot копирует обновлённые файлы в этот каталог и перезапускает только контейнер Stalwart, чтобы он перечитал сертификат. Hook устанавливается из `scripts/deploy-mail-certificate.sh`. Certbot запускает deploy-hook для каждого обновлённого сертификата. Скрипт проверяет, что сертификат покрывает `mail.moon-well.online` (`MAIL_TLS_HOSTNAME`), и пропускает сертификаты других сайтов. Иначе обновление сертификата основного сайта подменит сертификат SMTP/IMAP. Внешний HTTPS-доступ к панели и JMAP проксируется через Nginx. Готовая конфигурация находится в `ops/nginx-mail.conf`; внутренний HTTP-порт Stalwart остаётся доступен только на `127.0.0.1`. После установки сертификата его нужно добавить в Stalwart и выбрать как сертификат по умолчанию. Для HTTP-настроек за Nginx также включается `useXForwarded`, чтобы автоматические блокировки применялись к реальному адресу клиента, а не к Docker gateway. Если Nginx возвращает 502, а Stalwart работает и пишет `security.ip-blocked ... remoteIp = `, проверь блокировку адреса шлюза Docker в `Settings → Security → Blocked IPs`. Сними блокировку только с этого адреса и добавь именно его в `Allowed IPs`, затем перезагрузи настройки. Адрес шлюза можно узнать через `docker inspect`. HTTP-порт Stalwart должен оставаться доступным только на loopback-интерфейсе хоста; Nginx передаёт реальный адрес клиента в HTTP-заголовках. Не добавляй весь интернет в разрешённые адреса и не отключай auto-ban.