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

7.3 KiB
Raw Permalink Blame History

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 + Alembicsignatures, 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:

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.

Разработка (локально)

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()

Эксплуатация

# Статус
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 — не для публичного использования.