Почтовый сервер

Наша задача – перейти с sendmail и почтовых ящиков в формате mailbox на связку postfix+cyrus-imapd, с хранением паролей пользователей в базе MySQL и организацией виртуальных почтовых доменов.
Для удобства доступа и администрирования будем использовать web-cyradm для администрирования почтовых ящиков и squirrelmail в качестве веб-интерфейса для почты.

Cyrus IMAPD

Cyrus IMAPD – сервер, обеспечивающий доступ к почте по протоколам IMAP и POP3.

Почта не привязана к локальным пользователям системы. Почтовые ящики хранятся в своем формате в отдельном каталоге, пароли могут проверяться различными способами, которые доступны через библиотеку SASL. Можно хранить пароли в базе My SQL, в sasldb или проверять через любые PAM модули. В состав Cyrus IMAPD входят программа для локальной доставки почты.

Внимание Необходимо сменить владельца /etc/imapd.conf на cyrus и отобрать у «прочих» права на чтение
chown cyrus /etc/imapd.conf
chmod o-r /etc/imapd.conf

/etc/imapd.conf
================
configdirectory: /var/lib/imap

#Где хранятся почтовые ящики
partition-default: /var/spool/imap

#Список администраторов, которые могут управлять почтовыми ящиками.
admins: cyradm

allowplaintext: 1
sievedir: /var/lib/imap/sieve
sendmail: /usr/sbin/sendmail

#Не трогаем 8ой бит.
munge8bit: 0

#Все ящики в нижнем регистре. При подключении клиентов регистр преобразуется.
username_tolower: 1

#Дает возможность использовать имена с точками. Если стоит "0", то точка используется как разделитель в системе почтовых каталогов.
unixhierarchysep: 1

#Для повышения производительности каталог с почтовыми ящиками разбивается на подкаталоги по алфавиту
# /var/spool/imap/a/, /var/spool/imap/b/ и т.д.
hashimapspool: true

#Проверка пойдет через PAM
sasl_pwcheck_method: saslauthd
# PLAIN - способ получения пароля от клиента, только PLAIN подойдет для проверки в файлах (базе) с паролями.
sasl_mech_list: PLAIN

#Список виртуальных доменов, для которые мы держим почтовые ящики
loginrealms: mydomain1.my mydomain2.my

#Сертификаты для шифрованного соединения
tls_cert_file: /usr/share/ssl/certs/cyrus-imapd.pem
tls_key_file: /usr/share/ssl/certs/cyrus-imapd.pem
tls_ca_file: /usr/share/ssl/certs/ca-bundle.crt

# Если мы хотим проверять пароли в БД с помощью встроенных модулей sasl, можно добавить
sasl_pwcheck_method: auxprop saslauthd
sasl_auxprop_plugin: sql
sasl_sql_engine: mysql
sasl_sql_user: mailadmin
sasl_sql_passwd: mailpasswd
sasl_sql_hostnames: localhost
sasl_sql_database: maildb
sasl_sql_statement: select password from accountuser where username = '%u' and domain_name = '%r'

(см. Аутенификация SASL)

/etc/cyrus.conf
Все по умолчанию

Программа cyradm

cyradm – скрипт на Perl для управления почтовыми ящиками по протоколу IMAP. Запуск

cyradm -u cyradmin localhost

cyradm можно использовать в диалоговом режиме, либо перенаправлять ему вывод какого либо скрипта

Создание почтового ящика и установка квоты 100МБ

cm user/newuser
sq user/newuser 100000

Удаление ящика
sam user/newuser cyradm c
dm user/newuser

Восстановление индексных файлов в порушенном ящике
sudo -u cyrus /usr/lib/cyrus-imapd/reconstruct user/john.dou

Postfix

Переход на Postfix с sendmail в CentOS осуществляется почти автоматически.
Устанавливаем postfix
yum install postfix
Правим конфигурационные файлы в каталоге /etc/postfix, удаляем Sendmail, cтроим hash для файла aliases, стартуем Postfix и добавляем его в список загружаемых при старте демонов

vi /etc/postfix/main.cf
rpm -e sendmail
newaliases
/sbin/service postfix start
/sbin/chkconfig postfix on

