This commit is contained in:
2026-07-14 13:21:45 +07:00
commit 4333d69125
8 changed files with 1375 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
# mcimport — массовое создание ящиков mailcow из CSV
Однобинарный инструмент (stdlib-only Go, embedded веб-морда) для провижининга
почтовых ящиков mailcow через API. Импорт файла → предпросмотр с валидацией →
потоковый журнал создания.
## Возможности
- **Проверка подключения** к API (домены/ящики читаются, чтобы подтвердить ключ и allow-list).
- **Выбор домена**: после проверки подключения можно выбрать домен из списка mailcow —
тогда в CSV достаточно логина без `@домена` (email собирается как `логин@выбранный_домен`).
- **Предпросмотр**: разбор CSV, структурная валидация (email, пароль, дубликаты),
плюс — если задан ключ — сверка с живым mailcow: пропуск существующих ящиков и
отсев несуществующих доменов.
- **Импорт** с потоковым (NDJSON) журналом в реальном времени: по строке на ящик,
разбор ответа mailcow (`success`/`danger`), счётчики, выгрузка лога в CSV.
## Формат CSV
Заголовок обязателен. Разделитель — точка с запятой (`;`); также распознаются
`,` и таб. BOM снимается, кодировка — UTF-8. Готовый образец можно скачать в UI
(ссылка «Скачать пример CSV») или по `GET /api/example`.
С выбранным в UI доменом достаточно логина:
```csv
login;password;name
ivanov;S3cretPass!;Иван Иванов
petrov;An0therPass!;Пётр Петров
```
Без выбора домена — полный email в каждой строке:
```csv
email;password;name
ivanov@bildme.ru;S3cretPass!;Иван Иванов
petrov@amega.kz;An0therPass!;Пётр Петров
```
Колонки (регистр/пробелы/подчёркивания не важны, есть RU-алиасы):
| колонка | обяз. | примечание |
|----------------------|-------|--------------------------------------------------------|
| `email` / `login` | да* | при выбранном домене — логин без `@`; иначе полный email или пара `localpart` + `domain` |
| `password` | да | <8 символов → предупреждение |
| `name` | нет | ФИО; по умолчанию = localpart |
| `quota` | нет | МиБ; иначе «квота по умолчанию» |
| `active` | нет | `1`/`0`, по умолчанию `1` |
## Запуск
### Бинарь
```bash
CGO_ENABLED=0 go build -ldflags="-s -w" -o mcimport .
MAILCOW_URL=https://mail.dom.ru ./mcimport
# открыть http://localhost:8080
```
### Docker
```bash
docker compose up -d --build
# морда на 127.0.0.1:8080 — ходите через SSH-туннель:
# ssh -L 8080:127.0.0.1:8080 user@host
```
## Переменные окружения
| переменная | по умолчанию | назначение |
|------------------------|-------------------------|---------------------------------------------------|
| `MAILCOW_URL` | — | базовый URL (можно ввести в UI) |
| `MAILCOW_API_KEY` | — | Read-Write ключ; если задан — не вводится в UI |
| `DEFAULT_QUOTA` | `10240` | квота по умолчанию, МиБ |
| `LISTEN` | `:8080` | адрес прослушивания |
| `INSECURE_SKIP_VERIFY` | `false` | отключить проверку TLS (внутренний CA) |
## Что нужно на стороне mailcow
1. UI → `Configuration → Access → Edit administrator details → API`:
создать ключ с правами **Read-Write**.
2. В `API_ALLOW_FROM` добавить IP, с которого mcimport ходит в API
(egress-IP контейнера/хоста). Иначе — отказ доступа.
3. Убедиться, что лимит «Максимум почтовых ящиков» у домена и квоты домена
покрывают импортируемую пачку.
## Общая квота домена (частая ошибка `mailbox_quota_left_exceeded`)
mailcow не даст создать ящик, если `Σ выделенных квот ящиков домена` превысит
**Domain quota** (общую квоту домена). Это не про квоту одного ящика — ставить
её в `0` (безлимит) не нужно. Предпросмотр (при заданном ключе) заранее считает
нехватку и **останавливает** импорт с подсказкой, до какого значения поднять
Domain quota.
Поднять квоту домена: mailcow UI → домен → «Domain quota», либо один вызов API:
```bash
curl -sk -X POST https://mail.dom.ru/api/v1/edit/domain \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"items":["a27.kz"],"attr":{"quota":"307200"}}' # 300 ГБ (МиБ)
```
После правки — в UI кнопка **«Повторить проверку»** (перепроверить без загрузки
файла) или **«Повторить неудавшиеся»** в журнале (досоздать только упавшие ящики).
## Замечания по безопасности
- Инструмент **stateless**: ключ и пароли нигде не пишутся на диск и не логируются.
Пароли из CSV во время предпросмотра проходят через браузер (внутренний тул) —
запускайте только в доверенной сети / за туннелем, не публикуйте наружу.
- Публикация порта в примере — только на `127.0.0.1`.
- Слабые пароли mailcow отклонит по политике; такие строки видны в предпросмотре
как предупреждение и в журнале как `danger: password_complexity`.