Миграция с MDaemon на Exim+Dovecot

в 5:15, , рубрики: dovecot, exim, FreeBSD 9.0, imap, mysql, pop, smtp, spamassassin, системное администрирование, метки: , , , , , , ,

Приветствую Вас, жители Хабра.

Недавно на работе возникла ситуация: необходимо было поднять новый почтовый сервер и перенести на него все текущие учетные записи и структуру их почтовых папок со старого сервера. Эта необходимость возникла по нескольким причинам:

  1. Количество учетных записей было ограничено 250 аккаунтами;
  2. В последнее время сервер почты стал постоянно зависать так, что помогал только хард-ресет (в свое время подметил, что перед этим довольно-таки упорно используется HDD);

Вот что было на тот момент (на платформе SuperMicro):

  • PC: CPU Intel® Xeon® X3440 2.53GHz 2.53GHz, RAM 4GB, HDD 1TB
  • OS: Windows Server 2008 Enterprise Service Pack 2
  • MTA: Alt-N MDaemon (SMTP(S)/POP(S)/IMAP(S) server, SpamD, WorldClient)

Использовалось около 240 учетных записей и папка Users (здесь вся почта) весила около 200 GB.

Что получилось (платформа Dell PowerEdge 2850)

  • PC: CPUx2 Intel® Xeon® E5430 2.66GHz 2.67GHz, RAM 4GB, HDD 408GB (RAID: 0)
  • OS: FreeBSD 9.0
  • MTA: Exim+DoveCot+SpamAssassin

Ну а теперь все по порядку.

1. Установка FreeBSD, Exim, DoveCot, SpamAssassin
1.1. Установка FreeBSD
Выбор пал на FreeBSD 9.0. Проблем с установкой никаких не возникло. Скачал iso-образ с ftp, нарезал на диск и загрузился с него. Начинается процесс установки (извините, что без скриншотов).

Некоторое время ждем, затем появляется окошко начала инсталляции системы. Жмем кнопку Install, выбираем интересующую раскладку клавиатуры, кодировку или просто жмем No. Далее выбираем интересующие компоненты для установки. Я оставил, все что было выбрано, кроме games (зачем нам игры на серваке, exim тоже неплохая игрушка), добавил ports и продолжил далее. Разметку дисков сделал вручную, по следующей схеме:

# Device        Mountpoint     FStype   Size
/dev/mfid0p2    /              ufs      20G
/dev/mfid0p3    /var           ufs      50G
/dev/mfid0p4    /home          ufs      328G
/dev/mfid0p5    none           swap     4G

В /home содержатся все maildir'ы.

После разметки дожидаемся установки системы, вводим пароль для root. Далее настройка сети, пользователей и перезагрузка (необходимости в подробном описании установки нет, так как все это можно найти на просторах Интернета).

После установки, соответственно, настройка, установка всяких sudo, perl и т.п.

1.2. Установка Exim
На установке Exim остановлюсь подробней.
Для начала определимся с задачами и необходимыми условиями:

1) Формат почтовых ящиков — maildir;
2) SMTP-авторизация;
3) Поддержка SPF, DKIM (в будущем, пока еще не крутил);
4) Поддержка quote (пока только в appendfile, потом плагин dovecot quota);
5) Поддержка MySQL;
6) Поддержка SSL.

Начнем с установки MySQL 5.1.

echo "DEFAULT_MYSQL_VER=51" >> /etc/make.conf
cd /usr/ports/databases/mysql51-server
make install clean
# Установка баз Mysql
mysql_install_db
# Старт демона
echo 'mysql_enable="YES"' >> /etc/rc.conf
echo 'mysql_db_dir="/var/db/mysql"' >> /etc/rc.conf 
/usr/local/etc/rc.d/mysql start

Если все прошло гладко, то мускул запустится, и осталось только задать root'овый пароль

mysqladmin -u root password my_password

Создаем пользователя для exim

pw useradd exim -s /sbin/nologin -b /var/mail/mqueue -g mail