Замечательные русские инструкции по настройке Postfix можно найти здесь: http://sergeysl.pnz.ru/freebsd/mailsystem.php
Данная страница посвящена решению некоторых специфических задач конфигурации.

Альтернативные программы

В CentOS используется специальный механизм выбора версии программы, имеющей несколько реализаций. К таким программам относятся почтовые серверы, принт серверы, различные варианты java. В каталоге /etc/alternatives/ сделаны символические линки на реально установленные программы например, /etc/alternatives/mta изначально является символическим линком на /usr/lib/sendmail.sendmail. При удалении Sendmail происходит замена и /etc/alternatives/mta становится символическим линком на /usr/lib/sendmail.postfix. Файл /usr/sbin/sendmail является в свою очередь линком на /etc/alternatives/mta. Т.к. Postfix обрабатывает те же опции при запуске, что и Sendmail, подмену никто не заметит. Аналогичная ситуайия с mailq, newaliases, rmail.

Борьба со спамом и вирусами

Желательно установить Greylisting, clamav, spamassasin и/или mimedefang

yum install postgrey clamav clamd spamassassin mimedefang

Чтобы установка прошла атоматически, надо подключить к списку репозиториев yum'а Dag RPM Repository ( http://dag.wieers.com/rpm/ )
Возможны некоторые проблемы с зависимостями mimedefang с sendmail. (Похоже там явно прописана зависимость от rpm-пакета sendmail).
Подключение этих программ к Postfix будет описано ниже, при описании конфигурационных файлов.

Mimdefang подключится если у нас Postfix версии 2.4

Правим права доступа

В файле /etc/sysconfig/mimedefang (Проверить)
MX_USER=postfix

chown -R postfix.postfix /var/spool/MIMEDefang

MIMEDefang ожидает что сокет clamd расположен в /var/spool/MIMEDefang/clamd.sock, причем это прошито в коде /usr/bin/mimedefang.pl. Clamd по умолчанию помещает свой сокет в /tmp/clamd.socket. Попробуем сделать линк (Проверить)

ln -s /tmp/clamd.socket /var/spool/MIMEDefang/clamd.sock

По умолчанию MIMEDefang запускает Spamassassin с конфигурационным файлом /etc/mail/sa-mimedefang.cf, а пакет spamassassin устанавливает свой конфиг в /etc/mail/spamassassin/local.cf. Чтобы не было путаницы удаляем /etc/mail/sa-mimedefang.cf, MIMEDefang переключится на /etc/mail/spamassassin/local.cf автоматически.

Для postgrey прописываем белые листы:

Пользователи которым нельзя задерживать доставку почты ни под каким видом
Файл /etc/postfix/postgrey_whitelist_recipients

abuse@
quickaccess@

Локальные сети
Файл /etc/postfix/postgrey_whitelist_clients.local

192.168.100

К сожалению маска сети не предусмотрена. Если ваша подсеть больше или меньше стандартного класса, то придется перечислять все подсети или IP адреса (может получиться до 128 строк на подсеть)

Теперь надо включить postgrey, clamd, spamassassin и mimedefang в автозапуск.
/sbin/chkconfig clamd on
/sbin/chkconfig spamassassin on
/sbin/chkconfig mimedefang on

Файл /etc/postfix/main.cf
Основной конфигурационный файл Postfix'а описывающий «политические» параметры (контроль доступа, виртуальные домены и т.п.).
Полный список параметров и их значения по умолчанию можно посмотреть в main.cf.default
Ограничения на пересылку почты
Перед первым запуском правим имя хоста. Скорее всего оно определится из hostname, но лучше подстраховаться.

myhostname = mail.my.net
myorigin = $mydomain

myorigin подменяет почтовый домен для почты отправляемой с локальной машины. Нынче многие почтовые серверы проверяют наличие MX записи для адреса отправителя. В приведенном примере MX запись для my.net скорее всего существует, а для mail.my.net не существует. Почта с локальной системы, например диагностические сообщения, без установки myorigin будет блокироваться.

Ограничения на пересылку почты определяютя так
mydestination = $myhostname, localhost.$mydomain, localhost
mynetworks = 168.100.189.0/24, 127.0.0.0/8
smtpd_recipient_restrictions =
permit_mynetworks,
reject_unauth_destination,
check_policy_service unix:postgrey/socket

