Не почту! А именно учётки и пароли!
Я не буду описывать лишний раз процесс установки mailcow, он и так прекрасно описан на сайте mailcow.
Я начну описание с генерации файла с учетными записями zimbra.
Настоятельно рекомендуется перед тем как генерировать этот файл удалить все "закрытые" и "заблокированные" почтовые ящики из zimbra, чтобы потом не блокировать их заново в mailcow.
Переходим под учётную запись zimbra
Код: Выделить всё
sudo su - zimbraКод: Выделить всё
zmprov -l gaa > /tpm/emails.txtКод: Выделить всё
user1@domain.ru
user2@domain.ru
user3@domain.ruКод: Выделить всё
spam.xxjngi@domain.ru
ham.i_psjg@domain.ru
virus-quarantine.puosbq2r@domain.ru
Теперь нужно составить из этих адресов csv файл формата:
Код: Выделить всё
"email","password","name"Код: Выделить всё
#!/usr/bin/env bash
while read -r email; do
info=$(zmprov -l ga "$email" userPassword displayName)
password=$(awk -F': ' '/^userPassword:/ {print $2}' <<< "$info")
name=$(awk -F': ' '/^displayName:/ {print $2}' <<< "$info")
printf '"%s","%s","%s"\n' "$email" "$password" "$name"
done < /tmp/emails.txt >> /tmp/users.csv
- в последней строке мы передаём конструкции while значения из файла /tmp/emails.txt
- while читает этот файл по одной строке и делает запрос zmprov -l ga "$email" userPassword displayName
- ответ на этот запрос будет иметь трёхстрочный формат, где 1 строка это коментарий, вторая строка будет иметь вид userPassword: {SSHA}<hash> а третья строка будет иметь вид displayName: Иванов Иван. Все три строки попадают в переменную info.
- При помощи awk мы присваиваем переменной password значение {SSHA}<hash>
- При помощи awk мы присваиваем переменной name значение "Иванов Иван"
- printf выводит на стандартный вывод строку из трёх строковых переменных email, password и name.
- Возвращаемся к последней строке скрипта, >> /tpm/users.csv вывод printf в итоге попадает в users.csv.
Пример содержимого файла users.csv:
Код: Выделить всё
"user1@domain.ru","{SSHA512}tzJhcu...","Иванов Иван"
"user2@domain.ru","{SSHA512}cWJxP...","Петров Петр"
"user3@domain.ru","{SSHA512}qoqzY...","Сидоров Сидр"
На запущенном сервере mailcow этот файл нужно положить в директорию с базой данных mailcow. Путь её такой:
Код: Выделить всё
sudo cp users.scv /var/lib/docker/volumes/mailcowdockerized_mysql-vol-1/_data/mailcow/Код: Выделить всё
sudo chmod 777 /var/lib/docker/volumes/mailcowdockerized_mysql-vol-1/_data/mailcow/users.csvСкачайте adminer.
Код: Выделить всё
cd /opt/mailcow-dockerized/data/web/
sudo wget https://www.adminer.org/latest-mysql.phpНапример если адрес mailcow cow.domain.ru, то adminer будет доступен по ссылке cow.domain.ru/latest-mysql.php
Введите адрес сервера mysql: mysql
Логин: root
А пароль БД можно взять из файла mailcow.conf в строке DBROOT= Внимание!!!
Прежде чем выполнять дальнейшие действия, добавьте свой домен через админку mailcow.
Я точно не знаю в какой последовательности это нужно делать, но я это делал так.
Выбираем базу данных mailcow: Выбираем SQL запрос в левом верхнем углу: Теперь вводим такой запрос:
Код: Выделить всё
LOAD DATA INFILE 'users.csv'
INTO TABLE mailbox
CHARACTER SET utf8mb4
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
(@username, @password, @name)
SET
username = @username,
password = @password,
name = @name,
local_part = SUBSTRING_INDEX(@username, '@', 1),
domain = SUBSTRING_INDEX(@username, '@', -1);
Если вы хотите выключить квоты для всех почтовых ящиков сразу, или выставить их в какое-то адекватное значение выполните запрос:
Код: Выделить всё
UPDATE mailbox
SET quota = 0;Код: Выделить всё
UPDATE mailbox
SET attributes = { "force_pw_update": "0", "force_tfa": "0", "tls_enforce_in": "0", "tls_enforce_out": "0", "sogo_access": "1", "imap_access": "1", pop3_access": "1", "smtp_access": "1", "sieve_access": "1", "eas_access": "0","dav_access": "0", "relayhost": "0", "passwd_update": "2026-06-02 12:13:19", "mailbox_format": "maildir:", "quarantine_notification": "hourly", "quarantine_category": "reject", "attribute_hash": ""};
Далее нужно заполнить таблицу aliases. Я не совсем понимаю структуру этой таблицы, но когда заводишь новый ящик туда добавляется запись типа
Код: Выделить всё
address: user1@domain.ru
goto: user1@domain.ru
domain: domain.ruА можно и скопировать из mailboxes, это уже как кому нравится. Я сделал из users.csv:
Код: Выделить всё
LOAD DATA INFILE 'users.csv'
INTO TABLE mailbox
CHARACTER SET utf8mb4
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
(@username, @password, @name)
SET
address = @username,
goto = @username
domain = SUBSTRING_INDEX(@username, '@', -1);
Код: Выделить всё
INSERT INTO quota2 (username)
SELECT m.username
FROM mailbox m
LEFT JOIN quota2 q ON q.username = m.username
WHERE q.username IS NULL;Код: Выделить всё
INSERT INTO user_acl (username)
SELECT m.username
FROM mailbox m
LEFT JOIN user_acl u ON u.username = m.username
WHERE u.username IS NULL;INSERT INTO user_acl (username) - мы делаем вставку только поля username в user_acl (остальные поля будут заполнены согласно структуре таблицы и имеют дефолтные значения.
SELECT m.username FROM mailbox m
это выборка только поля username из таблицы mailbox. m это сокращение для таблицы mailbox.
Запись можно было бы записать длиннее: SELECT mailbox.username FROM mailbox.
Далее LEFT JOIN будет искать соответствие строк в таблицах user_acl.username и mailbox.username
и инструкция INSERT INTO будет применятся только к тем значениям, которых ещё нет в таблице user_acl.
Можно значительно упростить запрос, если вы не заводили ни одного почтового ящика. Это будет выглядеть так:
INSERT INTO user_acl (username) SELECT username FROM mailbox;
Однако если вы уже успели завести хотя бы один ящик, этот запрос выдаст ошибку.
На этом работы в базой данных можно завершить.
Есть ещё одна бд, которая должна быть заполнена значениями, это _sogo_static_view, однако, она заполнилась у меня значениями автоматически. Возможно, чтобы там что-то появилось нужно открыть домен и нажать кнопку "сохранить" в админке mailcow, но это не точно.
Ещё раз повторюсь что данная статья не является инструкцией, согласованной с mailcow.
На форумах mailcow все говорят что перенести таким образом учётки не получится и надо делать весь перенос через api и в результате все пароли поменяются.
Но я вам только что расписал все шаги, по которым я прошёл чтобы полностью скопировать логины-пароли и имена с зимбры на корову, и у меня в такой конфигурации всё прекрасно работает.
Не забудьте удалить файлы latest-mysql.php и users.csv после переноса.