Создаем БД:

mysqladmin -u root -p create database exim_db

Структура БД:

DROP TABLE IF EXISTS `accounts`;
CREATE TABLE `accounts` (
  `login` varchar(128) COLLATE utf8_bin NOT NULL DEFAULT '',
  `password` varchar(128) COLLATE utf8_bin NOT NULL DEFAULT '',
  `uid` int(11) NOT NULL DEFAULT '1002',
  `gid` int(11) NOT NULL DEFAULT '6',
  `domain` varchar(128) COLLATE utf8_bin NOT NULL DEFAULT 'domain.ru',
  `quota` varchar(16) COLLATE utf8_bin NOT NULL DEFAULT '250M',
  `status` int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`login`,`domain`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `aliases`;
CREATE TABLE `aliases` (
  `address` varchar(128) COLLATE utf8_bin DEFAULT NULL,
  `goto` varchar(128) COLLATE utf8_bin DEFAULT NULL,
  `domain` varchar(128) COLLATE utf8_bin DEFAULT 'domain.ru'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `domains`;
CREATE TABLE `domains` (
  `domain` varchar(128) COLLATE utf8_bin NOT NULL DEFAULT '',
  `status` int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`domain`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

Поля uid и gid — это UID и GID пользователя exim в нашей системе. У меня они оказались UID=1002 и GID=6. Для удобства делаем поля таблицы, заданные по-умолчанию этими значениями.
Добавляем пользователя БД exim

mysql -u root -p
Password: ***
mysql> grant all privileges on exim_newdb.* to exim@localhost identified by 'exim_password';
mysql> q

Создаем сертификат для SSL-соединений:

mkdir -p /etc/ssl/certs
cd /etc/ssl/certs
openssl req -x509 -newkey rsa:1024 -keyout favmail.pem -out favmail.pem -days 9999 -nodes

Отвечаем на кучу вопросов, и сертификат готов.
Предварительные действия для установки Exim выполнены, теперь можно заняться его установкой и настройкой.
Устанавливаем Exim:

cd /usr/ports/mail/exim
make install clean

Выбираем интересующие нас опции и убираем ненужные. Я выбрал поддержку maildir, spf, dkim, mysql. Ждем окончания установки. Exim собирается с кучей зависимостей, но займет это не так много времени.
Выключаем sendmail

echo 'sendmail_enable="NONE"' >> /etc/rc.conf
/etc/rc.d/sendmail stop

и правим /etc/mail/mailer.conf

cat /etc/mail/mailer.conf

# $FreeBSD: release/9.0.0/etc/mail/mailer.conf 93858 2002-04-05 04:25:14Z gshapiro $
#
# Execute the "real" sendmail program, named /usr/libexec/sendmail/sendmail
#
sendmail        /usr/local/sbin/exim
send-mail       /usr/local/sbin/exim
mailq           /usr/local/sbin/exim -bp
newaliases      /usr/local/sbin/exim -bi
hoststat        /usr/local/sbin/exim
purgestat       /usr/local/sbin/exim

После установки идем править конфиг. Настраивал я конфиг по трем разным мануалам, вот их источники:

Вот что получилось:

cat /usr/local/etc/exim/configure

primary_hostname = domain.ru
hide mysql_servers = localhost/exim_db/exim/exim_password
domainlist local_domains = ${lookup mysql{select domain from domains where domain='${domain}'}}
domainlist relay_to_domains = ${lookup mysql{select domain from domains where domain='${domain}'}}
hostlist   relay_from_hosts = localhost : 127.0.0.1
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data
tls_certificate = /etc/ssl/certs/favmail.pem
tls_privatekey = /etc/ssl/certs/favmail.pem
daemon_smtp_ports = 25 : 465
tls_on_connect_ports = 465
qualify_domain = domain.ru
allow_domain_literals = false
exim_user = exim
exim_group = mail
never_users = root
host_lookup = *
rfc1413_hosts = *
rfc1413_query_timeout = 5s
ignore_bounce_errors_after = 2h
timeout_frozen_after = 7d
return_size_limit = 10K
split_spool_directory = true
syslog_timestamp = no
begin acl

acl_check_rcpt:
 acl_check_rcpt:
  accept  hosts = :

  deny    domains       = +local_domains
          local_parts   = ^[.] : ^.*[@%!/|]

  deny    domains       = !+local_domains
          local_parts   = ^[./|] : ^.*[@%!] : ^.*/\.\./

  accept  senders=${lookup mysql{SELECT senders FROM whitelist 
          WHERE senders='${quote_mysql:$sender_address}'}}

  deny    message       = HELO/EHLO required by SMTP RFC
          condition     = ${if eq{$sender_helo_name}{}{yes}{no}}

  deny    message       = Go Away! You are spammer.
          condition     = ${if match{$sender_host_name} 
                          {bezeqint\.net|net\.il|dialup|dsl|pool|peer|dhcp} 
                          {yes}{no}}

  deny    message       = rejected because $sender_host_address 
                         is in a black list at $dnslist_domainn$dnslist_text
          hosts         = !+relay_from_hosts
          !authenticated = *
          log_message   = found in $dnslist_domain
          dnslists      = bl.spamcop.net : 
                        cbl.abuseat.org : 
                        dnsbl.njabl.org : 
                        pbl.spamhaus.org
  warn
         set acl_m0 = 25s
  warn
         hosts = +relay_from_hosts
         set acl_m0 = 0s
  warn
         authenticated = *
         set acl_m0 = 0s

  warn
         logwrite = Delay $acl_m0 for $sender_host_name 
                [$sender_host_address] with HELO=$sender_helo_name. Mail 
                from $sender_address to $local_part@$domain.
         delay = $acl_m0

  drop   message     = Rejected - Sender Verify Failed
         log_message = Rejected - Sender Verify Failed
         hosts       = *
         !verify     = sender/no_details/callout=2m,defer_ok
         !condition  =  ${if eq{$sender_verify_failure}{}}


  accept  domains       = +local_domains
          endpass
          message       = unknown user
          verify        = recipient

  accept  domains       = +relay_to_domains
          endpass
          message       = unrouteable address
          verify        = recipient

  accept  hosts         = +relay_from_hosts
  accept  authenticated = *
  deny    message       = relay not permitted

acl_check_data:

  warn  message = X-Spam-Score: $spam_score ($spam_bar)
        hosts   = !+relay_from_hosts
        spam    = nobody:true

  warn  message = X-Spam-Report: $spam_report
        hosts   = !+relay_from_hosts
        spam    = nobody:true

  warn  message = Subject: [***SPAM***] $h_Subject:
        hosts   = !+relay_from_hosts
        spam    = nobody


  deny  message = This message scored $spam_score spam points.
        spam    = nobody:true
        hosts   = !+relay_from_hosts
        condition = ${if >{$spam_score_int}{120}{1}{0}}


  deny message = Blacklisted file extension detected ($mime_filename)
       condition = ${if match 
                    {${lc:$mime_filename}} 
                    {N(.exe|.pif|.bat|.scr|.lnk|.com|.vbs|.cpl)$N} 
                    {1}{0}}
  accept

begin routers
dnslookup:
  driver = dnslookup
  domains = ! +local_domains
  transport = remote_smtp
  ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
  no_more

system_aliases:
  driver = redirect
  allow_fail
  allow_defer
  data = ${lookup mysql{select goto from aliases where address='${quote_mysql:$local_part}' and domain='${quote_mysql:$domain}'}}
  user = exim
  group = mail
  file_transport = address_file
  pipe_transport = address_pipe

userforward:
  driver = redirect
  check_local_user
  no_verify
  no_expn
  check_ancestor
  file_transport = address_file
  pipe_transport = address_pipe
  reply_transport = address_reply
  data = ${lookup mysql{select goto from aliases where address='${quote_mysql:$local_part}' and domain='${quote_mysql:$domain}'}}

localuser:
  driver = accept
  domains = ${lookup mysql{select domain from domains where domain='${domain}'}}
  local_parts = ${lookup mysql{select login from accounts where login='${local_part}' and domain='${domain}'}}
  transport = local_delivery
  cannot_route_message = Unknown user

begin transports

remote_smtp:
  driver = smtp

local_delivery:
  driver = appendfile
  maildir_format
  maildir_tag = ,S=$message_size
  directory = /home/mail/$domain/$local_part
  create_directory
  delivery_date_add
  envelope_to_add
  return_path_add
  group = mail
  mode = 0660
  no_mode_fail_narrower

address_pipe:
  driver = pipe
  return_output

address_file:
  driver = appendfile
  delivery_date_add
  envelope_to_add
  return_path_add

address_reply:
  driver = autoreply

begin retry

*                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h

begin rewrite

begin authenticators

auth_plain:
  driver                     = plaintext
  server_set_id              = $2
  server_prompts             = :
  public_name                = PLAIN
  server_condition           = ${lookup mysql{select login from accounts where login='${quote_mysql:${local_part:$2}}' and password='${quote_mysql:$3}'}{yes}{no}}

auth_login:
  driver                     = plaintext
  public_name                = LOGIN
  server_set_id              = $1
  server_prompts             = Username:: : Password::
  server_condition           = ${lookup mysql{select login from accounts where login='${quote_mysql:${local_part:$1}}' and password='${quote_mysql:$2}'}{yes}{no}}

auth_cram_md5:
 driver                      = cram_md5
 public_name                 = CRAM-MD5
 server_secret               = ${lookup mysql{select password from accounts where login='${quote_mysql:${local_part:$1}}'}{$value}fail} 
 server_set_id               = $1

Проверяем конфиг:

exim -bV

Exim version 4.77 #0 (FreeBSD 9.0) built 04-Jul-2012 19:16:56
Copyright (c) University of Cambridge, 1995 - 2007
Probably Berkeley DB version 1.8x (native mode)
Support for: crypteq iconv() use_setclassresources PAM Perl Expand_dlfunc OpenSSL Content_Scanning DKIM Experimental_SPF
Lookups (built-in): lsearch wildlsearch nwildlsearch iplsearch cdb dbm dbmnz dnsdb dsearch mysql nis nis0 passwd
Authenticators: cram_md5 dovecot plaintext spa
Routers: accept dnslookup ipliteral manualroute queryprogram redirect
Transports: appendfile/maildir autoreply lmtp pipe smtp
Fixed never_users: 0
Size of off_t: 8
Configuration file is /usr/local/etc/exim/configure

OK, никаких ошибок не обнаружено. Делаем ротацию логов для exim:

crontab -u exim -e

@daily /usr/local/exim/exicyclog

Проверяем распознавание локальных пользователей:

exim -bt admin
admin@domain.ru
    router = localuser, transport = local_delivery

И нелокальных

exim -bt user@www.com
user@www.com
  router = dnslookup, transport = remote_smtp
  host ASPMX.L.GOOGLE.com      [173.194.71.27] MX=10
  host ALT2.ASPMX.L.GOOGLE.com [209.85.225.26] MX=20
  host ALT1.ASPMX.L.GOOGLE.com [173.194.77.26] MX=20
  host ASPMX4.GOOGLEMAIL.com   [173.194.78.27] MX=30
  host ASPMX5.GOOGLEMAIL.com   [74.125.130.27] MX=30
  host ASPMX3.GOOGLEMAIL.com   [74.125.127.27] MX=30
  host ASPMX2.GOOGLEMAIL.com   [173.194.69.27] MX=30

Отлично, можно запускать

echo 'exim_enable="YES"' >> /etc/rc.conf
/usr/local/etc/rc.d/exim start

Проверяем авторизацию Exim. Как это сделать подробно описано здесь.
На этом пункте можно закончить настройку exim.
1.3. Установка Dovecot
Ставим dovecot также из портов

cd /usr/ports/mail/dovecot
make install clean

И настраиваем (настраивал также по вышеупомянутым ссылкам)

cat /usr/local/etc/dovecot.conf

base_dir=/var/run/dovecot/
protocols=imap imaps pop3 pop3s

ssl=yes
ssl_cert_file=/etc/ssl/certs/favmail.pem
ssl_key_file=/etc/ssl/certs/favmail.pem

protocol imap {
    listen=*:143
    ssl_listen=*:993
}

protocol pop3 {
    listen=*:110
    ssl_listen=*:995
}

disable_plaintext_auth=no
shutdown_clients=yes
log_timestamp="%b %d %H:%M:%S "
syslog_facility=mail

login_dir=/var/run/dovecot/login
login_chroot=yes
login_user=dovecot
login_process_size=64
login_process_per_connection=yes
login_processes_count=3
login_max_processes_count=3
login_greeting=Dovecot ready
login_log_format_elements=user=<%u> method=%m rip=%r lip=%l %c
login_log_format=%$: %s
first_valid_uid=1002
first_valid_gid=6

mail_access_groups=mail
mail_debug=yes
verbose_proctitle = yes
mail_location=maildir:/home/mail/%d/%n

protocol imap {
    imap_client_workarounds=delay-newmail outlook-idle netscape-eoh tb-extra-mailbox-sep
}

protocol pop3 {
    pop3_uidl_format=%08Xu%08Xv
    pop3_client_workarounds=outlook-no-nuls oe-ns-eoh
}

protocol lda {
    postmaster_address=admin@domain.ru
    auth_socket_path=/var/run/dovecot/auth-master
}


auth default {
    default_realm=domain.ru
    mechanisms=plain
    socket listen {
        master {
            path=/var/run/dovecot/auth-master
            mode=0600
            user=exim
        }
    }
    passdb sql {
        args=/usr/local/etc/dovecot-sql.conf
    }
    userdb sql {
        args=/usr/local/etc/dovecot-sql.conf
    }
    user=root
    verbose=yes
}
plugin {
}
#######################################
cat /usr/local/etc/dovecot-sql.conf

driver=mysql
connect=host=127.0.0.1 dbname=exim_db user=exim password=exim_password!
default_pass_scheme=PLAIN
password_query=select password from accounts where login='%n' and domain='%d'
user_query=select uid, gid from accounts where login='%n' and domain='%d'

Запускаем демон:

echo 'dovecot_enable="YES"' >> /etc/rc.conf
/usr/local/etc/rc.d/dovecot start

Проверяем POP(S), IMAP(S) telnet'ом или каким-либо клиентом. Если все ОК, то на этом можно закончить настройку Dovecot.

1.4. Установка SpamAssassin и настройка Exim для него
SpamAssassin можно установить двумя способами:

1) perl -MCPAN -e shell;
2) Из портов.

Я ставил из портов. SpamAssassin — это перловый модуль, и для его установки требуется куча зависимостей из тех же перловых модулей. Устанавливаем их:

cd /usr/ports/security/p5-Digest-MD5
make install clean
cd /usr/ports/www/p5-HTML-Parser
make install clean
cd /usr/ports/dns/p5-Net-DNS
make install clean
cd /usr/ports/japanese/p5-Mail-SpamAssassin
make install clean

Во время установки будет огромная куча вопросов, связанных с функциональностью тех или иных модулей.
После установки настраиваем SpamAssassin. Здесь приведу свой local.cf, который пользую уже несколько лет:

cat /usr/local/etc/mail/spamassassin/local.cf

trusted_networks 192.168.2/24
required_score 5.0

report_safe 0
rewrite_header subject [***SPAM***]
use_bayes 1
bayes_path /usr/local/etc/mail/spamassassin/bayes/
bayes_file_mode 0666
bayes_min_spam_num 1
bayes_min_ham_num 1
bayes_learn_to_journal 1
skip_rbl_checks 0
bayes_auto_learn 0

ok_languages ru en
ok_locales ru_en

score BAYES_00 0.0001 0.0001 -6.0 -6.0
score BAYES_05 0.0001 0.0001 -3.0 -3.0
score BAYES_20 0.0001 0.0001 -1.0 -1.0
score BAYES_50 0.0001 0.0001 1.6 1.6
score BAYES_60 0.0001 0.0001 2.0 2.0
score BAYES_80 0.0001 0.0001 4.0 4.0
score BAYES_95 0.0001 0.0001 6.5 6.5
score BAYES_99 0.0001 0.0001 10.0 10.0
score RDNS_NONE 0.0001 0.0001 3.0 3.0

score SUBJ_FULL_OF_8BITS 0.00
score HTML_COMMENT_8BITS 0.01
score HEADER_8BITS 0.00
score TO_NO_USER 0.01
score FORGED_MUA_OUTLOOK 0.5
score X_AUTH_WARNING 0.01
score SUBJ_HAS_UNIQ_ID 9.99
score HTTP_USERNAME_USED 9.99
score FORGED_YAHOO_RCVD 9.99
score FORGED_JUNO_RCVD 16
score UNWANTED_LANGUAGE_BODY 1.02
score MLM 5.55
score RCVD_NUMERIC_HELO 4.95

Перенес я его со своего старого сервера на MDaemon, т.к. SpamD — это урезанный до безобразия SpamAssassin.
Теперь добавляем в конфиг exim'a до acl'ов строчку

spamd_address = 127.0.0.1 783

и в ACL'ах в правило acl_check_data

acl_check_data:

#deny  message = Virus found ($malware_name)
        #malware = *

  warn  message = X-Spam-Score: $spam_score ($spam_bar)
        hosts   = !+relay_from_hosts
        spam    = nobody:true

  warn  message = X-Spam-Report: $spam_report
        hosts   = !+relay_from_hosts
        spam    = nobody:true

  warn  message = Subject: [***SPAM***] $h_Subject:
        hosts   = !+relay_from_hosts
        spam    = nobody

  deny  message = This message scored $spam_score spam points.
        spam    = nobody:true
        hosts   = !+relay_from_hosts
        condition = ${if >{$spam_score_int}{120}{1}{0}}

  accept

Запускаем spamd и рестартим exim

echo 'spamd_enable="YES"' >> /etc/rc.conf
/usr/local/etc/rc.d/sa-spamd start
/usr/local/etc/rc.d/exim restart

Готово. Теперь у нас есть новый почтовый серв и можно заняться миграцией юзеров

2. Миграция пользователей с MDaemon на Exim
2.1. Accounts and Aliases

Mdaemon хранит все учетные записи пользователей в DAT файлах, которые находятся у него в директории app. На самом деле это обычный текстовый файл и можно было бы парсить прям его, но этот же MDaemon умеет делать экспорт учеток в CSV файл. Итак, экспортируем все учетные записи командой меню: Учетные записи->Экспорт->Экспортировать учетные записи в текстовый файл, разделенный запятыми (да, очень длинное название для меню. А написать «Экспорт в CSV» религия не позволила). В директории app создастся файлик Accounts.csv, вот он то нам и нужен.
Учетки есть, теперь алиасы. Вот тут придется брать dat файл. Зовется он Alias.dat. Копируем его и правим до состояния, чтобы в нем остались только алиасы, а все комментарии в топку.
Для парсинга этих файлов и добавления учеток в БД exim'a я наваял небольшой скриптик на перле, вот его содержимое:

use strict;
use Digest::MD5 qw(md5_hex);
use DBI;

my $dsn='DBI:mysql:exim_db:192.168.2.7';
my $db_user='exim';
my $db_pass='exim_password!';
my $dbh=DBI->connect($dsn, $db_user, $db_pass)
	or die "Cann't connect to DBn";

my $acc_file="c:\Accounts.csv";
my $alias_file="c:\Alias.dat";

open(ACFILE, $acc_file);
open(ALIASFILE, $alias_file);
my @line=<ACFILE>;
my @alias=<ALIASFILE>;

my @arr;
my @arr1;

my $login;
my $password;
my $mquota;
my $mdir;

my $sq

sub  sql_query
{
	my ($query)=@_;
	#print $query."n";

	my $sth=$dbh->prepare($query);
	$sth->execute;
	$sth->finish;
}

print "Adding user accountsn";

foreach my $s(@line)
{
	@arr=split(/,/, $s);
	if ($arr[0] =~ m/Email/g) {
		next;
	}
	$login=$arr[0];
	$password=$arr[5];
	
	$login =~ s/"//g;
	$login =~ s/@domain.ru//;
	
	if($arr[17]>0)
	{
		$mquota=$arr[17]/1000;
	} else { $mquota=0; }
	
	$sql=qq(INSERT INTO accounts(login, password, quota) VALUES("$login", $password, $mquota));
	sql_query($sql);
	print $login." added OKn";
	
}

print "nAdding aliasesn";

foreach my $s(@alias)
{
	@arr1=split(/ /, $s);
	$arr1[2] =~ s/n//;
	
	$arr1[0] =~ s/@domain.ru//;
	$arr1[2] =~ s/@domain.ru//;
	
	my $goto=$arr1[2];
	my $address=$arr1[0];
	#print $goto."n";
	
	$sql=qq(insert into aliases(address, goto) values('$address', '$goto'));
	sql_query($sql);
	print "Alias ".$address." => ".$goto." added OKn";
}

Ну вот практически и все. Осталось перетащить почту юзерей.

2.2. Синхронизация mailbox'ов
Для синхронизации юзерских ящиков я использовал утилитку imapsync, о которой мне рассказале на еще на ЛОРе, когда я там поднимал тему миграции.
Ставим imapsync из портов

cd /usr/ports/mail/imapsync
make install clean

Далее я написал пару скриптов, хотя можно было бы и обойтись одним. Первый скрипт формирует csv файл для imapsync'a, а второй запускает его. Вот их содержимое

# Creating CSV file for imapsync
#

#!//usr/bin/perl

use strict;
use DBI;

my $dsn="DBI:mysql:exim_db:localhost";
my $db_user="exim";
my $db_password="exim_password";

my $dbh=DBI->connect($dsn, $db_user, $db_password) or die "Cannt connect to DB";

my $f_csv="imap_users.csv";

open(CSV, ">".$f_csv);

my $sql="select login, password from accounts";
my $result=$dbh->prepare($sql);

$result->execute;

while ((my $login, my $password)=$result->fetchrow_array) {
    print CSV $login.";".$password.";".$login.";".$password."n";
}

print "File $f_csv is createdn";
close(CSV);

$result->finish;

#-------------------------------------------------------------------

# imapsync
#!/usr/bin/perl

my $f_csv="imap_users.csv";

my $src="192.168.2.3";
my $dst="127.0.0.1";

open(CSV, $f_csv);

while(<CSV>) {
    chomp;

    my ($u1, $p1, $u2, $p2)=split(";");
    #print $p1."n";
    print "Sync user $u1n";
    my $r_sync=system("imapsync --debug --host1 $src --user1 $u1 --password1 $p1 --host2 $dst --user2 $u2 --password2 $p2");
}

close(CSV);

После запуска последнего, ждем долго, долго, долго, пока все 200GB не перекочуют со старого сервера, на новый.

3. Итоги
Спустя несколько часов, я как раз дописал эту статью, прошла синхронизация. Я проверил несколько почтовых ящиков с помощью разнообразных клиентов. Изменений не замечено, все как было, так и осталось. Все письма на месте. Единственный недостаток, если юзать POP3, то все письма будут якобы непрочитанным, но это неважно.
Надеюсь, кому-то поможет эта статья. Если у вас остались какие либо вопросы, задавайте их в комментариях.

Спасибо за внимание.

Автор: zloywolk

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js