Результат ограничений – разрешаем пересылку почты из локальных сетей. Из остального мира после аутенификации и прохождения greylisting'а, либо для наших пользователей из списка почтовых доменов mydestination и прохождения greylisting'а. (есть еще список виртуальных пользователей, но оних ниже).
(Неприятный вопрос, будеть ли greylisting пропускать аутенифицированных пользователей?)
Пример других ограничений http://www.opennet.ru/tips/info/813.shtml

Подключение mimedefang для Postfix версии >= 2.4. Postfix 2.3.3 параметр воспринял, но Mimedefang выдал ошибки протокола при попытке отправить письмо.
smtpd_milters = unix:/var/spool/MIMEDefang/mimedefang.sock
milter_default_action = tempfail

В этом варианте spamassassin и антивирус запустятся через MIMEDefang.

Доставка почты

Почта предназначенная для локальных пользователей может доставляться
в классический файл формата mailbox

mail_spool_directory = /var/mail

или в каталог Maildir

home_mailbox = Maildir/

или с помощью внешней программы (если надо проверять на вирусы только входящую почту, то здесь можно вставить антивирусный фильтр)

mailbox_command = /usr/bin/procmail

или по протоколу lmtp если Postfix используется в связке с Cyrus IMAPD

mailbox_transport = lmtp:unix:/var/lib/imap/socket/lmtp

Можно описать собственный транспорт в файле /etc/postfix/master.cf

Файл /etc/postfix/master.cf

Конфигурационный файл, описывающий «технические» параметры (запускаемые почтовые службы и их настройки).

Подключение spamassassin и антивируса для Postfix версии < 2.4.
Проверяем только SMTP

#smtp inet n - n - - smtpd
smtp inet n - n - - smtpd -o content_filter=avfilter:dummy
...
avfilter unix - n n - - pipe
flags=R user=clamav argv=/usr/local/sbin/avfilter.sh -f ${sender} -- ${recipient}

Файл /usr/local/sbin/avfilter.sh может быть таким

#!/bin/sh
INSPECT_DIR=/tmp #Каталог куда будут сохраняться письма для сканирования
SENDMAIL="/usr/sbin/sendmail -i"
VIRUSADMIN="root@my.net" # адрес для уведомлениий

EX_TEMPFAIL=75
EX_UNAVAILABLE=69

# строка для запуска spamassassin
FILTER_SPAMC="/usr/bin/spamc"
#FILTER_SPAMC="/usr/bin/spamc -u spamfilter -U /var/run/spamd.sock"
# строка для запуска clamav
FILTER_CLAMAV="/usr/bin/clamdscan -v --no-summary --stdout"

trap "rm -f $INSPECT_DIR/in.$$ $INSPECT_DIR/vr.$$ $INSPECT_DIR/vr1.$$" 0 1 2 3 15

# Проверка на спам
cat | $FILTER_SPAMC > $INSPECT_DIR/in.$$ || { echo Cannot save mail to file; exit $EX_TEMPFAIL; }

# Проверка на вирусы
$FILTER_CLAMAV ${INSPECT_DIR}/in.$$>$INSPECT_DIR/vr.$$

# Результат проверки
AV_RESULT=$?

