mail/README.md
deeily 5024bf9a8d init: full mail stack — phases 0..8 (web client, admin, IMAP/SMTP,
sieve, search, sessions, dramatiq, deploy/install, ELK, monitoring)
2026-04-29 16:30:43 +03:00

149 lines
7.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Mail
Веб-почта + админка почтового сервера для внутренней платформы. Встраивается
через iframe в основной сайт. Аналог Roundcube/Nextcloud-Mail с управлением
сервером.
## Возможности
- **Почта**: системные и пользовательские IMAP-папки, треды по теме,
фильтры (Все/Непрочитанные/С флагом/Важные/С вложениями), пометки звезды/важности,
поиск через Meilisearch, drag-drop чипов между To/Cc/Bcc, paste-файлов из буфера.
- **Compose**: чипы получателей с автодополнением (контакты + DMS-mailboxes),
Markdown с тулбаром и preview, подписи, вложения (drag-drop + buffer),
отложенная отправка через Redis (переживает закрытие вкладки),
свернуть-в-вкладку, автосейв черновиков в IMAP Drafts.
- **Realtime**: IMAP IDLE → SSE → новые письма без перезагрузки + автоматическая
индексация в Meilisearch.
- **Админка** (`/admin/`): дашборд, ящики, алиасы, домены с DNS-визардом
(3 шага: записи → проверка через `dnspython` → DKIM + первый ящик),
редактируемые настройки приложения, аудит-лог, активные сессии,
карточка ELK с одной кнопкой «Применить».
- **Аутентификация**: логин по IMAP-паролю, server-side сессии в Postgres
(Fernet-шифрованный пароль), rate-limit 5/60с, fail2ban-релакс на DMS.
- **Авто-очистка**: корзина чистится в фоне раз в 6 ч (Dramatiq), retention настраивается.
- **ELK-shipping**: rsyslog-конфиг отправляет логи Flask/Dramatiq/Postfix/Dovecot
на удалённый Logstash. Альтернатива через Filebeat в `deploy/elk/`.
- **Бэкапы**: ежедневный cron (postgres dump + redis snapshot + maildir tar.gz).
- **Мониторинг**: `/api/health` с глубокими проверками (DB/Redis/IMAP/Meili/queues/postqueue).
## Стек
- **Python 3.13 + Flask 3** (Jinja SSR), gunicorn + gevent
- **SQLAlchemy 2 + Alembic** — `signatures`, `groups`, `shared_mailboxes`,
`autoreply`, `rules`, `user_sessions`, `audit_log`
- **Dramatiq** (Redis broker) — отложенная отправка, очистка корзины,
realtime-индексация
- **docker-mailserver v14** — Postfix + Dovecot + Rspamd
- **Postgres 16**, **Redis 7**, **Meilisearch 1.x**
## Быстрая установка (production)
Свежий Debian/Ubuntu, всё готово через единый installer:
```bash
git clone <repo-url> /home/deeily/mail
cd /home/deeily/mail
sudo bash deploy/install.sh
```
Что делает установщик:
1. Ставит docker / python3-venv / build-essential (если нет)
2. Создаёт venv, ставит `requirements.txt`
3. Копирует `.env.example → .env` + генерирует `FLASK_SECRET_KEY`
4. Поднимает docker-compose (postgres, redis, meili, mailserver)
5. Применяет fail2ban-override для DMS (Docker bridge в whitelist)
6. Применяет `alembic upgrade head`
7. Ставит systemd-юниты `mail-flask` + `mail-dramatiq` и стартует их
8. Прописывает cron для ежедневного бэкапа в 03:30
9. Ставит sudoers-entry для UI-кнопки «Применить ELK»
После установки заполнить в `/home/deeily/mail/.env`:
- `ADMINS=admin@your-domain` — кто видит /admin/*
- `IMAP_PASSWORD=…` — пароль системного IMAP-юзера
- `MAIL_SERVER_HOSTNAME=smtp.your-domain`
И перезапустить: `sudo systemctl restart mail-flask`.
## Разработка (локально)
```bash
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cp .env.example .env
# выставить USE_MOCK_MAIL=1 для офлайн-режима
cd docker && docker compose up -d postgres redis meili
cd ..
.venv/bin/alembic upgrade head
.venv/bin/python wsgi.py
```
Открыть http://localhost:5000/, логин — `admin@mail.local` / `admin123`.
## Структура
```
app/
__init__.py # Flask factory + before_request middleware
config.py # все env-параметры
db.py # SQLAlchemy engine + scoped_session
models.py # ORM
tasks.py # Dramatiq actors (send_deferred, cleanup_trash, index_new_messages)
blueprints/
mail/ # /f/<folder>?uid=… — клиент
admin/ # /admin/ + /admin/audit + /admin/domains/new (визард)
auth/ # /auth/login + /auth/logout
api/ # /api/health, /api/search, /api/contacts, /api/mail/*
settings/ # /settings/sessions, /settings/signatures, /settings/autoreply
groups/, rules/, shared/
services/
imap_client.py # IMAPClient + per-user RLock + кэши
imap_idle.py # IDLE-thread per (user,folder), SSE-фанаут, хук в Meili
smtp_sender.py # smtplib порт 587
mail_service.py # фасад для blueprints (mock ↔ real)
store.py # CRUD над Postgres-моделями
sessions.py # server-side sessions + Fernet + audit_log
sieve_builder.py # rules → managesieve.sieve, deploy через docker exec
search.py # Meilisearch wrapper
dms_config.py # обёртка над `setup` CLI DMS + verify_dns (dnspython)
templates/ # Jinja
static/ # styles.css + app.js
docker/
docker-compose.yml # postgres, redis, meili, mailserver
dms-config/ # bind-mount в DMS — postfix-main.cf, fail2ban-jail.cf, …
deploy/
install.sh # единый установщик
backup.sh # ежедневный бэкап
systemd/ # mail-flask.service + mail-dramatiq.service + install.sh
rsyslog/ # 49-mail-stack.conf + install.sh (ELK shipping)
elk/ # альтернатива через Filebeat (если rsyslog не подходит)
migrations/ # Alembic
gunicorn.conf.py # gevent, 1 worker, 2000 connections
wsgi.py # gevent monkey-patch + create_app()
```
## Эксплуатация
```bash
# Статус
systemctl status mail-flask mail-dramatiq
journalctl -u mail-flask -f
curl localhost:5000/api/health | jq
# Перезагрузка после правки .env
sudo systemctl restart mail-flask mail-dramatiq
# Бэкап вручную
/home/deeily/mail/deploy/backup.sh
# Подключить ELK
# через UI: /admin/ → карточка «ELK · отправка логов» → ELK_HOST/PORT/PROTO + «Применить»
# или вручную: sudo bash deploy/rsyslog/install.sh logstash.internal 5140 tcp
```
## Лицензия
Internal — не для публичного использования.