case "$AV_RESULT" in
0)
# Проверено. Мин нет :)
$SENDMAIL "$@" <${INSPECT_DIR}/in.$$
exit 0
;;
1)
# Обнаружен вирус. Посылаем уведомление админу
echo "Subject: VIRUS FOUND" >> $INSPECT_DIR/vr1.$$
echo >> $INSPECT_DIR/vr1.$$
echo "************************************************" >> $INSPECT_DIR/vr1.$$
echo "* MAIL *" >> $INSPECT_DIR/vr1.$$
echo "************************************************" >> $INSPECT_DIR/vr1.$$
echo >> $INSPECT_DIR/vr1.$$
# Включаем в отчет реальные адреса релеев
grep Received $INSPECT_DIR/in.$$ >> $INSPECT_DIR/vr1.$$
echo "Mail from: $2 (may be forget)" >> $INSPECT_DIR/vr1.$$
echo "To: $4" >> $INSPECT_DIR/vr1.$$
grep Subject $INSPECT_DIR/in.$$ >> $INSPECT_DIR/vr1.$$
echo >> $INSPECT_DIR/vr1.$$
echo "************************************************" >> $INSPECT_DIR/vr1.$$
echo "* Virus(es) *" >> $INSPECT_DIR/vr1.$$
echo "************************************************" >> $INSPECT_DIR/vr1.$$
# Включаем в отчет список вирусов
cat $INSPECT_DIR/vr.$$ >> $INSPECT_DIR/vr1.$$
$SENDMAIL -f $VIRUSADMIN -r $VIRUSADMIN -F "Antivirus" $VIRUSADMIN < $INSPECT_DIR/vr1.$$
exit 0
;;
*)
# Произошла ошибка в работе антивируса. Сообщим об ошибке админу
echo "Subject: ANTIVIRUS FAILED" >> $INSPECT_DIR/vr1.$$
echo >> $INSPECT_DIR/vr1.$$
echo "************************************************" >> $INSPECT_DIR/vr1.$$
echo "* Antivirus Failed with next problem *" >> $INSPECT_DIR/vr1.$$
echo "************************************************" >> $INSPECT_DIR/vr1.$$
case "$AV_RESULT" in
40)
echo "* Unknown option passed. *" >> $INSPECT_DIR/vr1.$$
;;
50)
echo "* Database initialization error. *" >> $INSPECT_DIR/vr1.$$
;;
52)
echo "* Not supported file type. *" >> $INSPECT_DIR/vr1.$$
;;
53)
echo "* Can't open directory. *" >> $INSPECT_DIR/vr1.$$
;;
54)
echo "* Can't open file. (ofm) *" >> $INSPECT_DIR/vr1.$$
;;
55)
echo "* Error reading file. (ofm) *" >> $INSPECT_DIR/vr1.$$
;;
56)
echo "* Can't stat input file / directory. *" >> $INSPECT_DIR/vr1.$$
;;
57)
echo "* Can't get absolute path name of current *" >> $INSPECT_DIR/vr1.$$
echo "* working directory. *" >> $INSPECT_DIR/vr1.$$
;;
58)
echo "* I/O error, please check your filesystem. *" >> $INSPECT_DIR/vr1.$$
;;
59)
echo "* Can't get information about current user *" >> $INSPECT_DIR/vr1.$$
echo "* from /etc/passwd. *" >> $INSPECT_DIR/vr1.$$
;;
60)
echo "* Can't get information about user *" >> $INSPECT_DIR/vr1.$$
echo "* clamav (default name) from /etc/passwd. *" >> $INSPECT_DIR/vr1.$$
;;
61)
echo "* Can't fork. *" >> $INSPECT_DIR/vr1.$$
;;
63)
echo "* Can't create temporary files/directories *" >> $INSPECT_DIR/vr1.$$
echo "* (check permissions). *" >> $INSPECT_DIR/vr1.$$
;;
64)
echo "* Can't write to temporary directory (please *" >> $INSPECT_DIR/vr1.$$
echo "* specify another one). *" >> $INSPECT_DIR/vr1.$$
;;
70)
echo "* Can't allocate and clear memory (calloc). *" >> $INSPECT_DIR/vr1.$$
;;
71)
echo "* Can't allocate memory (malloc). *" >> $INSPECT_DIR/vr1.$$
;;
*)
echo "Unknown error $AV_RESULT" >> $INSPECT_DIR/vr1.$$
;;
esac
echo "************************************************" >> $INSPECT_DIR/vr1.$$
$SENDMAIL -f $VIRADMIN -r $VIRADMIN -F "Antivirus" "$VIRADMIN" < $INSPECT_DIR/vr1.$$
exit $EX_TEMPFAIL
;;
esac
exit 0

Виртуальные домены

В Postfix используются несколько способов задания имен локальных почтовых ящиков.
1. Имена пользователей зарегистрированных в системе. Т.е. в файле /etc/passwd
2. Имена перечисленные в файле /etc/aliases
3. Почтовые ящики перечисленные в файле /etc/postfix/virtual
4.Имена, определяемые локальной программой доставки

В зависимости от подсистемы обслуживающей почтовые ящики, имена из virtual могут отображаться, а могут и не отображаться на имена пользователей из файла passwd.

Основное идеологическое отличие между /etc/aliases и /etc/postfix/virtual в том, что aliases предназначены для локальных имен (например postmaster->root->adminuser или root->root@remote.com), а файл virtual предназначен для отображения имен пользователей различных почтовых доменов, обслуживаемых данным сервером, в имена локальных или удаленных почтовых ящиков (например user@virtual.net ->user_virtual_net).
Другими словами aliases нужны для корректной доставки почты на компьютере не являющемся выделенным почтовым сервером, а virtual это средство для развертывания почтовой системы массового обслуживания.
Если используются оба файла, то вначале для определения маршрута доставки почты используется virtual, а затем, если почта должна быть доставлена в локальный почтовый ящик, aliases.

Squirrelmail

Squirrelmail - веб интерфейс к IMAP серверу/

После инсталляции размещается в /usr/share/squirrelmail, в /etc/httpd/conf.d создается конфигурация для виртуального каталога /webmail, в /etc/squirrelmail/ помещаются файлы config.php и config_local.php

Файл config.php редактируется скриптом /usr/share/squirrelmail/config/conf.pl Настройки сводятся к выбору языка и типа IMAP сервера.

Внимание! Для cyrus-imapd надо в /etc/squirrelmail/config_local.php прописать $default_folder_prefix= 'INBOX/';

Для включения ssl желательно дописать в /etc/httpd/conf.d/squirrelmail.conf

<Directory /usr/share/squirrelmail>
SSLOptions +StrictRequire
SSLRequireSSL
SSLRequire %{HTTP_HOST} eq "mail.mydomain.my"
ErrorDocument 403 https://mail.mydomain.my/webmail
</Directory>

mailman

Дистрибутив CentOS 7

Удалить письма из архива

Сначала чистим почтовый архив, потом регенерируем веб-архив, стирая старый

mutt -f  /var/lib/mailman/archives/private/mylist.mbox/mylist.mbox
/usr/lib/mailman/bin/arch --wipe mylist

Управление списком рассылки из командной строки

Программа управления списками рассылки mailman написана на Python 2 и имеет хорошо задокументированное API.

Для тех, кто не хочет программировать на python, существует несколько готовых скриптов для управления списками рассылки. В CentOS 7 они находятся в каталоге /usr/lib/mailman/bin/.

Базовые команды

Создание списка newlist [listname [listadmin-addr [admin-password]]] Если часть параметров пропущена, то она будет запрошена в интерактивном режиме.

Добавление участников рассылки add_members -r infile listname Где файл infile состоит из строк вида:

jdoe@example.com
<jdoe@example.com>
John Doe <jdoe@example.com>
"John D. Doe" <jdoe@example.com>
jdoe@example.com (John Doe)

Просмотр списка участников list_members listname. С полными именами (не дружит с Unicode) list_members -f listname

Смена административного пароля на списки рассылки change_pw. Опция -a позволяет установить один пароль на все списки, -l list1 -l list2... позволяет перечислить списки. Пароль генерируется автоматически, но его можно задать явно опцией -p pass.

Удаление списка рассылки (БЕЗ ЗАПРОСА ПОДТВЕРЖДЕНИЯ) rmlist -a listname. Опция -a указывает, что надо удалить архив сообщений.

Изменение параметров списка рассылки

Сохранение в файл основных параметров списка (без информации об участниках) config_list -o listname.conf listname. Формат вывода - программа на python, которая может быть подана на вход config_list -i listname.conf listname

Просмотр всех параметров списка dumpdb /var/lib/mailman/lists/<listname>/config.pck

Изменение параметров списка (В том числе массовое добавление полных имён участников рассылки) config_list -i infile listname. В файле infile должна находиться программа на python, в которой присваиваются значения переменным, имена которых совпадают с именами атрибутов списка рассылки. Имена переменных не совпадающих с атрибутами игнорируются. Можно присваивать значения непосредственно атрибутам объекта списка рассылки mlist, но при этом можно нарушить внутреннюю непротиворечивость конфигурации.

Примеры файлов для config_list

Отключение ежемесячного напоминания о паролях

echo send_reminders=0 > remunders0.conf
config_list -i remunders0.conf sample_list

Для добавления участникам полных имен надо найти в выдаче dumpdb /var/lib/mailman/lists/sample_list/config.pck подходящие атрибуты:

    'members': {   'student1@example.com': 0,
                   'student2@example.com': 0},
...
    'usernames': {   'student1@example.com': u'\u041f\u0435\u0440\u0432\u044b\u0439 \u0441\u0442\u0443\u0434\u0435\u043d\u0442',
                     'student2@example.com': u''},

Видно, что полные имена хранятся в формате unicode. Так, полное имя student1@example.com - "Первый студент". Можно написать присваивание какому-либо элементу массива usernames и сохранить его в файле infile:

mlist.usernames['student2@example.com'] =  u'Second Student'

Команда config_list -i infile sample_list изменит полное имя для участника student2@example.com

Аутенификация SASL (cyrus-sasl)

SASL – Simple Authentication and Security Layer, это метод аутенификации пользователя для встраивания в сетевые протоколы основанные на соединении. Ниже описана конфигурация одной из реализаций механизма - cysrus-sasl версии 2.

В cysrus-sasl существует два основных способа аутенификации: auxprop - через библиотеку, слинкованную с приложением и saslauthd - по особому протоколу через сервер аутенификации saslauthd.

auxprop позволяет проводить аутенификацию в базе данных SQL (mysql, sqlite), файле BeklyDB или в LDAP. Список вариантов проверки saslauthd можно узнать командой

# saslauthd -v
saslauthd 2.1.26
authentication mechanisms: getpwent kerberos5 pam rimap shadow ldap httpform

Один экземпляр saslauthd может использовать только один механизм аутенификации.

Не стоит использовать auxprop совместно с БД, поскольку существующая реализация требует хранить пароли БД открытым текстом. Более гибким способом является связка saslauthd + pam + pam_mysql.

Поддержка SASL включена, в частности, postfix и в cyrus-imapd. Опции SASL для cyrus-imapd прописываются в файл /etc/imapd.conf, для postfix в CentOS 7 - в файле /etc/sasl2/smtpd.conf (/usr/[local/]lib[64]/sasl2/smtpd.conf в других дистрибутивах).

Пример конфигурации с хранением незашифрованных паролей в mysql

Файл конфигурации cyrus-imapd /etc/imapd.conf

#Для отладки взаимодействия с SQL сервером (печать sql-запросов)
sasl_log_level: 5
#Для логирования необходимо вставить в конфигурацию `rsyslogd` строку
#*.=debug /var/log/debug

#Механизм запроса пароля. В данном случае в виде открытого текста.
sasl_mech_list: PLAIN

#Механизм доступа к SASL
sasl_pwcheck_method: auxprop

#Плагин, используемый через auxprop
#Сами плагины лежат в /usr/[local/]lib[64]/sasl2/
sasl_auxprop_plugin: sql

#Опции для sql плагина
# mysql - тип сервера (еще есть sqlite)
sasl_sql_engine: mysql
# Доступ к базе
sasl_sql_user: mailadmin
sasl_sql_passwd: mailpassword
sasl_sql_hostnames: localhost
sasl_sql_database: mail

# Запрос должен извлечь пароль в виде текста для пользователя %u@%r (%r - realm)
# По умолчанию вместо %r подставляется имя хоста, на котором запущен cyrus-imapd
sasl_sql_statement: select password from accountuser where username = '%u' and domain_name = '%r'

Пример использования saslauthd с postfix

Файл конфигурации postfix - /etc/postfix/main.cf

# Сервер, который будет делать проверку
smtpd_sasl_path = smtpd

smtpd_sasl_auth_enable = yes

Файл /etc/sysconfig/saslauthd содержит опции для запуска saslauthd, в том числе, используемый механизм проверки.

MECH=pam

Файл настроек sasl для демона smtpd /etc/sasl2/smtpd.conf

pwcheck_method: saslauthd
mech_list: PLAIN

Файл настроек PAM для службы smtp /etc/pam.d/smtp Приложения передают в saslauthd имя сервиса. postfix передаёт строку smtp.

#%PAM-1.0
auth required pam_mysql.so config_file=/etc/security/pam_mysql.conf [where=smtpauth=1]
account required pam_mysql.so config_file=/etc/security/pam_mysql.conf [where=smtpauth=1]

БД

В дальнейшем считаем, что в БД создана база mail, доступ к ней разрешен пользователю mailadmin с паролем mailpassword. В администраторы cyrus-imapd внесен пользователь cyradmin.
Web-cyradm предпологает следующую структуру данных для хранения паролей:

CREATE TABLE accountuser (
username varchar(255) binary NOT NULL default '',
password varchar(30) binary NOT NULL default '',
prefix varchar(50) NOT NULL default '',
domain_name varchar(255) NOT NULL default '',
UNIQUE KEY username (username)
) TYPE=MyISAM;

Миграция с Mailbox на CyrusIMAP

Перенос почтовых ящиков

Скрипт для создания пустых почтовых ящиков на основе информации в /etc/passwd

#!/usr/bin/perl -w
#
# Written by Wil Cooley <wcooley@nakedape.cc>, 25 April 2002.
#
# This script is copyright (C) 2002 by Wil Cooley and
# licensed under the GNU GPL <http://www.gnu.org//licenses/gpl.txt>
#
# Usage: migrate-pw-to-cyrus2.pl
#
# Purpose: Creates empty Cyrus mailboxes.
#
# Input: None.
#
# Notes: Set the default quota below. I used a default
# of 100MB more as a failsafe than a restriction.
#
# $Id: migrate-pw-to-cyrus2.pl,v 1.1 2002/04/26 00:56:09 wcooley Exp $
###
my $adminuser = "cyradmin" ;
my $server = "localhost" ;
my $quota = 100*1024 ; # 100MB
my $user_uid_start = 500 ;
my $err = 0 ;
my ($user,$p,$uid) ;

use Cyrus::IMAP::Admin;

$imapcon = Cyrus::IMAP::Admin->new($server) || die "Unable to connect to $server";

unless ($imapcon) {
die "Error creating IMAP connection object\n" ;
}

$imapcon->authenticate(-user => $adminuser, -mechanism => "LOGIN") ;

if ($imapcon->error) {
die $imapcon->error ;
}

print "\n" ;

setpwent() ;

while (($user,$p,$uid) = getpwent) {
if ($uid >= $user_uid_start) {
unless ($imapcon->list("user.$user")) {
$imapcon->create("user.$user") ;
if ($imapcon->error) {
print "ERROR: ", $imapcon->error, "\n" ;
next;
} ;
$imapcon->setquota("user.$user", "STORAGE", $quota) ;
if ($imapcon->error) {
print "ERROR: ", $imapcon->error, "\n";
next;
} ;
print "Created mailbox user.$user [$uid]\n" ;
}
}
}
endpwent() ;

Перенос содержимого почтовых ящиков с помощью formail и cyrus deliver

# Script to import mbox-format mailboxes to Cyrus folders
# Requires formail (from procmail)
#
# Note: As this runs cyrdeliver directly, you'll need to be
# a member of the mail group for it to work.
#
# Use this script at your own risk! I'm not responsible if
# it trashes your mail system :)
#
# By Michael-John Turner <mj@debian.org>
#

USER=$1
MAILBOX=$2
CYRUSFOLDER=$3
#CYRDELIVER=/usr/sbin/cyrdeliver
CYRDELIVER=/usr/lib/cyrus-imapd/deliver
FORMAIL=/usr/bin/formail

if ! [ -x "$FORMAIL" ]; then
echo ""
echo "formail (from procmail) is required to run this script"
echo ""
exit 1
fi

if [ "$USER" = "" ]; then
echo ""
echo "syntax: $0 user [mbox] [cyrus folder]"
echo ""
echo "If no mbox is specified, the user and mbox name are taken to be the same"
echo "If no cyrus folder is specified, the INBOX is used"
echo ""
exit 2
fi

if [ "$MAILBOX" == "" ]; then
MAILBOX=$USER
fi

if [ "$CYRUSFOLDER" == "" ]; then
echo "Adding mailbox '$MAILBOX' to Cyrus INBOX of user '$USER'..."
$FORMAIL -I "From " -s $CYRDELIVER $USER < $MAILBOX
else
echo "Adding mailbox '$MAILBOX' to Cyrus folder '$CYRUSFOLDER' of user '$USER'..."
$FORMAIL -I "From " -s $CYRDELIVER -m $CYRUSFOLDER $USER < $MAILBOX
fi

Перенос паролей

При миграции возникает желание убрать записи почтовых пользователей из /etc/passwd и перейти на хранение паролей в MySQL, LDAP или где нибудь еще. Прямого пути нет!

В качестве обходного пути можно попытаться использовать PAM-modules Сергея Позднякова http://puszcza.gnu.org.ua/software/pam-modules/

Устанавливаем pam_fshadow из указанного пакета. Копируем записи почтовых пользователей из файла /etc/shadow (/etc/master.passwd во FreeBSD) в новое место, например в /etc/mail/shadow. Пишем настройки PAM для сервисов pop, imap и, возможно, sieve.

auth sufficient pam_fshadow.so sysconfdir=/etc/mail nopass
account sufficient pam_fshadow.so sysconfdir=/etc/mail nopass

Дополнительно настраиваем SASL для проверки в MySQL. Вариант с pam_mysql менее интересен, т.к. не поддерживает виртуальные домены.

auth sufficient pam_fshadow.so sysconfdir=/etc/mail nopass
auth sufficient pam_mysql.so config_file=/etc/pam_mysql.conf
auth sufficient pam_fshadow.so sysconfdir=/etc/mail nopass
account sufficient pam_mysql.so config_file=/etc/pam_mysql.conf

Пример /etc/pam_mysql.conf
users.host=localhost;
users.database=maildb;
users.db_user=mailadmin;
users.db_passwd=mailpassword;
users.table=accountuser;
users.user_column=username;
users.password_column=password;
users.password_crypt=plain;
users.disconnect_every_operation=true;
verbose=0;
log.enabled=1;
log.table=logins;
log.message_column=message;
log.pid_column=pid;
log.user_column=username;
log.host_column=machineip;
log.time_column=logintime;

Русские буквы в почтовых ящиках IMAP

В соответствие с RFC2060 национальные символы в именах почтовых ящиков на сервере должны кодироваться в модифицированную кодировку UTF7. Отличия от оригинальной UTF7 связаны с особым значением символа '+' в некоторых почтовых системах и символа '/' в роли разделителя имён каталогов в Unix.

Алгоритм кодирования имён папок: Текст -> UTF7; & -> &-; / -> ,; + -> &

Декодирование:

echo '.&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-' \
| sed 's/&\([^-]\)/+\1/g;s/&-/&/g;s/,/\//g' \
| iconv -f UTF7 -t UTF8

.Отправленные

Использование программы mail (mailx)

Автоматическая отправка почты

echo test | mail -s test user@example.com

Отправка вложенного файла

uuencode filename ./filename | mail -s "test with file" user@example.com

Дополнительные опции при отправке

-s - Subject:
-c - Cc:
-b - BCc:
-r - From:

Редактирование почтового ящика с помощью mutt

Открыть IMAP/mailbox/Maildir

mutt -f imaps://mail.example.com/
mutt -f file.mbox

или

MAIL='/home/user/Maildir' mutt -f file.mbox

Удалить письма с определенных доменов (From:)

Shift D ~f@example.com

Удалить письма со словом SPAM в поле Subject:

Shift D ~sSPAM

Удалить все письма (два варианта)

Shift D ~s.*
Shift D ~A

Восстановить удаленное письмо с номером 1234 1234<CR>u

Команды

Список писем

Cmd Description
j,k next, previous message
1234 go to mail number 1234
= first message
* last message
d delete
D~pattern delete by pattern
u undelete
U~pattern undelete by pattern
m new message
f forward
r reply
s save message to file
v view attachment
$ delete all marked messages
x discard changes and quit
q quit

Чтение письма

Cmd Description
j,k next, previous message
d delete
u undelete
m new message
f forward
r reply
s save message to file
i return to main menu

Отправка письма

Cmd Description
t To:
s Subject:
c CC:
b BCC:
a attach file
q abort sending message
y send

Шаблоны поиска

Шаблон Описание
~A все (all)
~N новые (new)
~O старые(old)
~R прочитанные (read)
~U непрочитанные (unread)
~bEXPR поиск в теле (body) письма
~sEXPR поиск в поле Subject
~fEXPR поиск в поле From:
~tEXPR поиск в поле To:
~d [MIN]-[MAX] дата отправки Date между MIN и MAX. Дата в формате DD/MM/YY[YY] или выражение вида >, <, = число дней (d), недель (w), месяцев (m), лет (y). Например 01/01/2019 или >3m