Мы — долго запрягаем, быстро ездим, и сильно тормозим.
www.lissyara.su —> статьи —> FreeBSD —> почтовые системы —> Возможности Dovecot 2

Возможности Dovecot 2

Автор: KontraBass.


Данный документ надеюсь будет полезен всем кого интересует настройка DOVECOT2 с 0. По шагам я расписал как настраивается dovecot и какие есть у него возможности.

Почтовый сервер — один основной домен и некоторое количество второстепенных. Я выбрал путь с хранением адреса целиком, вместе с доменной частью, подробнее об этом далее.

Начнем, предполагаем что система уже стоит, вот мой кусочек uname -a
FreeBSD mail.testdomain.local 9.1-RELEASE FreeBSD 9.1-RELEASE #0 r243826: Tue Dec  4 06:55:39 UTC 2012     root@obrian.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386

порты обновили.

Шаг 1 - MYSQL

cd /usr/ports/databases/mysql55-server/
make install && make clean

Думаю проблем с выбором компонент не возникнет.
echo 'mysql_enable="YES"' >> /etc/rc.conf

смотрим где должен находиться  конфигурационный файл  MySQL
less /usr/local/etc/rc.d/mysql-server

ищем строки

: ${mysql_dbdir="/var/db/mysql"}
: ${mysql_optfile="${mysql_dbdir}/my.cnf"}

получается   var/db/mysql/my.cnf

Создаем конфигурационный файл, скопировав из примеров
cp /usr/local/share/mysql/my-large.cnf /var/db/mysql/my.cnf

прежде чем править, обратим внимание на вывод следующей команды
/usr/local/libexec/mysqld --verbose —help

из всего вывода интересуют некоторые параметры, не отраженные в my.cnf

character-set-server                              latin1
collation-server                                  latin1_swedish_ci
log                                               /var/db/mysql/test.log
bind-address                                      (No default value)

Подредактируем некоторые параметры в my.cnf
В последствии я добавлю пару дополнительных столбцов, к моим таблицам, с русским описанием пользователей и хотелось бы  иметь их в utf8.
log файл, очень полезен для отладки и выявления того, какой именно запрос приходит серверу от приложения и приходит ли вообще.

my.cnf
[client]
default-character-set = utf8 

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

# Привязываем MySQL к loopback интерфейсу.
bind-address=127.0.0.1 

# лог мне хочется в        /var/log/
log=/var/log/mysql.log 
log-error=/var/log/mysql-error.log 

# Я хочу использовать связанные между собой таблицы, поэтому нуждаюсь в
# поддержке таблиц InnoDb. Эти таблицы медленнее MyIsam, но чем то надо 
# жертвовать. Раскомментируем:

innodb_data_home_dir = /var/db/mysql 
innodb_data_file_path = ibdata1:10M:autoextend 
innodb_log_group_home_dir = /var/db/mysql 
innodb_buffer_pool_size = 256M 
innodb_additional_mem_pool_size = 20M 
innodb_log_file_size = 64M 
innodb_log_buffer_size = 8M 
innodb_flush_log_at_trx_commit = 1 
innodb_lock_wait_timeout = 50 

[mysqldump] 
default-character-set = utf8 

Создаем соответствующий файл и выставляем необходимые права
touch /var/log/mysql.log /var/log/mysql-error.log
chown mysql:mysql /var/log/mysql*

Запускаем MySQL
/usr/local/etc/rc.d/mysql-server start
Starting mysql.

/usr/local/etc/rc.d/mysql-server status
mysql is running as pid 40233

если не завелся, то смотрим что не так
less /var/log/mysql-error.log либо в /var/db/mysql/..  error.log  если наш конфиг не подцеплен.

Можно воспользоваться готовым скриптом настройки mysql отсюда /usr/local/bin/mysql_secure_installation , либо сделать свой...

secure.mysql
# use this:  mysql < secure.mysql

drop database test; 
use mysql; 
delete from db where db='test'; 
delete from db where db='test\_%'; 
delete from user where user=''; 
# пропишем ниже пароль для root
update user set password=password('password') where user='root'; 

Разница — я не запрещаю подключения пользователем root с хостов, отличных от localhost(правда ранее, привязал сервер к localhost). Заливаем в mysql и перезапускаем mysql сервер
mysql < secure.mysql

/usr/local/etc/rc.d/mysql-server restart

Таблицы MYSQL

Рекомендую использовать файлы для создания баз данных, таблиц в mysql. Это наглядней, и при ошибке проще откатывать. Создал базу, удалил, опять создал с исправлениями.

Напишем файл с командами создающими базу с пользователями mkmaildb

Теория такова: создадим таблицу с, почти минимальным (минимум только 2 поля логин, пароль. Остальные можно сделать статическими) количеством полей, необходимых для запуска системы. Подсмотреть рекомендуемые типы и максимальную длину значений в столбцах можно, к примеру здесь /usr/local/share/doc/dovecot/example-config/dovecot-sql.conf.ext. Email идет одним полем, для возможности поддержки нескольких доменов и уникальности почтовых адресов UNIQUE. Home тоже  UNIQUE для предотвращения указания разным учетным записям одной папки сохранения почты. При раздельном хранении пользовательской и доменной частей, достигнуть этого сложно. Внимание на то, с какими home создаются пользователи  test@testdomain.ru  и test@newdomain.ru. От уникальности записей в этом поле можно было бы отказаться, если на файловой системе хранить почтовые ящики в подоменных каталогах (/MAIL/%d/%h), но уникальность в пределах домена тогда тоже невозможна. С такой конфигурацией ошибки исключены. Ящиков в не основных доменах не много, и писать domain_user для них несложно, а исключить ошибки с большим количеством ящиков в основном домене важно. Dovecot будет обращаться только к этой таблице, остальные нужны postfix.
Таблица aliases — дополнительные адреса для существующих почтовых ящиков. Значения в поле email в этой таблице зависят(обязательно должны присутствовать) от значений поля email в таблице users. При удалении учетной записи из users автоматически удаляются aliasы на нее ссылающиеся, при обновлении поля email учетной записи, обновляется соответствующий alias. Таким образом не принимается и не болтается в системе  почта на alias-ы для несуществующих учетных записей(удаленных, или не даст создать ошибочный).  Позднее создадим дополнительные таблицы, а пока хватит.

Попутно создаем пользователя mailreader, даем ему только права select на всю базу mail. В конце файла этому пользователю задается пароль. Сразу вносим некоторые записи в базу. Этого достаточно чтобы завести почтовую систему и постепенно расширить ее функциональность до требуемых пределов.

mk_mail_db.mysql
# use this:  mysql < mk_mail_db.mysql

# если что-то пойдет не так - база создастся не полностью/с ошибками
# раскомментировать строку ниже и запустить повторно с исправлениями
# drop database mail; 

# Создадим базу данных
create database mail 
DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; 

# переключимся на нее
use mail; 

# создадим таблицу содержащую имена доменов, которые мы обслуживаем
create table domains( 
domain char(32) NOT NULL UNIQUE 
); 
# внесем в нее начальные значения
insert into domains value ( 'testdomain.ru' ); 
insert into domains value ( 'newdomain.ru' ); 

# создадим таблицу с пользователями
create table users ( 
email VARCHAR(32) NOT NULL UNIQUE PRIMARY KEY, 
home VARCHAR(16) NOT NULL UNIQUE, 
password VARCHAR(64) NOT NULL
) ENGINE = InnoDB; 

# таблица псевдонимов, значения в столбце email жестко связаны
# с колонкой email из таблицы users
create table aliases ( 
alias VARCHAR(32) NOT NULL  KEY, 
email VARCHAR(32), 
FOREIGN KEY (email) REFERENCES users(email) ON DELETE CASCADE 
ON UPDATE CASCADE 
) ENGINE = InnoDB; 

# введем неких стартовых пользователей
insert into users value ('test@testdomain.ru','test','111'); 
insert into users value ('test1@testdomain.ru','test1','111'); 
insert into users value ('test2@testdomain.ru','test2','111'); 
insert into users value ('admin@testdomain.ru','admin','111'); 
insert into users value ('test@newdomain.ru','newdomain_test','111'); 
insert into users value ('admin@newdomain.ru','newdomain_admin','111');

# создадим пользователя и предоставим ему права выборки (чтения) из 
# всех таблиц в базе mail
grant select on mail.* to 'mailreader'@'localhost'; 
grant select on mail.* to 'mailreader'@'127.0.0.1'; 
grant select on mail.* to 'mailreader'@'::1'; 

# сменим базу данных на системную, где зададим пароль
# нашему пользователю mailreader
use mysql; 
update user set password=password('password') where user='mailreader'; 
flush privileges;

Внимание на то какие домены добавляем, на пользователей и на предпоследнюю строчку где ставим свой пароль.
Заливаем все это добро в  mysql
mysql < mk_mail_db.mysql -u root -p

Шаг 2 - Dovecot 2

[logb]cd /usr/ports/mail/dovecot2
make install && make clean[/log]Выбранные опции:
   [ * ]    DOCS
   [ * ]    EXAMPLES
   [   ]    GSSAPI
   [ * ]    KQUEUE
   [   ]    LDAP
   [   ]    LIBWRAP
   [ * ]    LUCENE
   [ * ]    MYSQL
   [   ]    PGSQL
   [   ]    SOLR
   [   ]    SQLITE
   [ * ]    SSL
   [   ]    VPOPMAIL

пояснения к некоторым опциям
GSSAPI —   это по части керберос, попробуем без него.
KQUEUE -   масштабируемый интерфейс уведомления о событиях, позволяет получать
           уведомления о событиях на указанные цели очень быстро.
LIBWRAP -  для введения ограничений на доступ к сервисам по IP.
LUCENE -   возможность подключить сторонний полнотекстовый поиск.
MYSQL -    будем держать базу пользователей в MYSQL
SOLR -     возможность подключить сторонний полнотекстовый поиск от apache
SSL -      защита соединения
VPOPMAIL - позволяет создавать и работать с виртуальными доменами без
           использования баз данных таких как: mysql, pgsql и т. д.

разрешим запуск dovecot при старте системы
echo 'dovecot_enable="YES"' >> /etc/rc.conf

Если  папка /usr/local/etc/dovecot/ пуста, то заполним ее конфиг файлами по умолчкнию
cp -R /usr/local/share/doc/dovecot/example-config/* /usr/local/etc/dovecot/

Приступим к настройке.
Пользователей будем использовать только виртуальных, из базы данных в mysql. Не вижу причин поддерживать две базы данных для пользователей, это только усложнит настройку, а положительных моментов я не вижу. За место хранения почтовых ящиков примем точку монтирования /MAIL.

Здесь должна быть врезка о проблеме выбора/создания/оптимизации raid/fs в зависимости от типа почтовых ящиков, которые будут использоваться.

Небольшое отступление: буду стараться использовать понятие почтовый каталог для каталогов внутри почтового ящика, видимым нами как папки Spam Drafts Sent.
mkdir /MAIL

Доступ ко всем почтовым ящикам будем осуществлять от единого vmail. Разные UID/GID усложнят настройку дополнительных фишек Dovecot ценой, возможно, большей безопасности. Чем то надо жертвовать. (честно говоря я просто не пробовал).

Создадим пользователя и группу
pw groupadd -n vmail -g 999
pw useradd -n vmail -u 999 -g vmail -s /usr/sbin/nologin

chown vmail:vmail /MAIL
chmod 750 /MAIL

Внесем минимальные настройки в конфигурационные файлы чтобы dovecot завелся. Это будет отправная точка для усложнения конфигурации.
cd /usr/local/etc/dovecot/

dovecot.conf
protocols = imap
listen = * 

Протокол я оставил только IMAP.  Без него нет возможности реализовать все то на что способен Dovecot.
dovecot-sql.conf.ext
default_pass_scheme = PLAIN 
driver = mysql 
connect = host=/tmp/mysql.sock dbname=mail user=mailreader password=password 
user_query = select concat ( '/MAIL/', home ) as home from 
users where email = '%u' 
# Внимание! выше одна строка
password_query = select password from users where email = '%u'

В файле dovecot-sql.conf.ext задаются параметры соединения с базой данных, и какие именно поля мы там запрашиваем. default_pass_scheme указывает в каком виде находятся пароли в базе данных - PLAIN (открытым текстом).
chown dovecot:dovecot dovecot-sql.conf.ext

перейдем на уровень ниже для удобства
cd conf.d/


10-auth.conf
disable_plaintext_auth = no 
auth_mechanisms = plain
#!include auth-system.conf.ext 
!include auth-sql.conf.ext


В 10-auth.conf задаются параметры аутентификации. auth_mechanisms используется клиентами при подключении. PLAIN просто текст, в открытом виде, возможно Вам понадобится добавить LOGIN, через пробел, для MS клиентов. Thunderbird достаточно PLAIN, ориентируемся на него. default_pass_scheme и auth_mechanisms могут быть разными, рассмотрим эту возможность ниже. Прежде чем выбирать в auth_mechanisms нечто сложнее чем PLAIN, нужно убедиться что все используемые клиенты смогут подключиться. А то через 2 месяца после внедрения прийдет начальник с новеньким модным  девайсом от *** и скажет хочу ...   PLAIN хоть и считается небезопасным, т. к. передает пользователя и пароль открытым текстом — есть возможность перехватить, но это типа закрывается другими средствами — SSL/TLS. (Кроме того у меня закралось подозрение что плагины к Thunderbird, типа acl.. не могут использовать не PLAIN) По своему опыту могу сказать, ориентируйтесь сразу на PLAIN с SSL/TLS. Закомментируем строку !include auth-system.conf.ext отвечающую за системных пользователей. Не вижу смысла иметь две базы пользователей.
10-logging.conf
auth_verbose = yes 
auth_debug = yes 
mail_debug = yes 

На этапе настройки видеть подробный вывод ошибок сервиса необходимо, поэтому раскомментируем нужные строчки.
10-mail.conf
mail_location = maildir:~/Maildir 
namespace inbox { 
  inbox = yes 
  list = yes 
  subscriptions = yes 
} 
mail_uid = 999 
mail_gid = 999 
first_valid_uid = 999 
last_valid_uid = 999 
first_valid_gid = 999 
last_valid_gid = 999 

Здесь находится важный параметр mail_location. Он определяет не только местоположение почтовых ящиков, но и формат в котором будет храниться почта. Доступны варианты (источник http://wiki2.dovecot.org/MailboxFormat):

mbox -  Традиционный способ хранения сообщений в UNIX. Один файл содержит несколько сообщений. Лучше сразу отказаться, если будут большие почтовые ящики  будут проблемы.
Maildir - Один файл содержит одно сообщение. Надежный выбор, так как файлы никогда не изменяются и все операции являются атомарными.
sdbox, mdbox - Собственный высокопроизводительный формат почтовых ящиков Dovecot . Сообщения хранятся в одном или нескольких файлах, каждый из которых содержит одно или несколько сообщений.

Я выбрал Maildir, надеясь на совместимость с Courier IMAP, вдруг что. Сейчас думаю, надо было повнимательнее присмотреться к sdbox, mdbox форматам.

Итак строка  
mail_location = maildir:~/Maildir
формат ящиков  maildir
местоположение /home/Maildir,   home возьмем из базы данных. Та же строка в другом виде maildir:%h/Maildir Почему не поступить проще, к примеру так: maildir:/%h/, зачем дополнительный уровень вложенности? - желательно иметь домашний каталог, отдельно от почтового, это всплывет позже при настройке, дополнений типа Sieve.
Какие переменные можно использовать в пути к почтовому ящику см. 10-mail.conf
Дополнительно можно:
сменить разделитель используемый для каталогов внутри почтового ящика. По умолчанию Maildir/.folder.subfolder  можно получить Maildir/folder/subfolder установив mail_location = maildir:/mail/~/Maildir:LAYOUT=fs (кроме визуального удобства, если будем лазить по каталогам в консоли, не вижу преимуществ). Если выберете, подсматривайте в оригинальную документацию для отслеживания где еще придется делать дополнительные телодвижения.

Хранить отдельно control файлы (вспомогательные)
dovecot-uidlist — соответсвие IMAP UID <-> Maildir filename
dovecot-keywords - Maildir filename flag (a..z = 0..25) <-> keyword name соответствие
прописав mail_location = maildir:/mail/~/Maildir:CONTROL=/var/no-quota/%u можно хранить их отдельно от почтовых сообщений. Имеет смысл только при использовании квот файловой системы.

Еще можно задать местоположение индексных файлов,
mail_location = maildir:/mail/~/Maildir:INDEX=/var/indexes/%u, этим займемся для общих почтовых каталогов. Здесь переопределять это смысла я не вижу. Можно отключить создание индексных файлов :INDEX=MEMORY.
10-master.conf
service auth { 
 mode = 0660 
    user = vmail 
    group = dovecot
} 

dovecot группу указываем заранее, иначе потом все равно всплывет при настройке квот.
10-ssl.conf
ssl = no
#ssl_cert = </etc/ssl/certs/dovecot.pem 
#ssl_key = </etc/ssl/private/dovecot.pem

пока отключим ssl, завести бы так...
15-lda.conf
lda_mailbox_autocreate = yes 

полезный параметр, позволяет автоматически создавать почтовые ящики пользователей, не только по факту появления почты для него, но и по подключению по IMAP.
auth-sql.conf.ext изменяем 2 вхождения
args = /etc/dovecot/dovecot-sql.conf.ext 

на
args = /usr/local/etc/dovecot/dovecot-sql.conf.ext 

открывем вторую консоль,
tail -f /var/log/maillog

на первой консоли
/usr/local/etc/rc.d/dovecot start
Starting dovecot.

/usr/local/etc/rc.d/dovecot status
dovecot is running as pid 2610.

netstat -na | grep LISTEN
tcp4 0 0 *.143 *.* LISTEN

смотрим есть ли ругань, на консоли. Настраиваем учетные записи в почтовом клиенте, пытаемся подключиться, смотрим лог. Для полноценного тестирования нужно настроить 3-4  учетные записи.

Что, я считаю необходимым сделать дополнительно:

Уже привычно что в почтовом клиенте, присутствуют почтовые каталоги Отправленные, Черновики, Корзина. Они могут быть созданы автоматически, почтовым клиентом. Но с этим возможны траблы. Представим, пользователь только получил учетную запись, стандартных каталогов нет, и он их создает вручную, на русском языке. Какие каталоги создадутся на сервере? На русском? Да еще если клиент показывает русские названия, а работает с папками на сервере Sent, Drafts ….

Для того чтобы избежать лишних проблем и сэкономить время и нервы в будущем, желательно, что бы стандартная структура для каждого почтового ящика создавалась автоматом.
15-mailboxes.conf
namespace inbox { 
  mailbox Drafts { 
    auto=subscribe 
    special_use = \Drafts 
}
  mailbox Trash { 
    auto=subscribe 
    special_use = \Trash 
  } 
  mailbox Sent { 
    auto=subscribe 
    special_use = \Sent 
  } 
  } 

namespace inbox это наше private namespace (подробнее об этом далее). В 15-mailboxes.conf комментариев достаточно чтобы понять что мы сделали (перевод конфигов - следующая статья).
/usr/local/etc/rc.d/dovecot restart

проверим.

Давайте для теста добавим еще свой почтовый каталог Spam
15-mailboxes.conf
mailbox  Spam { 
   auto = subscribe 
  } 

Добавляем это в конце файла до последней закрывающей фигурной скобки, т. е. внутри namespace inbox { … }
/usr/local/etc/rc.d/dovecot restart

Готово! Далее для сбора полноценного стенда нам потребуется настроить postfix.

Шаг 3 - Postfix

cd /usr/ports/mail/postfix/
make install && make clean

Опции довольно понятно расписаны.
VDA можно не ставить. Раскладыванием почтовых сообщений по ящикам будет заниматься dovecot.
Would you like to activate Postfix in /etc/mail/mailer.conf [n]?
y

Сделаем рекомендуемое:
/etc/periodic.conf
daily_clean_hoststat_enable="NO" 
daily_status_mail_rejects_enable="NO" 
daily_status_include_submit_mailq="NO" 
daily_submit_queuerun="NO" 

/etc/rc.conf
postfix_enable="YES" 
sendmail_enable="NO" 
sendmail_submit_enable="NO" 
sendmail_outbound_enable="NO" 
sendmail_msp_queue_enable="NO" 

перейдем в каталог с конфигурациооными файлами postfix
cd /usr/local/etc/postfix/

main.cf
myhostname = mail.testdomain.ru
mydomain = testdomain.local 
myorigin = $mydomain 
mydestination = mail.testdomain.local, localhost.$mydomain, 
localhost, $mydomain
# внимание! выше одна строка
mynetworks_style = subnet 
debug_peer_level = 2 

##__это новые строчки, добавим их, в конец 
###################################################### 
##               MY CONFIG                          ## 
######################################################

virtual_mailbox_domains = mysql:/usr/local/etc/postfix/virtual/domains.mysql
virtual_mailbox_maps = mysql:/usr/local/etc/postfix/virtual/users.mysql 
virtual_alias_maps = mysql:/usr/local/etc/postfix/virtual/aliases.mysql 
virtual_transport = dovecot 
dovecot_destination_recipient_limit = 1

наверное это минимальный набор изменений в main.conf, для запуска postfix в нашем случае.
Немного комментариев:
myhostname лучше указать то имя для которого у вас настроена mx запись.
mydomain указаны честно локальное имя моего сервера, он находится во внутренней сети.
mydestination — для кого мы будем принимать почту помимо виртуальных доменов, пример для мой записи: root@mail.testdomain.local root@localhost.testdomain.local  root@localhost root@testdomain.local  все эти адреса действительны и postfix для них почту принимать будет. Меня это устраивает. Это больше будет относится к хождению локальной почты(с учетом доверенных сетей), на входящую по smtp, в любом случае надо создавать жесткие правила, дополнительно. Потом. Мануалов в инете на эту тему очень много.
virtual_transport = dovecot указываем что почту для виртуальных пользователей будет доставлять dovecot (будет LDA -локальным агентом доставки). Делать доставку почты самостоятельно postfix, не будем, иначе не удастся воспользоваться всеми теми великолепными возможностями предоставляемыми dovecot. С указанным выше параметром dovecot будет LDA только для почты виртуальных пользователей, для локальных (root) доставит postfix самостоятельно. Чтобы этого не было, /var/mail не забивался и вся почта была в одном месте /MAIL, и доступ к ней был по imap сделаем ход конем:
postconf | grep alias_maps
alias_maps = hash:/etc/aliases

postfix ожидает хэш системного файла aliases здесь /etc/aliases, это ссылка на /etc/mail/aliases. Этот файл - список алиасов, которые в конечном счете указывают на root, добавим в конце еще один алиас на виртуального пользователя
/etc/mail/aliases
# в конец добавляем
root:   admin@testdomain.ru 

и создадим хеш
postalias /etc/mail/aliases

принудительно укажем смотреть на оригинальный файл
main.cf
alias_maps = hash:/etc/mail/aliases 

после этих манипуляций, вся почта адресованная root будет уходить виртуальному пользователю  admin@testdomain.ru.

Создадим файлы с параметрами подключения к базе данных.
mkdir /usr/local/etc/postfix/virtual
cd /usr/local/etc/postfix/virtual

domains.mysql
unix:file=/tmp/mysql.sock 
user = mailreader 
password = password
dbname = mail 
table = domains 
select_field = domain 
where_field = domain 

users.mysql
unix:file=/tmp/mysql.sock 
user = mailreader 
password = password 
dbname = mail 
table = users 
select_field = concat ( '/MAIL', home, '/Maildir/' ) 
where_field = email 
#additional_conditions = and act = '1'


с такой строкой
select_field = concat ( '/MAIL', home, '/Maildir/' )
постфикс сам может раскладывать письма по папкам, тем же с которыми работает dovecot (нужа опция VDA). В смысле строка правильная, но Postfix использовать у нас ее не будет.
virtual/aliases.mysql  
unix:file=/tmp/mysql.sock 
user = mailreader 
password = password 
dbname = mail 
table = aliases 
select_field = email 
where_field = alias 

Немного подкрутим безопасность файлов с паролями
chown -R root /usr/local/etc/postfix/virtual
chmod -R 640 /usr/local/etc/postfix/virtual/
chgrp -R postfix /usr/local/etc/postfix/virtual

Добавим описание транспорта dovecot в master.cf для postfix
master.cf
dovecot   unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail:vmail argv=/usr/local/libexec/dovecot/dovecot-lda 
 -f ${sender} -d ${recipient}
# Внимание! здесь две строки всего, 2я и3я - одна строка.

Обязательно на соседней консоли
tail -f /var/log/maillog

а в рабочей
/usr/local/etc/rc.d/postfix start

проверяем,
echo test | mail root

отслеживаем в другой консоли что происходит...
dovecot: lda(admin@testdomain.ru): msgid=<20130307131730.64A812A3C1@mail.testdomain.ru>: saved mail to INBOX
postfix/pipe[96643]: 779E12A3C2: to=<admin@testdomain.ru>, orig_to=<root>, relay=dovecot, delay=0.47, delays=0.05/0.01/0/0.41, dsn=2.0.0, status=sent (delivered via dovecot service)

Вроде работает.
Важно еще проверить ходимость почты между пользователями из почтового клиента. Мы уже настраивали учетные записи при проверке imap, используем их.

Ну вот, тестовый стенд для постепенного наращивания функционала собран.

Шаг 4 Postfix and Dovecot SASL

Сейчас у меня mynetworks_style имеет значение subnet, значит для всех клиентов в той же подсети что и сервер, мы будем принимать почту для доставки в чужие домены. Если клиент подключится к нашему серверу из другой подсети(инет) и попытается передать сообщение для получателя, к примеру, **@yandex.ru, то получит отказ в ретрансляции. Однако для наших учетных записей это позволить необходимо. Следовательно требуется механизм опознавания «своих».
У Dovecot уже есть такой механизм, и более того, мы его уже настроили. Postfix может им воспользоваться. Для начала из клиента попробуем отправить сообщение для произвольного адресата … test@yandex.ru. Сервер нам доверяет как локальному пользователю (mynetworks_style) и принимает сообщение без лишних вопросов для попытки доставки. Изменим это поведение.
cd /usr/local/etc/postfix/

main.cf
mynetworks_style = host

/usr/local/etc/rc.d/postfix reload

Проверим. Опять попытаемся отправить сообщение для  test@yandex.ru. Результат — сервер отвечает отказом. Все правильно, теперь он будет принимать почту для релея в чужие домены только от себя самого. Разрешим это еще для наших виртуальных пользователей. Отметим , что почта для наших виртуальных пользователей, отправляется без ограничений, так как этот сервер конечная точка для нее.

Внесем правки:
cd /usr/local/etc/dovecot/conf.d

10-master.conf
  # Postfix smtp-auth 
  unix_listener /var/spool/postfix/private/auth { 
    mode = 0660
    user = postfix 
    group = postfix 
  } 

cd /usr/local/etc/postfix/

main.cf
smtpd_sasl_auth_enable=yes 
smtpd_sasl_type = dovecot 
smtpd_sasl_security_options = noanonymous 
smtpd_sasl_path = /var/spool/postfix/private/auth 
broken_sasl_auth_clients = no 

smtpd_sasl_security_options возможны варианты
  noanonymous —   запретить аутентификацию как аноним.
  noplaintext —   запретить механизмы передающие пароль и имя пользователя
                   открытым тестом.
  nodictionary -  не использовать механизмы, которые являются уязвимыми для
                   атак по словарю.
  forward_secrecy—новый секрет для каждой сессии (нарушение одной сессии
                   не нарушает предыдущих сессий).
  mutual_auth — используется только с механизмами аутентифицирующими и
                   клиент и сервер.

Опция broken_sasl_auth_clients = yes позволяет Postfix повторить объявление AUTH в диалоге SMTP в форме, понятной некоторым кривым клиентам. Нужно включить для  Outlook, вплоть до версии 2003 и Outlook Express до версии 6. (Не забыть про механизм LOGIN вместе с ним)  Эта опция не помешает другим клиентам.

Посмотрим на некоторые SMTP ограничения postfix
postconf | grep smtpd_recipient_restrictions
smtpd_recipient_restrictions =

postconf | grep smtpd_relay_restrictions[/b]
smtpd_relay_restrictions = permit_mynetworks, reject_unauth_destination

сделаем минимум изменений:
main.cf
smtpd_relay_restrictions = 
                permit_mynetworks 
                permit_sasl_authenticated 
                reject_unauth_destination 

внимание, продолжение строки должно начинаться с пробела.
Проверим съедены ли настройки postfix-ом
/usr/local/etc/rc.d/postfix restart
postconf | grep smtpd_relay_restrictions
smtpd_relay_restrictions =
permit_mynetworks
permit_sasl_authenticated
reject_unauth_destination

/usr/local/etc/rc.d/dovecot restart

Проверяем, отправим сообщение для  test@yandex.ru, возможно в клиенте нужно поправить параметры smtp сервера для этой учетной записи. Сервер потребует аутентификации.  и попытается его доставить. (проверить smtp настройки учетной записи, не забываем, что имя пользователя в данной конфигурации полностью, типа test@testdomain.ru).

Шаг 5 — TLS, SSL

Итак пароли у нас передаются открытым текстом. Это может быть приемлемым, но не всегда. Если выбрать другой, более сложный механизм аутентификации, можно получить проблемы с неподдержкой его клиентами. Конкретнее, проблема в приложениях для мобильников, как правило они поддерживают только PLAIN, и в дополнение требуют SSL/TLS).

Немного теории с http://wiki2.dovecot.org

Первоначально поддержка SSL была добавлена для протоколов, используя отдельный  "SSL порт" (IMAPS, pop3s и т.д.), где SSL рукопожатие начинается сразу же, при  подключении клиента, и только после получения зашифрованной сессии, начинается работа регулярных протоколов. Использовать два отдельных порта для аутентификации открытым текстом  и SSL соединений считается расточительным и добавляет сложности клиентам которые, возможно, хотят использовать SSL. Появление команды STARTTLS позволяет отказаться от выделенных SSL портов.

Попробуем внедрить TLS.

Безусловно, хорошо бы поступать правильно, с публичными центрами сертификации, но ознакомившись с ценами идем создавать самоподписные сертификаты.

Разработчики dovecot о нас позаботились, можно воспользоваться готовым скриптом /usr/local/share/examples/dovecot/mkcert.sh предварительно подредактировав /usr/local/share/examples/dovecot/dovecot-openssl.cnf

cd /usr/local/share/examples/dovecot/

dovecot-openssl.cnf
C=RU 
L=Moscow 
O=TestDomainCompany 
OU=IT server 
CN=mail.testdomain.ru
emailAddress=postmaster@testdomain.ru

создадим папки в которых будут храниться сертификаты
mkdir /etc/ssl/certs /etc/ssl/private

еще полезно поправить срок действия сертификатов, параметр -days 365 в скрипте mkcert.sh. Грубо прикинем, сколько осталось до пенсии — 20*365=7300.(да, я старый) Запустим генерирование сертификатов:
sh mkcert.sh

chmod -R 0444 /etc/ssl/certs/
chmod -R 0400 /etc/ssl/private/

сертификаты готовы, права выставлены, идем настраивать dovecot
cd /usr/local/etc/dovecot/conf.d/

10-ssl.conf
ssl = yes 
ssl_cert = </etc/ssl/certs/dovecot.pem 
ssl_key = </etc/ssl/private/dovecot.pem 
ssl_require_crl = no 

10-auth.conf
disable_plaintext_auth = yes 

10-logging.conf
verbose_ssl = yes 

/usr/local/etc/rc.d/dovecot restart

Идем на клиент, проверяем что не можем подключиться к серверу по IMAP, смотрим логи. Меняем в настройках клиента — защита соединения STARTTLS. Начинается ругань, что неизвестный сертификат, соглашаемся что неизвестный, просматриваем, убеждаемся что наш сертификат, принимаем. Проверяем как работает.

Итак, чего мы достигли: теперь все пользователи подключаются к нашему серверу через зашифрованное соединение. Положительные моменты — возможность подключения мобильных приложений и пароли с пользователями в открытом виде не передаются. Отрицательные — зачем мне дополнительная нагрузка в виде шифрования для пользователей внутри моей локальной сети? Выход есть.

в dovecot.conf пропишем доверенные сети:
login_trusted_networks = 192.168.0.0/24

проверяем...

Маленькое замечание, если выбираем дополнительно LOGIN, на него распространяются все те же ограничения что и на PLAIN ( disable_plaintext_auth, …)

Итак, какие назревают варианты использования:

Сейчас установлено — все из локальной сети PLAIN с/без STARTTLS
Из остальных сетей, недоверенных - PLAIN только с STARTTLS

Можно не задавать login_trusted_networks, вернуть в 10-auth.conf disable_plaintext_auth = no, тогда кто хочет(знает как и зачем это нужно), или не может по другому, будет использовать TLS, остальные (все) не заморачиваясь — пароль и пользователя открытым текстом откуда угодно. (Правда тот же thunderbird при настройке учетной записи изначально пытается самонастроиться с TLS и, возможно не все так печально как я выше описал)

Еще вариант сделать выделенные порты только с SSL и в инет выставить только их.

Компромиссный вариант - 10-auth.conf  disable_plaintext_auth = yes, это мы запретили PLAIN аутентификацию без [SSL/TLS, login_trusted_networks пусто, никаких исключений. Добавить дополнительный механизм аутентификации, не передающий хотя бы пароль открытым текстом (см ниже).

Рассмотрим настройку выделенного порта с SSL.

10-master.conf
inet_listener imaps { 
   #port = 993 
   ssl = yes 
}

Внимательно, с фигурными скобками,
/usr/local/etc/rc.d/dovecot restart

идем на клиент, настаиваем подключение на порт 993 с SSL
принимаем сертификат, .. работает.

Дополнительные механизмы аутентификации.
Добавим механизм похитрее, чем PLAIN

Теория:

Non-plaintext механизмы были разработаны, чтобы обеспечить безопасность без SSL/TLS шифрования. Особенностью использования является то, что, они требуют доступ к простому тестовому паролю или его хэшированной по тому же методу, версии.
Если вы хотите использовать более одного non-plaintext механизма, пароли должны храниться в виде открытого текста, так что бы Dovecot мог генерировать необходимые хэши для всех различных механизмов. Если вы хотите использовать только один non-plaintext механизм, вы можете хранить пароли, зашифрованные этим механизмом.

С success/failure базами данных (например, PAM)  невозможно использовать non-plaintext механизмы, потому что они поддерживают проверку только текстового пароля.

Dovecot поддерживает следующие non-plaintext механизмы:
CRAM-MD5:   шифрует пароль. Довольно хорошая поддержка в клиентах.
DIGEST-MD5: криптографически несколько сильнее, чем CRAM-MD5
            но клиенты редко его поддерживают.
APOP: POP3  специфичная аутентификация. Похожа на CRAM-MD5,
            но требует хранения паролей в открытом виде.
NTLM:       механизм создан Microsoft и поддерживается их клиентами.
            Опционально поддерживается с помощью Winbind Samba.
GSS-SPNEGO: механизм обертка определяется RFC 4178
GSSAPI:     Kerberos v5 поддержка.
RPA:        Похож на DIGEST-MD5, но поддержка клиентов является редкостью.
ANONYMOUS:  Поддержка анонимного входа. Это может быть полезно, если вы
            собираетесь предоставлять публично доступные IMAP архивы.
OTP and SKEY: механизмы одноразовых паролей.
EXTERNAL:   внешний механизм SASL.
SCRAM-SHA-1: Salted Challenge Response Authentication Mechanism (SCRAM) SASL и GSS-API механизмов. (чего-то очень сложное :) )

Мы ориентируемся на кроссплатформенный клиент thunderbird, попробуем настроить поддерживаемый им CRAM-MD5(означеный в нем как зашифрованый пароль). Пароли в базе открытым текстом.

Уберем из  dovecot.conf доверенные сети:
# login_trusted_networks = 

10-auth.conf
disable_plaintext_auth = yes

auth_mechanisms = plain cram-md5 

/usr/local/etc/rc.d/dovecot restart


идем на клиент, в свойствах тестовой учетной записи — защита соединения — нет,
метод аутентификации — зашифрованный пароль. Проверяем.  Смотрим в логах
user=<test@testdomain.ru>, method=CRAM-MD5

ок, работает. Что мы получили — без использования TLS на порт 443 можно подключиться с зашифрованным паролем, с использованием TLS пароль — и простой текст и зашифрованный. Параметр ssl =  может иметь значение required, с ним  TLS является необходимым не только для PLAIN аутентификации, но и для любых других механизмов.

Шаг 6 -  Шифрованные пароли в базе данных

На данный момент мы имеем базу с паролями пользователей в виде простого текста. Это может быть неприемлемым. По хорошему даже администратор не должен знать пароли пользователей. Что можно сделать? Можно хранить не сами пароли, а MD5-хэши от них.
Важно: то что мы сейчас сделаем, поломает аутентификацию с паролями CRAM-MD5. Дело в том, что сейчас если dovecot получает пароль от пользователя в PLAIN то просто сравнивает со значением в базе, если получает пароль CRAM-MD5 то значение из базы подвергает обработке по этому алгоритму и сравнивает с полученным. Мы собираемся хранить в базе  MD5-хэши паролей, при PLAIN аутентификации  dovecot все еще может сделать хеш от полученного от пользователя пароля и сравнить с имеющимся хешем. Если получаем от пользователя CRAM-MD5 то что с чем сравнивать? Самого пароля нет. (решение с CRAM-MD5 ниже).

Идем в  mysql
mysql -u root -p

mysql> use mail;
mysql> select * from users;
+----------------------------+------------------------+------------+
|_______email________________|_________home___________|__password__|
+----------------------------+------------------------+------------+
| admin@newdomain.ru ________| newdomain_admin _______| 111 _______|
| admin@testdomain.ru _______| admin _________________| 111 _______|
| test1@testdomain.ru _______| test1 _________________| 111 _______|
| test2@testdomain.ru _______| test2 _________________| 111 _______|
| test@newdomain.ru _________| newdomain_test ________| 111 _______|
| test@testdomain.ru ________| test __________________| 111 _______|
+----------------------------+------------------------+------------+

На символы подчеркивания внимание не обращать(особенности оформления).
Сейчас у нас пароли открытым текстом. Используем встроенные в  mysql возможности:
mysql> update users set password=MD5(123) where email='admin@testdomain.ru';
mysql> select email, password from users where email='admin@testdomain.ru';[/b]
+---------------------+----------------------------------+
|_________email_______|___________password_______________|
+---------------------+----------------------------------+
| admin@testdomain.ru | 202cb962ac59075b964b07152d234b70 |
+---------------------+----------------------------------+
[b]\q

!!!
Внимание, здесь мной была допущена ошибка, дело в том что длина поля password в этом случае, должна быть более 64 - заданной при создании таблицы. (Спасибо Demius) Соответственно увеличьте поле до 128.
!!!

обновили пароль одной учетной записи и идем менять конфиг dovecot
dovecot-sql.conf.ext
default_pass_scheme = MD5 

/usr/local/etc/rc.d/dovecot restart


тестируем. Не забываем, тестируем на пользователе  admin@testdomain.ru
обычный пароль STARTTLS, работает - смотрим в логах method=PLAIN. Пробуем выбрать в thunderbird зашифрованный пароль для этой учетной записи. Наблюдаем ругань -
Requested CRAM-MD5 scheme, but we have only MD5

все логично, под зашифрованным паролем thunderbird имеет ввиду CRAM-MD5.

Как заставить работать  CRAM-MD5? - сказать что в базе пароли CRAM-MD5 и положить их туда. Как получить CRAM-MD5? http://wiki2.dovecot.org/HowTo/CRAM-MD5
doveadm pw
Enter new password: 123
Retype new password: 123
{CRAM-MD5}8f48a311793d494b53ad488bb603f93a0457e40fe45cbacb082c0720ceeb1e37

mysql -u root -p
mysql> use mail;
update users set password='8f48a311793d494b53ad488bb603f93a0457e40fe45cbacb082c0720ceeb1e37 ' where email='admin@testdomain.ru';
\q

   
dovecot-sql.conf.ext
default_pass_scheme = CRAM-MD5 

/usr/local/etc/rc.d/dovecot restart

Тестируем, на admin@testdomain.ru видим работает, с STARTTLS простой пароль и зашифрованный, без  STARTTLS только зашифрованный.

Отметим для себя — механизм используемый клиентом задается в 10-auth.conf,
параметром auth_mechanisms, возможно несколько, а в каком виде пароли хранятся в базе - dovecot-sql.conf.ext отвечает параметр default_pass_scheme.

Если все работает, можно обновить пароли остальным пользователям, либо вернуться к паролям открытым текстом. Я откачу к простому тексту, далее внимательнее, в конфигах будет подразумеваться PLAIN (хотя кажется больше нигде не всплывет).


Шаг 7 - Master users/passwords

Можно настроить мастер пользователей, которые смогут входить в систему под любой учетной записью. Также есть возможность войти в систему под любой учетной записью с помощью мастер-пароля, хотя это и не рекомендуется.

Начнем с Master users

Итак, что нам нужно, указать разделитель (* хороший выбор) и  2 базы данных с обычными и мастер пользователями. При использовании логина пользователь*мастер проверка мастера производится в другой базе. Работает только  при использовании PLAIN механизма SASL( с STARTTLS или без)(еще один аргумент за PLAIN). Попробуем сначала простой вариант:
Настроим рекомендуемый разделитель, и подключим auth-master.conf.ext
10-auth.conf
auth_master_user_separator = * 
!include auth-master.conf.ext 

auth-master.conf.ext
passdb { 
  driver = passwd-file 
  master = yes 
  args = /usr/local/etc/dovecot/master-users 
 pass = yes 
  } 

Создадим файл с мастер пользователем masteradmin и паролем 222 закодированным SHA (htpasswd идет в комплекте к apache серверу)
htpasswd -b -s -n masteradmin 222 > /usr/local/etc/dovecot/master-users
cat /usr/local/etc/dovecot/master-users
masteradmin:{SHA}HGY3qPLh914G/5mEiU1r0Wo6Nqk=

здесь мастер-пользователь masteradmin может быть и masteradmin@testdomain.ru, не принципиально. Кроме того, это пример из руководства, если лень извращаться с паролями, то можно и попроще, только надо в аргументах указать схему.
auth-master.conf.ext
passdb { 
  driver = passwd-file 
  master = yes 
  args = scheme=plain /usr/local/etc/dovecot/master-users 
 pass = yes 
  } 

после этого можно пароли PLAIN
echo 'masteradmin:{plain}222' > /usr/local/etc/dovecot/master-users
cat /usr/local/etc/dovecot/master-users
masteradmin:{plain}222

в официальной документации http://wiki2.dovecot.org/Authentication/PasswordSchemes есть еще варианты … «сокрытия пароля».
/usr/local/etc/rc.d/dovecot restart

Проверяем, необходимо с клиента подключиться под пользователем test@testdomain.ru*masteradmin и паролем 222, защита соединения STARTTLS или без (если disable_plaintext_auth = no), метод аутентификации, важно! - обычный пароль (работает только с PLAIN).

Мастер пользователей может быть несколько:
htpasswd -b -s -n masteradmin3 333 >> /usr/local/etc/dovecot/master-users
htpasswd -b -s -n masteradmin4 444 >> /usr/local/etc/dovecot/master-users

При наличии SQL, мастер пользователя можно хранить в общей куче с обычными пользователями, но желательно иметь признак «мастер», чтобы не все могли быть мастерами :) .

добавим поле в таблицу users
mysql -u root -p
use mail;
alter table users add column master varchar(6) DEFAULT NULL;
update users set master='master' where email='admin@testdomain.ru';
\q

мы добавили поле master длиной 6 символов, для значения master, можно выбирать другие варианты, типа tinyint(1) , памяти меньше занимать будет.... но для тестирования и наглядности, делаем так. Ввели значение master в поле master только одной учетной записи  admin@testdomain.ru

Конфиг 10-auth.conf абсолютно такой же
auth_master_user_separator = * 
!include auth-master.conf.ext 

auth-master.conf.ext
passdb { 
  driver = sql
  master = yes 
  args = /usr/local/etc/dovecot/dovecot-sql-master.conf.ext 
 pass = yes 
  } 

/usr/local/etc/dovecot/dovecot-sql-master.conf.ext
default_pass_scheme = PLAIN 
driver = mysql 
connect = host=/tmp/mysql.sock dbname=mail user=mailreader password=password 
password_query = select password from users where email = '%u' 
and master = 'master' 
# Внимание! выше одна строка

/usr/local/etc/rc.d/dovecot restart

проверяем на пользователе test@testdomain.ru подключившись к его почтовому ящику с помощью  test@testdomain.ru*admin@testdomain.ru и паролем от admin@testdomain.ru

Master passwords

Это самый простой способ:
эти два конфига как выше,
10-auth.conf
auth_master_user_separator = * 
!include auth-master.conf.ext 

auth-master.conf.ext
passdb { 
  driver = sql
  master = yes 
  args = /usr/local/etc/dovecot/dovecot-sql-master.conf.ext 
 pass = yes 
  } 

а вот этот /usr/local/etc/dovecot/dovecot-sql-master.conf.ext немного подправить
default_pass_scheme = PLAIN 
driver = mysql 
connect = host=/tmp/mysql.sock dbname=mail user=mailreader password=password 
password_query = SELECT '%u' AS user, 'master-password' AS password 

Пароль здесь жеско забивается в конфиг.

/usr/local/etc/rc.d/dovecot restart


Проверим, работает ли у нас учетная запись test@testdomain.ru*admin@testdomain.ru с паролем master-password. А теперь, настроим учетную записсь test@testdomain.ru*qwerty  с паролем  master-password. Видим, все работает, достаточно знать мастер пароль. В данном случае он жестко забит у нас в конфиге. Если сделать
password_query = SELECT 'master-password' AS password FROM users WHERE email = '%u'
включим проверку на существование мастер пользователя в нашей базе — плавно перейдем к мастер пользователям, а если
password_query = SELECT 'master-password' AS password FROM users WHERE email = '%u' and master = 'master'
то, дополнительно будем проходить проверку, что мастер пользователь является мастером, осталось только одно различие с примером мастер пользователя — различные пароли для входа мастер пользователем под собой, и под чужой учетной записью. И мастер пароль один на всех мастеров.

Я оставил настройки первого варианта, с мастерпользователями в файле. Учетная запись  test@testdomain.ru*masteradmin у меня осталась настроенной, позже надо проверить работу ACL.

Шаг 8 - QUOTA

Настройка квот очень важна на сервере, даже если у Вас 10 человек, то все равно рано или поздно получим проблемы. В основном это проблемы с огромным количеством никому не нужных сообщений, которые еще и будут  синхронизироваться по imap, и удалить их нельзя, вдруг там что-то ООЧЕНЬ важное, и чистить от неважного времени нет....

Чуть чуть теории с оф. сайта
Для начала необходимо определить корневую квоту (задать область к которой будет применяться квота) и выбрать  backend (движок) который определяет метод, как Dovecot будет отслеживает текущее использование квот.
Строка конфигурации:

quota = <backend>[:<quota root name>[:<backend args>]]

backend может быть:
  fs:      квоты файловой системы
  dirsize: Самый простой и самый медленный backend, но он достаточно хорошо
           работает с mboxes.
  dict:    Записи о использованной квоте хранится в словаре (например, SQL).
  maildir: Записи о использованной квоте в Maildir++ файлах maildirsize.
           Это наиболее часто используемый метод для виртуальных пользователей.

quota root name произвольная строка, которая отправляется IMAP клиентам. Название не имеет смысла. По умолчанию используется пустая строка, но вы можете изменить это, поскольку некоторые клиенты (Apple Mail), с пустой строкой вообще не отображают квот.
Можно определить несколько корневых квот (областей), например:
plugin {
  quota = maildir:User quota
  quota2 = fs:Disk quota
  #quota3 = ...
}

Quota rules

Правила задают конкретные значения квот
quota_rule = <mailbox name>:<limit configuration>
#quota_rule2 = ...
#quota_rule3 = ..etc..

mailbox name — если используется "*" то задает ограничение по умолчанию, которое может быть переопределено из базы данных пользователей.
Limit configuration -  поддерживаются следующие значения
  storage:  Квота в килобайтах, 0 - неограниченно.
  bytes:    Квота в байтах, 0 - неограниченно.
  messages: Квота на количество сообщений, 0 неограниченно. Вероятно, не очень полезно.
  backend:  backend-специфичная квота
  ignore:   не включать указанный почтовый ящик в общую квоту.

Все значения поддерживают суффиксы b/k/M/G/T/%. Так storage=100M и bytes=100M идентичны. messages=1k соответствуют 1024 сообщениям (не 1000).
Проценты считаются относительно правила по умолчанию.

Пример:
quota_rule = *:storage=1G
quota_rule2 = Trash:storage=+100M
quota_rule3 = SPAM:ignore
# 20% of 1GB = 200MB
quota_rule4 = Test:storage=+20%%

Пример выше означает, что пользователь имеет квоту 1 Гб. В корзине дополнительно можно сохранить 100 Мб писем. Идея -  позволить клиентам удалять письма через корзину при достижении предела квоты. Любые сообщения в папке спам игнорируются. В почтовом каталоге Test дополнительно можно сохранить 200 Мб писем.

Quota and Trash mailbox

Стандартный способ удаления сообщений с IMAP работает так:
  1. Сообщения маркируются флагом \Deleted
  2. Стираются по настоящему сообщения с помощью команды EXPUNGE

Обе эти команды могут быть успешно использованы при 100% заполнении пользовательского ящика. Однако многие клиенты используют "move-to-Trash"(переместить в корзину), которая работает следующим образом:
  1. Сообщения копируются в корзину
  2. Сообщения маркируются флагом \Deleted
  3. Команда EXPUNGE сообщениям в исходном почтовом ящике (каталоге).
  4. (Возможно позже, удаление сообщений из корзины, используя функцию очистить
      корзину)

Если пользователь превысил квоту, первая команда COPY не удастся, и пользователь получит  сообщение, что не может удалять письма, потому что квота превышена. Возможные решения:
Отключить функцию переместить в корзину при удалении на клиенте.
Либо полностью исключить корзину почтового ящика из расчета квот(см ниже). А чтобы у пользователей не скапливались невероятные количества сообщений в корзине, можно использовать ночные задания cron или плагин expire - (истечение срока), чтобы стирать старые сообщения из корзины.

Приступим к реализации. Настроим наиболее часто используемые - maildir пользовательские квоты в 10Мб.

90-quota.conf
plugin { 
  quota = maildir:User quota 
  quota_rule = *:storage=10M
  quota_rule2 = Trash:storage=+100M 
}
# воспользуемся сервисом предупреждений о приближении ограничения.
plugin { 
  quota_warning = storage=95%% quota-warning 95 %u 
  quota_warning2 = storage=80%% quota-warning 80 %u 
} 
# заменим пользователя от которого запускается скрипт..
service quota-warning { 
  executable = script /usr/local/bin/quota-warning.sh 
  user = vmail 
  unix_listener quota-warning { 
    user = vmail 
  } 
} 

на http://wiki2.dovecot.org/ пример скрипта, создадим соответствующий файлик
/usr/local/bin/quota-warning.sh
#!/bin/sh
PERCENT=$1
USER=$2
cat << EOF | /usr/local/libexec/dovecot/dovecot-lda -d $USER -o 
"plugin/quota=maildir:User quota:noenforcing"
From: postmaster@domain.com
Subject: quota warning

Your mailbox is now $PERCENT% full.
EOF

chmod +x /usr/local/bin/quota-warning.sh
chown vmail:vmail /usr/local/bin/quota-warning.sh
chmod 550 /usr/local/bin/quota-warning.sh

Настроили, теперь необходимо задействовать.
Модуля квоты два:
  quota:      сама реализация квот, включая  все движки квот.
  imap_quota: выдает информацию о квотах через IMAP.

Добавим их в нужные конфиги...
15-lda.conf
mail_plugins = $mail_plugins quota

20-imap.conf
mail_plugins = $mail_plugins quota imap_quota 

по необходимости в 20-pop3.conf, 20-lmtp.conf тоже(только quota).
/usr/local/etc/rc.d/dovecot restart

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

Протестируем..
обязательно смотрим на  соседней консоли
tail -f /var/log/maillog


добиваемся заполнения ящика на 80 и 95 % и 100%

если все работает правильно и без ругани в /var/log/maillog, делем более разумные настройки.
90-quota.conf
quota_rule = *:storage=1G

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

введем в таблицу users дополнительное поле quota
mysql -u root -p
use mail;
alter table users add column quota integer(10) UNSIGNED DEFAULT '0';
update users set quota='30';
\q

добавили  UNSIGNED - беззнаковое число, думаю длины в 10 знаков хватит с лихвой, и задали всем квоту в 30Мб

дополнительно необходимо в ../dovecot-sql.conf.ext несколько модифицировать  user_query
user_query = select concat ('/MAIL/', home) as home, concat ('*:storage=',
 quota, 'M' ) as quota_rule from users where email = '%u' 
# Внимание! здесь одна строка.

внимательно с запятыми.
Здесь добавляется запрос значения поля quota из базы данных и формирования строки, которая переопределит строку  quota_rule = *:storage=10M из 90-quota.conf
Приписывание M/G позволяет хранить в базе более читабельные значения квот (как вариант наверное прокатит текстовое поле с значениями 2G, 100M без приписываний).

Проверяем, если все работает как задумывалось, можно немного лоска навести — подредактировать /usr/local/bin/quota-warning.sh, написать поинтересней сообщение, возможно, даже на великом и могучем.

Шаг 9 — Public Namespace (общие почтовые каталоги)

Зачем может понадобиться namespace? Появится возможность создавать общие почтовые каталоги видимые всеми/не всеми сотрудниками и возможность делать общими «расшаривать» свои почтовые каталоги для других пользователей.

Вступление: в описании ниже я буду использовать слово namespace без перевода. Так же замечу, то что мы видим как папки Sent(Отправленные) Drafts(Черновики) в терминах оригинальной документации называется maildir, так же как, нечто общее где они же и хранятся. Постараюсь пользоваться двумя понятиями — почтовый ящик — общее, имеющее почтовый адрес пространство на диске и почтовые каталоги содержащиеся в нем.  Пример: почта приходит в почтовый ящик (Maildir в терминах документации), в котором находятся почтовые каталоги(тоже Maildir в терминах документации).

Имеется 3 типа namespace.

  private: как правило, содержит только собственные почтовые каталоги пользователя.
  shared:  содержит общие почтовые каталоги других пользователей.
  public:  содержит общественные почтовые каталоги.

Воспользуемся утилитой doveconf — позволяющей посмотреть все настройки с которыми работает dovecot в данный момент.
Вычлиним только нас интересующие.
namespace inbox {
disabled = no
hidden = no
ignore_on_failure = no
inbox = yes
list = yes
location =
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox Trash {
auto = subscribe
special_use = \Trash
}
prefix =
separator =
subscriptions = yes
type = private
}


Пока мы работаем только с личным (private), namespace по умолчанию.

Начнем с простого: попробуем добавить public namespace.
Перейдем в каталог в котором будет вестись основная работа
cd /usr/local/etc/dovecot/conf.d/


откроем еще одну консоль, на которой запустим
tail -f /var/log/maillog

Важно видеть всю ругань которая возможно будет появляться при наших манипуляциях.

Для начала раскомментим некоторые параметры в пространстве имен по умолчанию. Дело в том, что если ни одно namespace не определено, то подразумевается что определено private. Но, если сразу добавить public или shared, система будет думать что мы создаем сервер только с этими namespace и забудет о private. Поэтому перед добавлением дополнительного namespace, явно укажем что у нас есть private.
10-mail.conf
namespace inbox { 
type = private 
separator = /
inbox = yes
list = yes 
subscriptions = yes
} 

в руководстве separator рекомендуется выбирать «/», Если это не указывать, будет использоваться сепаратор по умолчанию «.»  Я использовал рекомендуемый.
/usr/local/etc/rc.d/dovecot restart

смотрим консоль с логом и малость протестируем, что все еще работает....

Попробуем настроить public namespace.

10-mail.conf
namespace  test {
  type = public
  separator = / 
  prefix = Company/ 
  hidden = no 
  location = maildir:/MAIL/Company
  inbox = no 
  list = yes 
  subscriptions = yes 
  #ignore_on_failure = 
  #disabled = 
  #alias_for = 
  #mailbox = 
} 

Описание используемых параметров в переводе 10-mail.conf (см. отделбную статью на этом же ресурсе)
тип почтового ящика maildir,  location = maildir:/MAIL/Company
и создадим почтовые каталоги. Почтовые каталоги у меня начинаются с «.», т. к. я не переопределял принятый по умолчанию в dovecot разделитель иерархии для  maildir
mkdir -p /MAIL/Company/.Spam
mkdir /MAIL/Company/.News
chown -R vmail:vmail /MAIL/Company/
chmod -R g+w /MAIL/Company/

По руководству, можно работать с Company как с почтовым каталогом, создав там соответствующую структуру:
mkdir -p /mail/Company/{cur,new,tmp}
chown -R vmail:vmail /mail/Company

но у меня получилось это как то случайно только раз, и повторить этот результат я не смог, может чего-то не понимаю.
/usr/local/etc/rc.d/dovecot restart

Выбираем подписаться в контекстном меню ящика, и отмечаем каталоги на которые хотим подписаться.

Итак, что должно получиться:  почтовый каталог виден всем пользователям, как каталог Company, возможно потребуется подписаться на него. Название пространства test, используется только в пределах конфигурации, оно не обязательно, но понадобится если мы будем переопределять местоположение public namespace через базу пользователей и в 15-mailboxes.conf(см. ниже). Так можно расшарить почтовый каталог «новости кампании» и выкладывать туда разную «полезную» информацию, либо каталог Spam и периодически скармливать его содержимое спам фильтрам, а лучше объединить эти функции :)

Проверим как все работает.
По умолчанию, сообщения в этих почтовых каталогах маркируются как прочитаные/непрочитаные глобально, т. е. если один пользователь изменил \Seen флаг, это увидят все остальные. Полезно изменить это поведение

10-mail.conf
namespace  test { 
  type = public 
  separator = / 
  prefix = Company/ 
  hidden = no 
  location = maildir:/mail/Company:INDEX=~/Maildir/Company
  inbox = no 
  list = children 
  subscriptions = yes 
  #ignore_on_failure = 
  #disabled = 
  #alias_for = 
  #mailbox = 
} 

С такой конфигурацией, каждый пользователь будет иметь свой вариант  прочитаных/непрочитаных сообщений.

Попробуем прикрутить квоту к этому namespace.

приведем правила квот к виду:
90-quota.conf
plugin { 
  quota = maildir:User quota 
  quota_rule = *:storage=10M 
  quota_rule2 = Trash:storage=+10M 
  quota1 = maildir:Shared quota:ns=Company/ 
  quota1_rule = *:storage=10M 
} 

/usr/local/etc/rc.d/dovecot restart

Проверим как все работает.

Квоты работают, но
  к этому каталогу все имеют полный доступ, мы это поправим..
  не удалось заставить работать правила квоты для отдельных каталогов в  Company типа:
quota1 = maildir:Shared quota:ns=Company/ 
quota1_rule = *:storage=10M 
quota1_rule2 = Spam:ignore

правда документация такого счастья и не обещала.

Уделим 5 минут возможности переопределения местоположения нашего namespace через базу данных пользователей.

Помним что наше  public namespace называется test.
закоментим в 10-mail.conf
#location = maildir:/mail/Company 

Добавим выбор Location в user_query
конкретнее: concat ( 'maildir:/mail/', public ) as 'namespace/test/location'

dovecot-sql.conf.ext
user_query = select concat ('/MAIL/', home) as home, concat ('*:storage=', 
quota, 'M' ) as quota_rule, concat ( 'maildir:/MAIL/', public ) as 
'namespace/test/location' from users where email = '%u'
# Внимание! выше одна строка

Здесь декларируется что местоположение namespase test - /MAIL/ + значение поля public
Lобавим поле public в таблицу users
mysql -u root -p
use mail;
alter table users add column public varchar(32) NOT NULL;
update users set public='Company';
update users set public='Company2' where home='test1';
\q

поле добавили, для всех в нем значение Company, а для test1@testdomain.ru значение Company2
создадим соответствующую структуру.
mkdir /mail/Company2/.Test
mkdir /mail/Company2/.Test2
chown -R vmail:vmail /mail/Company2/
chmod -R g+w /mail/Company2/

Готово, рестартуем сервер:
/usr/local/etc/rc.d/dovecot restart

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

Использовать возможность переопределения местоположения  public namespace я не хочу. Откатить можно удалив столбцы в базе данных, и вернув запрос.
mysql -u root -p
use mail;
alter table users drop column public;
\q

dovecot-sql.conf.ext
user_query = select concat ('/MAIL/', home) as home, concat ('*:storage=', 
quota, 'M' ) as quota_rule from users where email = '%u'
# Внимание! выше одна строка

/usr/local/etc/rc.d/dovecot restart

Итак, общий каталог конечно хорошо, но было бы неплохо иметь возможность рулить доступом к таким каталогам, а то замусорят ведь, или наоборот удалят чего "важного".

Шаг 10 — Access Control Lists

Немного теории с dovecot.org:
Dovecot v1.0 и v1.1 поддерживает файлы ACL — списки контроля доступа настраиваемые администратором. v1.2+ также поддерживает расширение IMAP ACL, которое позволяет пользователям самостоятельно изменять списки ACL.  

Поддержка групп в списках ACL работает через получение списка значений, разделенных запятой из дополнительного поля acl_groups  из userdb, которое содержит все группы, к которым принадлежит пользователь.
По умолчанию ACL для почтовых ящиков, дают права только владельцу. Почтовые каталоги в public namespaces не имеют владельца, поэтому по умолчанию никто не может получить к ним доступ.
Поддерживается локальный ACL почтового ящика и глобальный ACL.
Локальный ACL хранится файле с именем dovecot-acl, который находится в почтовом каталоге Maildir (например, ~/Maildir, ~/Maildir/.folder/)

ACL наследование

Каждый раз, когда вы создаете новый почтовый каталог, он использует ACL родительского почтового каталога. Если вы создаете почтовый ящик, он использует ACL текущего namespace. При создании это работает как наследование но: если вы измените  родительский  ACL, ACL дочерних почтовых ящиков не изменятся, а конечные разрешения просуммируются. В настоящее время наследование ACL не поддерживается.
ACL назначенный по умолчанию для namespace читается из "dovecot-acl" файла находящегося  корневом почтовом каталоге (например,/var/public/Maildir).

Global ACLs

Глобальные ACL могут быть использованы глобально, для всех почтовых ящиков/каталогов пользователей. Они используются в основном для двух целей:
  1. Удаление некоторых разрешений личных почтовых ящиков/каталогов пользователей.
  2. Предоставление разрешения на вход мастер (master) пользователя.
     Мастер пользователь не владелец почтового ящика, поэтому по
     умолчанию он не имеет разрешений к любому из почтовых ящиков.

Глобальный ACL задается в качестве параметра для ACL backend-а.
acl = vfile:/etc/dovecot/acls

Если почтовый каталог имеет как глобальный, так и свой локальный ACL , оба файла читаются и списки управления доступом объединяются. Если есть какие-либо конфликты, глобальный ACL перекрывает локальный ACL. Это сделано чтобы глобальные ACL, которые могут быть изменены только администратором, могли переопределить локальные ACL, настраиваемые пользователями через расширение IMAP ACL.

ACL файлы имеют формат:
<identifier> <ACLs> [:<named ACLs>]
Где <identifier> может быть:
  group-override=название группы
  user=имя пользователя
  owner(владелец)
  group=название группы
  authenticated(аутентифицированные)
  anyone (или anonymous, псевдоним  anyone )
 
ACLS обрабатываются с учетом приоритетов, так, например, если вы дали доступ на чтение группе, вы можете удалить его для определенных пользователей из этой группы (приоритет конкретно указанного пользователя выше, чем группы).
Идентификатор group-override позволяет переопределить приоритет пользовательских записей в ACL. Наверное, самая актуальная сфера применения  - временно лишать доступа некоторых пользователей. Например:
  user=timo rw
  group-override=tempdisabled

Если timo находится в группе tempdisabled, он не будет иметь доступа к почтовому каталогу. Это не было бы возможно с нормальным идентификатором группы, потому что user=timo переопределил бы его.
В настоящее время в списках ACL поддерживаются следующие ..ммм.. литеры.
  l  lookup      - Почтовый каталог виден в списке почтовых ящиков. Можно подписаться
                   на этот почтовый каталог.
  r  read        - Почтовый каталог может быть открыт для чтения.
  w  write         Флаги сообщений и ключевые слова могут быть изменены,
                   за исключением \Seen и \Deleted
  s  write-seen  - \Seen флаг может быть изменен
  t  write-deleted \Deleted флаг может быть изменен
  i  insert      - Сообщения могут быть дописаны или скопированы в каталог ящик
  p  post        - Сообщения могут быть помещены в почтовый каталог  LDA,
                   например, через сценарии  Sieve
  e  expunge     - Сообщения могут быть стерты
  k  create      - Почтовые каталоги могут быть созданы (или переименованы),
                   непосредственно в этом почтовом ящике (но не обязательно его
                   потомки, см. раздел выше наследование списков ACL)
                   (переименование требует также прав удаления)
  x  delete     - Почтовый каталог может быть удален
  a  admin      - Административные права на почтовый каталог (на данный момент:
                   возможность изменения списков ACL для почтового каталог)

Пример файла ACL:
 
owner lrwstipekxa
   user=timo rl

В файле dovecot-acl-list  перечислены все почтовые каталоги, имеющие права "l". Если вы вручную добавите/отредактируете dovecot-acl файлы, вам может понадобиться удалить dovecot-acl-list, чтобы почтовые каталоги стали видимыми.

Теория пройдена, приступим к реализации.

90-plugin.conf

plugin { 
  #setting_name = value 
  acl = vfile 
} 

в 20-imap.conf добавить к существующим расширениям, следующие: acl imap_acl, у меня с учетом предидущих примеров, подобное:
mail_plugins = $mail_plugins quota imap_quota acl imap_acl 

/usr/local/etc/rc.d/dovecot restart

и проверяем, действительно ли мы потеряли доступ к нашему public namespace. Если были подписаны, то выдает ошибку, если подписываться заново, то не видит почтовых каталогов.  
Теперь создадим dovecot-acl файл с разрешением доступа
dovecot-acl
anyone lr 

Изменения вступают в силу сразу, можно убедиться что мы можем подписаться на почтовые каталоги Spam и News.  Только что мы создали глобальный файл для public namespace, эти разрешения будут добавляться ко всем разрешениям на подкаталоги. Хотелось бы иметь видимые не всем подкаталоги, попробуем
mv /mail/Company/dovecot-acl /mail/Company/.News/

cat 'user=test@testdomain.ru lrwstipekxa ' > /mail/Company/.Spam/dovecot-acl

Что мы сделали: переместили dovecot-acl файл из корня namespace в каталог /.News. В каталоге /.Spam создали собственный список dovecot-acl. Проверим как работает, пользователь  test@testdomain.ru будет видеть оба почтовых каталога News и Spam, на последний полный доступ. Остальные пользователи — только  News

А как же группы..

идем в mysql добавлять поле с группами, внимание с длиной поля, возможно всего 128 знаков маловато будет, но мне хватит.
mysql -u root -p
use mail;
alter table users add column acl_groups varchar(128) DEFAULT NULL ;
update users set acl_groups='accessallow,accessdeny' where email='test@testdomain.ru';
update users set acl_groups='accessallow' where email='test1@testdomain.ru';
\q

Внимание, группы должны быть разделены только запятой «accessallow,accessdeny», с пробелами «accessallow, accessdeny» работать не будет. В реальной системе я буду использовать группы вида group@testdomain.ru, а сейчас, для теста, попроще.

поле  acl_groups добавлено,
test@testdomain.ru в группах  accessallow,accessdeny
test1@testdomain.ru в группе  accessallow

в dovecot-sql.conf.ext правим запрос к базе пользователей, добавим в user_query запрос поля acl_groups
user_query = select concat ( '/MAIL/', home ) as home, 
concat ( '*:storage=', quota, 'M' ) as quota_rule, acl_groups 
from users where email = '%u'
# Внимание! все это одна строка

/usr/local/etc/rc.d/dovecot restart

пользователь test1@testdomain.ru не имеет доступа к Spam (по условию предидущего примера), дадим ему доступ:
/mail/Company/.Spam/dovecot-acl
user=test@testdomain.ru lrwstipekxa 
group=accessallow lrws

Проверяем. Результат:  у test1@testdomain.ru появилась возможность подисаться на каталог Spam. Права ограничены. (thunderbird может ошибаться с отображением прав на вкладке «совместное использование» свойств почтового каталога. По хорошему надо отписаться от каталога, перезапустить thunderbird, подписаться на каталог... Но серверная часть принимает изменения прав сразу.)

Отнимем доступ у test1@testdomain.ru на каталог Spam.
/mail/Company/.Spam/dovecot-acl
user=test@testdomain.ru lr
group=accessallow lrwstipekxa 
user=test@testdomain.ru 

Внимание, user=test@testdomain.ru lr ограниченные права, и они не будут расширены членством в группе group=accessallow lrwstipekxa, строка прав у user=test1@testdomain.ru пустая — весомее разрешения на группу. Проверяем.

Отберем все права, группой.
/mail/Company/.Spam/dovecot-acl
user=test@testdomain.ru lr
group=accessallow lrwstipekxa 
user=test@testdomain.ru 
group-override=accessdeny

у group-override=accessdeny пустая строка прав, она переопределяет все права.

Проверяем. Результат — если ранее принудительно указанные права пользователя переопределяли права группы, то group-override меняет это поведение.

ACL и Мастер пользователи

Если осталась настроенной учетная запись  test@testdomain.ru*masteradmin, то можно видеть что она не работает. Выходы из этой ситуации описаны в руководстве, http://wiki2.dovecot.org/Authentication/MasterUsers. Первый вариант с настройкой глобальных ACL показался самым заманчивым, но на практике оказался самым негибким и сложным.

В 90-acl.conf указывается путь к директории в которой должны лежать ACL-файлы по именам почтовых директорий, к которым хотим получить доступ....  Не осилил.

Второй вариант с настройкой postlogin скриптов, тоже быстро поблек перед простотой последнего варианта.

Последний, самый простой способ - поместить master_user=%u в запрос поиска в базе пользователей:

в dovecot-sql.conf.ext раздуем еще чуть-чуть запрос, добавив:'%u' as master_user,
user_query = select concat ( '/mail/', home ) as home, concat 
( '*:storage=', quota, 'M' ) as quota_rule, acl_groups, '%u' 
as master_user from users where email = '%u' 
# Внимание! все это одна строка

/usr/local/etc/rc.d/dovecot restart

В результате master_user для системы ACL становится user-ом

Шаг 11 Shared namespace

Попробуем следующий уровень - добавим shared namespace.
У пользователей появится возможность самостоятельно расшаривать свои почтовые каталоги для других пользователей.

Добавим желанное namespace
10-mail.conf
namespace  test2 { 
  type = shared
  separator = / 
  prefix = Users/%%u/
  hidden = no 
  location = maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u
  inbox = no 
  list =  children
  subscriptions = no
  #ignore_on_failure = 
  #disabled = 
  #alias_for = 
  #mailbox = 
} 

опять немного теории с http://wiki2.dovecot.org/SharedMailboxes/Shared

Параметр location настраиваем с оглядкой на mail_location. Что мы тут можем использовать:
%var расширяется в пользовательские переменные
  %u — имя_пользователя
  %n — имя_пользователя в user@domain, так же как %u если нет домена
  %d — доменная часть в user@domain, пусто если нет домена
  %h — домашняя директория пользователя

%%var расширяется в переменные других пользователей. Например, если ваше имя "myself" и "someone1" и "someone2" имеют общие почтовые ящики, переменные будут расширены как:
  %u расширяется до "myself"
  %%u расширяется до "someone1" или "someone2"
  %h расширяется до "/mail/myself"
  %%h расширяется до "/mail/someone1" или "/mail/someone2"
  ~/ равнозначно %h/

Итак наша строка
mail_location = maildir:%%h/Maildir:INDEX=%h/Maildir/shared/%%u
означает:
%%h/Maildir указывает на Maildir других пользователей, например, "/mail/someone1".
:INDEX=%h/Maildir/shared/%%u указывает на то, где будут храниться лично мой индексный файл расшареного почтового каталога другого пользователя.

С указанной выше конфигурацией можно открыть расшареные почтовые каталоги, если вы знаете их имена, но они не будут видны в списке общих почтовых каталогов. Это потому, что Dovecot не знает, какие пользователи сделали общими свои  почтовые каталоги и для кого. Перебор всех пользователей и, просмотр их почтовых каталогов был бы ужасно неэффективен для более чем пары пользователей.
Для решения этой проблемы Dovecot-у необходим словарь, содержащий список пользователей имеющих общие почтовые каталоги и для кого они доступны. Общие почтовые каталоги пользователей не перечисленные в этом словаре, видны не будут. В настоящее время нет возможности автоматически восстанавливать этот словарь, так что примите меры чтобы его не утратить. Если это произойдет, каждый пользователь, имеющий общие почтовые каталоги должен будет заново их опубликовать.
Вы можете использовать любой backend словарь, в том числе SQL, но простой плоский файл тоже будет неплохо работать (руководство - дословно):
plugin {
  acl_shared_dict = file:/var/lib/dovecot/db/shared-mailboxes.db
}

Процессы IMAP должны иметь доступ на запись в /var/lib/dovecot/db/.
Если вы используете несколько доменов, и не хотите, чтобы пользователи делились своими почтовыми каталогами с пользователями других доменов, вы можете использовать отдельные dict файлы для каждого домена:
plugin {
  acl_shared_dict = file:/var/mail/%d/shared-mailboxes.db
}

Что еще можно
  prefix = Users/%%u/  - расшареные каталоги будут видны как  Users/адрес
                       пользователя кто расшарил.
  hidden = no  - не скрытое namespace
  list =  children  - не отображать namespace если нет ни одного
                       расшареного каталога  (либо конкретно у вас нет разрешений
                       l (lookup) на существующий общий каталог.
  subscriptions = no — нет автоматической подписки.

Создадим словарь, для начала как простой файл:
90-plugin.conf или лучше 90-acl.conf
plugin { 
  acl_shared_dict = file:/usr/local/etc/dovecot/db/shared-mailboxes.db 
} 

mkdir /usr/local/etc/dovecot/db
chown vmail:vmail /usr/local/etc/dovecot/db

/usr/local/etc/rc.d/dovecot restart

Смотрим, визуально изменений никаких, но главное чтобы ругани в /var/log/maillog не было.
Далее:
Dovecot ожидает что общий почтовый каталог будет расшарен с помощью команды IMAP SETACL. Это единственный путь к обновлению словаря списка общих почтовых каталогов.
В руководстве есть описания команд с примерами их использования, посылая которые IMAP серверу в сеансе openssl/telnet, можно ........ Несколько заморочный метод, как мне показалось, особенно в ключе, возможно, самостоятельного использования пользователями.
Выход — смотрим есть ли чего в дополнениях thunderbird. Оказывается есть: imap-ACL-Extension версии 0.2.2 на момент написания этой статейки. Ставим. Вуаля, на вкладке «совместное использование» свойств почтового каталога появилась чудесная кнопочка Set Permissions.
Создадим почтовый каталог у пользователя test@testdomain.ru с именем TestShare. В свойствах выберем вкладку «совместное использование» и дадим разрешения read messages пользователю  test1@testdomain.ru
как проверять думаю понятно...
namespace Users видно только у test1@testdomain.ru, так как только для него есть расшареный каталог. Интересно что у test@testdomain.ru, того кто папку расшарил, namespace Users не отображается. Для него расшареных каталогов нет.

Если очень хочется, можно расшарить свою папку всем. По умолчанию Dovecot не позволяет использовать установку IMAP разрешений для "anyone" или "authenticated". Но если Вам очень нужно:
90-plugin.conf
plugin { 
  acl_shared_dict = file:/usr/local/etc/dovecot/db/shared-mailboxes.db 
  acl_anyone = allow 
} 

После этой манипуляции можно использовать anyone и authenticated идентификаторы и у всех пользователей появится возможность воспользоваться Вашим опубликованным каталогом. За исключением, тех, кому можно установить негативные права!! Например добавим -test1@testdomain.ru  read message. Добавляется с минусом, и этот пользователь теряет доступ, в отличии от всех остальных.
Небольшое отступление: anyone включает anonymous, authenticated без него. Это встроенные группы. Группы из поля acl_groups, тоже работают! Их можно добавлять как $group или $!group для возможности group-override.

Использование  SQL словаря.

Внимание, эта возможность у меня адекватно не заработала. Вернее она работала, но не в полном объеме — пользователи - пользователям расшаривали, а acl группе нет. Отказался в пользу плоского файла. Не уверен что нужно тогда это здесь печатать, но пусть будет, вдруг кому интересно где я накосячил. Кому неинтересно — идем на шаг 12

Создадим файлик mkacldict.mysql и не мудрствуя лукаво скопируем туда пример создания таблиц с http://wiki2.dovecot.org:
CREATE TABLE user_shares ( 
  from_user varchar(100) not null, 
  to_user varchar(100) not null, 
  dummy char(1) DEFAULT '1', 
  primary key (from_user, to_user) 
); 

CREATE INDEX to_user ON user_shares (to_user); 

CREATE TABLE anyone_shares (
  from_user varchar(100) not null,
  dummy char(1) DEFAULT '1',    -- always '1' currently
  primary key (from_user)
);
# это уже отсебятина, даем все права пользователю mailreder на эти таблицы
grant ALL PRIVILEGES on mail.user_shares to 'mailreader'@'localhost'; 
grant ALL PRIVILEGES on mail.user_shares to 'mailreader'@'127.0.0.1'; 
grant ALL PRIVILEGES on mail.user_shares to 'mailreader'@'::1'; 

grant ALL PRIVILEGES on mail. anyone_shares to 'mailreader'@'localhost'; 
grant ALL PRIVILEGES on mail. anyone_shares to 'mailreader'@'127.0.0.1'; 
grant ALL PRIVILEGES on mail. anyone_shares to 'mailreader'@'::1'; 
# применить изменения прав :)
flush privileges;

Зальем в mysql, в базу mail
mysql mail < mkacldict.mysql -u root -p

Подключим наш словарь

../dovecot.conf
dict { 
    user_shares = mysql:/usr/local/etc/dovecot/dovecot-dict-sql.conf.ext 
} 

../dovecot-dict-sql.conf.ext
connect = host=/tmp/mysql.sock dbname=mail user=mailreader password=password 
map { 
  pattern = shared/shared-boxes/user/$to/$from 
  table = user_shares 
  value_field = dummy 
 fields { 
    from_user = $from 
    to_user = $to 
  } 
}
map {
  pattern = shared/shared-boxes/anyone/$from
  table = anyone_shares
  value_field = dummy

  fields {
    from_user = $from
  }
}

90-plugin.conf  меняем acl_shared_dict
plugin { 
  acl_shared_dict = proxy::user_shares 
  acl_anyone = allow 
} 

мы указали что будем использовать сервис proxy посредством которого будем обращаться к таблицам. Дополнительно необходимо поправить права для сокета unix_listener dict в 10-master.conf
service dict { 
  unix_listener dict { 
    mode = 0600 
    user = vmail 
    group = vmail 
  } 
} 

/usr/local/etc/rc.d/dovecot restart

Идем публиковать каталог TestShare пользователя test@testdomain.ru для test1@testdomain.ru. Проверим как работает. Дополнительно можно посмотреть что за записи в таблице user_shares:
mysql -u root -p
use mail;
select * from user_shares;
+--------------------+---------------------+-------+
|______from_user_____|______to_user________|_dummy_|
+--------------------+---------------------+-------+
| test@testdomain.ru | test1@testdomain.ru | __1__ |
+--------------------+---------------------+-------+
\q

Перепубликуем наш каталог для  anyone. Смотрим какие записи появились в таблице  anyone_shares

mysql -u root -p
use mail;
select * from anyone_shares;
+--------------------+-------+
|____from_user_______| dummy |
+--------------------+-------+
| test@testdomain.ru | __1__ |
+--------------------+-------+
\q

Шаг 12 Sieve

Зачем это нужно? - появляется возможность обработки почтовых сообщений на сервере по заданным правилам (настраивали правила сортировки в почтовой программе?, а потом приходили, к примеру домой и тоже самое настраивали?)

cd /usr/ports/mail/dovecot2-pigeonhole/
make install

поставили, то что поставили состоит из 2х частей: плагин для dovecot который обрабатывает почту и сервер, позволяющий пользователям самим править свои правила sieve.
Приступим.

Включим плагин в конфигурации dovecot, обработки запускаются при локальной доставке.

cd /usr/local/etc/dovecot/conf.d/

скопируем новый конфиг файл

cp /usr/local/share/doc/dovecot/example-config/conf.d/90-sieve.conf /usr/local/etc/dovecot/conf.d/

включим плагин sieve в дополнение к, у меня уже работающему, плагину quota

15-lda.conf
mail_plugins = $mail_plugins quota sieve 

Если почта у Вас приходит в dovecot по LMTP (см ниже настройку DSPAM)то в 20-lmtp.conf тоже.
90-sieve.conf
sieve = ~/.dovecot.sieve 
   sieve_dir = ~/sieve 
} 

sieve = ~/.dovecot.sieve - путь к пользовательскому основному активному Sieve сценарию. Когда используется ManageSieve, это символическая ссылка на активный сценарий в каталоге sieve_dir. Избегайте активных Sieve сценариев в sieve_dir каталоге. В данном примере сценарий будет располагаться в домашнем каталоге пользователя. Согласно руководству, в пути можно использовать переменные %u, %d, .. и даже переопределить эту настройку через пользовательскую базу данных(добавляем поле, правим запрос). Позже это опробую.

sieve_dir = ~/
личные сценарии пользователя с расширением .sieve. При использовании ManageSieve, это так же каталог, в который загружаются сценарии.

/usr/local/etc/rc.d/dovecot restart

Смотрим нет ли ругани...

Внедрили, теперь можно написать скрипты и посмотреть как работает, но писать лень, и для простых пользователей необходимо более простое решение, чем написание скриптов .sieve в сеансе SSH или заливание их к себе в домашний каталог по FTP.
Настроим ManageSieve Server, скопируем, для начала, чудесно появившийся новый конфиг файл

cp /usr/local/share/doc/dovecot/example-config/conf.d/20-managesieve.conf /usr/local/etc/dovecot/conf.d/

20-managesieve.conf
protocols = $protocols sieve 

service managesieve-login { 
  inet_listener sieve { 
    port = 4190 
  } 
} 

/usr/local/etc/rc.d/dovecot restart

netstat -na | grep LISTEN

tcp4 0 0 *.4190 *.* LISTEN

видим что у нас поднялся еще один сервис, теоретически он должен позволять рулить .sieve скриптами, но как им воспользоваться? Смотрим что есть у thunderbird-а в дополнениях. Нам повезло, доступно дополнение sieve, которое не заработало (Исправлено: скорее всего оно рабочее, но будьте внимательны, есть подозрение, что не все дополнения работают если у Вас несколько методов аутентификации, либо берется простейший (PLAIN) из возможных. На момент тестирования у меня была аутентификация "зашифрованный пароль"), попробуем другое  sieve out of office (2.0.0).  Sieve out of office заработало из коробки, но по функциональности полностью соответствует своему названию, включить перенаправление писем, куда нить, не более.  Для тестирования все же воспользуемся предложенной функциональностью. У пользователя test@testdomain.ru создадим правило отправляющее копию пришедшего сообщения на test1@testdomain.ru. В thunderbird идем в инструменты ….  Проверяем. Сразу может не заработать, нужно чуть поплясать с бубном, включить/выключить правило..и т. п.  
Результаты получены, sieve работает. Рекомендую сразу забыть об этих дополнениях, и настаивать правила через web-интерфейс roundcube, благо там поддержка dovecot sieve заявлена как fine. Строкой выше я имел ввиду что желательно настраивать все правила через одну "систему" или roundcube или расширения.

Попробуем прикрутить глобальный сценарий, работающий для всех пользователей.
90-plugin.conf
sieve_before = /usr/local/etc/dovecot/sieve/spam.sieve 

mkdir /usr/local/etc/dovecot/sieve

/usr/local/etc/dovecot/sieve/spam.sieve
require ["fileinto"]; 
# rule:[move_spam] 
if anyof (header :contains "Subject" "***SPAM***") 
{ 
        fileinto "Spam"; 
} 

chown -R vmail:vmail /usr/local/etc/dovecot/sieve
chmod 660 /usr/local/etc/dovecot/sieve
chmod 770 /usr/local/etc/dovecot/sieve/spam.sieve

Это мы создали каталог, с правом записи для vmail:vmail. Ситуация такова, что сценарии .sieve сначала интерпретируются - получается файлик .svbin, а потом с ним работаем. Этим занимается dovecot, каждый раз при обработке письма по этому скрипту. Можно ему помочь - интерпретировать скрипт заранее, и положить рядом, тем самым интерпретация каждый раз происходить не будет (man sievec). Менять конфиг, и указывать перелопаченый скрипт не нужно.
sievec /usr/local/etc/dovecot/sieve/spam.sieve
chmod 770 /usr/local/etc/dovecot/sieve/spam.svbin

помним, что у нас, у каждого пользователя имеется почтовый каталог Spam. Мы настроили его принудительное создание в 15-mailboxes.conf
/usr/local/etc/rc.d/dovecot restart

Проверяем как работает. Нужно отправить письмо пользователю с темой ***SPAM***.
У меня уже есть работающая система с web-интерфейсом roundcube,  в котором очень просто создавать правила. Текст этого sieve сценария создан roundcube расширением sieve. Я стащил его, предварительно создав себе правило сортировки спама через web интерфейс.

Аналогично можно указать путь к сценарию выполняющемуся после пользовательских сценариев, параметр sieve_after =  Если в этих параметрах будут пути к каталогам, то будут выполняться все сценарии из них.

Все красиво работает, если бы не одно но. Письмо с темой ***SPAM*** перемещается в каталог Spam и не дойдет до пользовательских фильтров(это справедливо не для всех возможных действий, а только для тех, которые «заканчивают обработку», к примеру переместить, удалить) Предположим пользователь создает правило пересылать всю почту на свой google аккаунт. А тут приходит ошибочно помеченное как ***SPAM*** сообщение....

Как вариант вместо sieve_before, можно использовать sieve_after, либо sieve_default

Что еще касаемо sieve можно прописать в 90-plugin.conf (тупо перевод мануала)

sieve_default = (v0.3+)
Расположение файла сценария Sieve, который запускается на выполнение ТОЛЬКО если частный сценарий пользователя  не существует.
sieve_global_dir =
Глобальные скрипты. Можно зоздать некоторое количество готовых  сценариев, которые будут доступны для использования пользователям.
sieve_extensions =
Какие расширения Sieve языка доступны для пользователей. По умолчанию все поддерживаемые расширения доступны, за исключением устаревших, расширений, которые требуют явного конфигурирования или те, которые находятся в стадии разработки. Некоторые системные администраторы могут отключить определенные расширения Sieve или включить те, которые не доступны по умолчанию. Все поддерживаемые расширения, перечисленные здесь http://wiki2.dovecot.org/Pigeonhole/Sieve#features. Как правило, все включенные расширения должны быть здесь перечислены, но начиная с Sieve версии 0.1.7, можно использовать '+' и '-', чтобы определить различия по отношению к умолчанию. Например sieve_extensions = +imapflags[b] разрешит использовать устаревшее расширение imapflags в дополнение ко всем включенным по умолчанию.
sieve_global_extensions = (v0.3+)
Какие расширения [b]Sieve
языка доступны ТОЛЬКО в глобальном сценарии. Это может быть использовано для ограничения использования некоторых Sieve расширений, например, когда эти расширения могут вызвать проблемы безопасности. Этот параметр имеет более высокий приоритет, чем sieve_extensions (см. выше), что означает, что эти расширения  не доступны для личных сценариев пользователей. Синтаксис этого параметра похож на sieve_extensions. По умолчанию пусто.
sieve_plugins =
Pigeonhole Sieve интерпретатор может иметь свои собственные плагины.
sieve_user_log =
Путь к файлу, в котором ведется пользовательский журнал.
recipient_delimiter = +
Разделитель, использующийся, между: пользователь и расширением.
sieve_max_script_size = 1M
Максимальный размер Sieve сценария. Компилятор откажется компилировать любой сценарий больше, чем этот предел. Если установлено в 0, ограничений на размер сценария не соблюдается.
sieve_max_actions = 32
Максимальное количество действий, которые могут быть выполнены за одно выполнение сценария. Если установлено в 0, никаких ограничений.
sieve_max_redirects = 4
Максимальное количество действий перенаправления, которые могут быть выполнены за одно выполнение сценария. Значение 0 различается в зависимости от версии. Для версии v0.3.0 и выше это означает, что перенаправление запрещено. Для более старых версий, это означает, что число перенаправлений не ограничено, так что будьте осторожны.

Extension-specific Configuration

Некоторые расширения языка Sieve могут/нуждаются в дополнительном конфигурировании. Рассмотрим на примере vacation-seconds.
Расширение Sieve vacation(отпуск) определяет механизм для создания автоматических ответов на входящие сообщения электронной почты. В оригинальном расширении vacation, интервал, как часто отправлять ответы на определенный контакт, указывается в днях с минимум в один день. Если необходимо отправлять ответы чаще чем один день,  можно использовать vacation-seconds. Это позволяет задать минимальный интервал в секундах, с минимумом равным нулю (всегда посылать ответ), в зависимости от административной настройки.
Расширение vacation доступно по умолчанию. В отличие от него, расширение vacation-seconds  не доступно по умолчанию и должно быть включено явно, добавлением в настройке sieve_extensions.

Приступим к настройке.

90-sieve.conf
sieve_extensions = +vacation-seconds
   sieve_vacation_min_period = 1h 
   sieve_vacation_default_period = 1d

Проверить, нужно подождать roundcube.

Следующие параметры могут быть настроены для расширение vacation  (значения по умолчанию указаны):
sieve_vacation_min_period = 1d
Это определяет минимальный период, Минимум 0 означает, что пользователи могут указать интерпретатору Sieve отправлять сообщения в ответ на каждое входящее сообщение удовлетворяющее остальным критериям. Нулевое значение, не рекомендуется.
sieve_vacation_max_period = 0
Максимальный срок. Заданное значение должно быть больше, чем sieve_vacation_min_period. Значение 0 имеет особое значение: это означает, что не существует верхнего предела.
sieve_vacation_default_period = 7d
Это указывает период по умолчанию. Заданное значение должно лежать между sieve_vacation_min_period и sieve_vacation_max_period.

При неверных значениях параметров сделает Sieve интерпретатор напишет предупреждение в лог и вернется к значениям по умолчанию.

Шаг 13 - EXPIRE

Зачем это нужно? Просто посмотреть как настраивается и работает, и возможно, получить себе немного времени упустив возможность общения с некоторыми пользователями не понимающими почему у них кончилась квота на почтовом ящике, хотя они все поместили в «Удаленные»

Немного теории с http://wiki2.dovecot.org/Plugins/Expire

Как правило, этот плагин используется для оптимизации удаления старых почтовых сообщений  из почтовых ящиков пользователей. Рассмотрим команду

doveadm expunge -A mailbox Trash savedbefore 30d

Эта команда прекрасно работает и без плагина expire. Она просто проходит по всем пользователям, а не по тем, у которых действительно есть что удалить.

Плагин будет работать для всех doveadm почтовых команд, а не только expunge. Таким образом, можно использовать doveadm search -A ...,  чтобы посмотреть, какие сообщения подходят под фильтр.

Оптимизация выполняется только тогда, когда используется параметр -A, чтобы пройти по всем пользователям. Если вы используете параметр -u для отдельных пользователей, от плагина expire толку не будет.

Оптимизация выполняется только тогда, когда в поисковом запросе используется "savedbefore".

Оптимизация выполняется только тогда, когда данные почтовые ящики или ящик, соответствует списку определенному в настройках плагина expire.

Таким образом, задача плагина expire в том, чтобы снизить количество дисковых I/O, когда определяется какие пользователи имеют сообщения подлежащие очистке. Если у вас не тысячи пользователей, вы, вероятно, не должны возиться с этим плагином.
Когда плагин expire включен, он следит за "oldest mail's saved timestamp" для указанных почтовых каталогов. Когда doveadm команда использует поиск с ключем "savedbefore", метки в базе данных могут быть использованы, для выяснения, какие пользователи имеют соответствующие письма.

Плагин expire отслеживает/оптимизирует только поисковые запросы c "savedbefore", т.е. на дату, когда сообщение было сохранено или cкопировано в почтовый каталог (не дата получения сообщения), и плагин expire был загружен. Если почтовый ящик, уже содержал сообщения, до загрузки плагина в первый раз, они будут очищены, когда придет время очистки сообщения сохраненного/скопированного после включения плагина expire.

Попробуем:

10-mail.conf
mail_plugins = $mail_plugins expire 

Далее нужно настроить список отслеживаемых почтовых каталогов. Шаблоны почтовых каталогов могут содержать IMAP-совместимые символы:

  "*" работает стандартно: совпадает с любым количеством символов.
  "%" работает для любого количества символов, но останавливается на
      разделителе иерархии. В настоящее время разделитель жестко установлен
      в "/", так что это будет не правильно работать, если вы настроили
      что-то другое (например, "." по умолчанию для Maildir).

90-plugin.conf
plugin { 
  #setting_name = value 
  expire_dict = proxy::expire 
  expire = Trash 
  expire1 = Spam 
} 

Сконфигурируем словарь в /usr/local/etc/dovecot/dovecot.conf

dict { 
  expire = mysql:/usr/local/etc/dovecot/dovecot-dict-sql.conf.ext 
} 

укажем куда подключаться в /usr/local/etc/dovecot/dovecot-dict-sql.conf.ext, добавив строку
connect = host=/tmp/mysql.sock dbname=mail user=mailreader password=password 

Пример необходимой таблицы в mysql, не мудрствуя лукаво, возьмем из dovecot-dict-sql.conf.ext.
Создадим файлик dictexp.mysql
# use this:  mysql < mk_mail_db 
use mail; 
CREATE TABLE expires ( 
   username varchar(100) not null, 
   mailbox varchar(255) not null, 
   expire_stamp integer not null, 
   primary key (username, mailbox) 
 ); 
grant ALL PRIVILEGES on mail.expires to 'mailreader'@'localhost'; 
grant ALL PRIVILEGES on mail.expires to 'mailreader'@'127.0.0.1'; 
grant ALL PRIVILEGES on mail.expires to 'mailreader'@'::1'; 
flush privileges; 

я добавил только расширение прав на таблицу expire. Зальем все это добро в mysql
mysql -u root -p < dictexp.mysql

проверим доступ к сервису dict в 10-master.conf
service dict { 
  unix_listener dict { 
    mode = 0600 
    user = vmail 
    group = vmail 
  } 
} 

Некоторым командам, таким как doveadm нужно получать список пользователей. С SQL UserDB это делается настройкой iterate_query. Надо получить "user" содержащее user или user@domain имена пользователей, или поля "username" и "domain"

В /usr/local/etc/dovecot/dovecot-sql.conf.ext добавим строку
iterate_query = SELECT email AS user FROM users 

/usr/local/etc/rc.d/dovecot restart

Теперь, если нет ругани в maillog, надо проверять работу. Переместим сообщение в каталог Trash, можно посмотреть что в таблице появились записи:

mysql -u root -p mail
select * from expires;
+--------------------+---------+--------------+
|______username______| mailbox | expire_stamp |
+--------------------+---------+--------------+
| test@testdomain.ru | _Trash_ | _1363690509_ |
+--------------------+---------+--------------+
\q

Уже хорошо. Как чистить? Запускать doveadm  по CRON.

crontab -e

10 23 * * * /usr/local/bin/doveadm expunge -A mailbox Trash savedbefore 3d
20 23 * * * /usr/local/bin/doveadm expunge -A mailbox Spam savedbefore 5d

Шаг 14 - Trash Plugin

Обычно, если сообщение не может быть сохранено/скопировано, потому что пользователь превысил квоту, операция завершается с ошибкой "Квота превышена". Trash плагин поможет еще немного продержаться, давая Dovecot право автоматически стирать старые сообщения из определенных почтовых каталогов, пока новое сообщение не будет сохранено. Если новое сообщение настолько большое, что не поместится, даже если стереть все сообщения из настроенных почтовых каталогов, то удаления не происходит, и пользователь получает ошибку "Квота превышена". Этот плагин может сэкономить время, избежав общения с пользователями, просто перемещающими ненужные сообщения в корзину, без ее очистки. Иногда просто забывают.

Этот плагин требует загруженного и настроенного плагина quota, использующего не файловую квоту.

Приступим к реализации:

Где включается? По идее там где и квота, 15-lda.conf, 20-imap.conf, 20-lmtp.conf либо глобально 10-mail.conf

15-lda.conf
mail_plugins = $mail_plugins …...... trash …..

укажем местоположение файла конфигурации

90-plugin.conf
plugin {
  trash = /usr/local/etc/dovecot/dovecot-trash.conf.ext 
}

Файл конфигурации представляет собой текстовый файл, где каждая строка имеет формат:
<priority> <mailbox name>
Письма будут удаляться по приоритету, начиная с низшего -> до высшего номера.

/usr/local/etc/dovecot/dovecot-trash.conf.ext
# Spam mailbox is emptied before Trash
1 Spam
# Trash mailbox is emptied before Sent
2 Trash
# If both Sent and "Sent Messages" mailboxes exist, the next oldest message
# to be deleted is looked up from both of the mailboxes.
3 Sent
3 Sent Messages

/usr/local/etc/rc.d/dovecot restart

Проверяем, ….. не забываем при тестировании работы, настраивали ли мы дополнительные, внеквотные 100Mб для каталога Trash.


Шаг 14 — DSPAM

При чем здесь DSPAM? Дело в том что для dovecot есть инструмент dovecot2-antispam-plugin, позволяющий выполнять некие действия (переобучать фильтр) по факту перемещения сообщения из/в папку Spam. Заманчиво просто. В качестве переобучаемого фильтра я выбрал DSPAM, но есть и другие варианты.
Сначала сам DSPAM.
Сылка хороший на мануал по установке, в который подсматривал: http://wolandblog.com/page/15/?s=http
чтобы dspam работал не от root

/etc/make.conf
DSPAM_OWNER=dspam
DSPAM_GROUP=dspam
DSPAM_HOME_OWNER=dspam
DSPAM_HOME_GROUP=dspam

pw groupadd dspam
pw useradd dspam -g dspam -s "/sbin/nologin" -c «DSPAM»
cd /usr/ports/mail/dspam-devel/
make install && make clean

опции с которыми собирал я

OPTIONS_FILE_SET+=SYSLOG
OPTIONS_FILE_SET+=DAEMON
OPTIONS_FILE_SET+=MYSQL55
OPTIONS_FILE_SET+=VIRT_USERS
OPTIONS_FILE_SET+=WebUI

к сожалению больше ничего полезного по этим опциям сказать не могу
echo 'dspam_enable="YES"'>> /etc/rc.conf

создадим базу данных в mysql для dspam
mkdspamdb.mysql
# use this:  mysql < mkdspamdb.mysql
# drop database dspam; 
create database dspam
DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; 

grant ALL PRIVILEGES on dspam.* to 'dspam'@'localhost'; 
grant ALL PRIVILEGES on dspam.* to 'dspam'@'127.0.0.1'; 
grant ALL PRIVILEGES on dspam.* to 'dspam'@'::1'; 

use mysql; 
update user set password=password('password') where user='dspam'; 
flush privileges; 

Заливаем все это добро в mysql, не забываем сменить пароль
mysql < mkdspamdb.mysql -u root -p

перед залитием нижеследующего изменить в этих файлах все вхождения type на engine
mysql dspam -u root -p < /usr/local/share/examples/dspam/mysql/mysql_objects-4.1.sql
mysql dspam -u root -p < /usr/local/share/examples/dspam/mysql/virtual_users.sql

Впихнем DSPAM на пути следования писем от postfix к dovecot.
источник
http://wiki2.dovecot.org/HowTo/Virtual%2BPostfix%2BDspam%2BDovecot

--smtp--> [ MTA ] --lmtp:--> [DSPAM] —lmtp--> [DOVECOT] ---> (virtual Mailbox)

мой конфиг почти по этому мануалу, только письма передаю в dspam по сокету

--smtp--> [ MTA ] --socket:--> [DSPAM] —lmtp--> [DOVECOT] ---> (virtual Mailbox)

/usr/local/etc/dspam.conf

Home /var/db/dspam 
StorageDriver /usr/local/lib/dspam/libmysql_drv.so 

# куда DSPAM передает письма после обработки
DeliveryHost            127.0.0.1 
DeliveryPort            24 
DeliveryIdent           dspam_on_mail.testdomain.local 
DeliveryProto           LMTP

OnFail error   # для начала error, потом, как заработает, поменять

Trust root 
Trust dspam 
Trust vmail
Trust dovecot
# не уверен что это нужно, это пользователи кто может обучать..

Debug * 
DebugOpt process classify 

TrainingMode teft  
TestConditionalTraining on  
Feature whitelist

Feature tb=5
Algorithm graham burton 
Tokenizer osb
PValue bcr 

WebStats on 

Preference "spamAction=deliver" 
Preference "signatureLocation=headers"
Preference "showFactors=off"

# параметры подключения к SQL
MySQLServer             /tmp/mysql.sock 
MySQLUser               dspam 
MySQLPass               password 
MySQLDb                 dspam 

ServerIdent             "dspam.testdomain.local" 
# важный параметр, без него передавать дальше никуда ничего не будет
ServerParameters "--deliver=innocent, spam"
ServerDomainSocketPath  "/var/run/dspam/dspam.sock" 

mkdir /var/run/dspam
chown dspam:dspam /var/run/dspam

Postfix

master.cf
virtual_transport = lmtp:unix:/var/run/dspam/dspam.sock 

dovecot

/usr/local/etc/dovecot/dovecot.conf
protocols = imap lmtp 

/usr/local/etc/dovecot/conf.d/20-lmtp.conf
mail_plugins = $mail_plugins quota sieve trash

/usr/local/etc/dovecot/conf.d/10-master.conf
inet_listener lmtp { 
       address = 127.0.0.1 
    port =  24 
 } 

База токенов будет одна на всех,
/var/db/dspam/group
globalgroup:shared:* 

chown dspam:dspam /var/db/dspam/group

/usr/local/etc/rc.d/dovecot restart
/usr/local/etc/rc.d/dspam-devel restart
/usr/local/etc/rc.d/postfix restart

Надо проверить как работает....
пару писем туда -обратно, посмотреть логи, и заголовки писем, присутствует ли X-DSPAM-Signature.

Итак DSPAM завели. То что описано выше конечно скудно, но нам нужно просто рабочая версия. Хороший мануал для более детальной настройки dspam здесь: http://wiki.linuxwall.info/doku.php/en:ressources:dossiers:dspam#dokuwiki__top

Еще пару штрихов

Чтобы логи не росли, dspam_logrotate
он не совсем их ротирует, а похоже режет, в крон нечто подобное

/usr/local/bin/dspam_logrotate -a 30 -l /var/log/dspam/dspam.debug
/usr/local/bin/dspam_logrotate -a 30 -l /var/log/dspam/dspam.messages
/usr/local/bin/dspam_logrotate -a 30 -l /var/log/dspam/sql.errors

/usr/local/bin/mysql mail —user=dspam —password=DspamSecurePa$$ < /usr/local/share/examples/dspam/mysql/purge-4.1.sql



Настройка перемещения входящих сообщений с заголовком X-DSPAM-Result SPAM в папку SPAM

предполагается что sieve установлен.
Переделаем наш первоначальный файлик таким образом (не помню уже откуда спер):
/usr/local/etc/dovecot/spam/spam.sieve
require ["regex", "fileinto", "imap4flags"];
# Catch mail tagged as Spam, except Spam retrained and delivered to the mailbox
if allof (header :regex "X-DSPAM-Result" "^(Spam|Virus|Bl[ao]cklisted)$",
          not header :contains "X-DSPAM-Reclassified" "Innocent") {
  # Mark as read
  setflag "\\Seen";
  # Move into the Junk folder
  fileinto "Spam";
  # Stop processing here
  stop;
}

чтобы он работал, пропишем в конфиге sieve, я выбрал default, как вариант before или after. Не забудьте вычистить из sieve before что мы делали раньше для теста.
90-sieve.conf
sieve_default = /usr/local/etc/dovecot/spam/spam.sieve 

sievec /usr/local/etc/dovecot/spam/spam.sieve
chown vmail:vmail /usr/local/etc/dovecot/spam/*

dovecot2-antispam

Теперь то ради чего все это затевалось dovecot2-antispam-plugin

Что нам даст — переобучение dspam автоматически по факту перемещения  пользователем писем из/в папки Spam

cd /usr/ports/mail/dovecot2-antispam-plugin/
make install && make clean

Можно настроить 4 вида папок, SPAM TRASH UNSURE OTHER. Перемещение писем между папками вызывает определенные действия (man dspam):
         
       | dst\src | SPAM |  TRASH | UNSURE | OTHER |
       |   SPAM  |  /   |   /    |   -    |   -   |
       |  TRASH  |  /   |   /    |   *    |   /   |
       | UNSURE  |  *   |   *    |   *    |   *   |
       |  OTHER  |  +   |   /    |   +    |   /   |

      Legend:
         /      игнорируется
         *      запрещено
         -      переобучаем как spam
         +      переобучаем как ham

Я решил как нить обойтись без папки  UNSURE. И без нее надо втолковать пользователям как с этим работать.

Маленькое отступление, по особенности работы. (тупо перевод)
ALLOWING APPENDS
   # Рассмотрим случай, когда при перемещении сообщения исходная папка
   # неизвестна, например при перемещении с другой учетной записи,
   # или при offlineimap. Вы должны быть осторожны с разрешением
   # добавлять в папку SPAM. Причина возможного включения этого —
   # чтобы not-SPAM --> SPAM перемещения работали и переобучали фильтр.
   # Однако, так как плагин не может знать источник сообщения
   # (предполагается, что из другой папки), возможны нехорошие последствия:

   # 1. SPAM --> SPAM перемещения могут быть признаны тренировкой как SPAM;
   # 2. TRASH --> SPAM перемещения могут быть признаны тренировкой как SPAM;
   # 3. SPAM --> not-SPAM перемещения могут быть не признаны, поэтому переобучения
   #                                                 не произойдет.

Да, не все идеально конечно..
Создадим дополнительный конфиг, пришлось порыть инет...
источники
http://johannes.sipsolutions.net/files/antispam.html
http://aliech.ru/?tag=%D0%B2%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5
перевод в следующей статье
/usr/local/etc/dovecot/conf.d/90-antispam.conf
plugin {
    ##################
    # GENERIC OPTIONS

    # Debugging options
    # Uncomment to get the desired debugging behaviour.
    # Note that in some cases stderr debugging will not be as
    # verbose as syslog debugging due to internal limitations.
    #
    antispam_debug_target = syslog
    # antispam_debug_target = stderr
    # antispam_verbose_debug = 1

    # backend selection, MUST be configured first,
    # there's no default so you need to set one of
    # these options:
    # antispam_backend = crm114
    # antispam_backend = dspam
    antispam_backend = pipe
    # antispam_backend = spool2dir

    # mail signature (used with any backend requiring a signature)
    # antispam_signature = X-DSPAM-Signature

    # action to take on mails without signature
    # (used with any backend requiring a signature)
    # (we recommend only setting this to 'move' after verifying that the
    # whole setup is working)
    # antispam_signature_missing = move 
    # move silently without training
    antispam_signature_missing = error

    # The list of folders for trash, spam and unsure can be given
    # with three options, e.g. "trash" matches the given folders
    # exactly as written, "trash_pattern" accept the * wildcard at
    # the end of the foldername, "trash_pattern_ignorecase"
    # accepts the * wildcard at the end of the foldername _and_
    # matches the name case insensitivly.

    # the *-wildcard with the following meaning:
    #    * at the end: any folder that _start_ with the string
    # e.g.:
    #   antispam_trash_pattern = deleted *;Gel&APY-schte *
    # match any folders that start with "deleted " or "Gel&#246;schte "
    # match is _case_senstive_!
    #
    #   antispam_trash_pattern_ignorecase = deleted *;Gel&APY-schte *
    # match any folders that start with "deleted " or "gel&#246;schte "
    # match is _case_insenstive_, except the non-USASCII letters,
    # "&#246;" in this example.
    # To match the upper-case &#214;, too, you need to add yet another
    # pattern "gel&ANY-schte *", note the different UTF7 encoding:
    # &ANY- instead of &APY-.


    # semicolon-separated list of Trash folders (default unset i.e. none)
    # antispam_trash =
    antispam_trash = trash;Trash;Deleted Items; Deleted Messages
    # antispam_trash_pattern = trash;Trash;Deleted *
    # antispam_trash_pattern_ignorecase = trash;Deleted *

    # semicolon-separated list of spam folders
    antispam_spam = spam,Spam,SPAM,junk,Junk,JUNK
    # antispam_spam_pattern = SPAM
    # antispam_spam_pattern_ignorecase = SPAM

    # semicolon-separated list of unsure folders (default unset i.e. none)
    # antispam_unsure =
    # antispam_unsure_pattern =
    # antispam_unsure_pattern_ignorecase =

    # Whether to allow APPENDing to SPAM folders or not. Must be set to
    # "yes" (case insensitive) to be activated. Before activating, please
    # read the discussion below.
    # antispam_allow_append_to_spam = no

    ###########################
    # BACKEND SPECIFIC OPTIONS
    #

    #===================
    # dspam plugin

    # dspam binary
    antispam_dspam_binary = /usr/bin/dspam

    # semicolon-separated list of extra arguments to dspam
    # (default unset i.e. none)
    # antispam_dspam_args =
    # antispam_dspam_args = --deliver=;--user;%u  # % expansion done by dovecot
    # antispam_dspam_args = --mode=teft

    # Ignore mails where the DSPAM result header contains any of the
    # strings listed in the blacklist
    # (default unset i.e. none)
    # antispam_dspam_result_header = X-DSPAM-Result
    # semicolon-separated list of blacklisted results, case insensitive
    # antispam_dspam_result_blacklist = Virus

    # semicolon-separated list of environment variables to set
    # (default unset i.e. none)
    # antispam_dspam_env =
    # antispam_dspam_env = HOME=%h;USER=%u

    #=====================
    # pipe plugin
    #
    # This plug can be used to train via an arbitrary program that
    # receives the message on standard input. Since sendmail can be
    # such a program, it can be used to send the message to another
    # email address for training there.
    #
    # For example:
    #   antispam_pipe_program = /path/to/mailtrain
    #        (defaults to /usr/sbin/sendmail)
    #   antispam_pipe_program_args = --for;%u
    #   antispam_pipe_program_spam_arg = --spam
    #   antispam_pipe_program_notspam_arg = --ham
    #   antispam_pipe_tmpdir = /tmp
    # will call it, for example, like this:
    #   /path/to/mailtrain --for jberg --spam
    #
    # The old configuration options from when this plugin was called
    # "mailtrain" are still valid, these are, in the same order as
    # above: antispam_mail_sendmail, antispam_mail_sendmail_args,
    # antispam_mail_spam, antispam_mail_notspam and antispam_mail_tmpdir.
    #
    # Alternatively, if you need to give multiple options, you can use
    # the spam_args/notspam_args parameters (which are used in preference
    # of the singular form):
    #   antispam_pipe_program_spam_args = --spam;--my-other-param1
    #   antispam_pipe_program_notspam_args = --ham;--my-other-param2
    # which will then call
    #   /path/to/mailtrain --for jberg --spam --my-other-param1

    # temporary directory
    antispam_pipe_tmpdir = /tmp

    # spam/not-spam argument (default unset which will is not what you want)
    antispam_pipe_program_spam_arg = --spam
    antispam_pipe_program_notspam_arg = --ham

    # binary to pipe mail to
    antispam_pipe_program = /etc/dovecot/sa-learn.sh
    #antispam_pipe_program_args = -f;%u@example.com 
    # % expansion done by dovecot

    #===================
    # crm114 plugin

    # mailreaver binary
    antispam_crm_binary = /bin/false
    # antispam_crm_binary = /usr/share/crm114/mailreaver.crm

    # semicolon-separated list of extra arguments to crm114
    # (default unset i.e. none)
    # antispam_crm_args =
    # antispam_crm_args = --config=/path/to/config

    # semicolon-separated list of environment variables to set
    # (default unset i.e. none)
    # antispam_crm_env =
    # antispam_crm_env = HOME=%h;USER=%u

    # NOTE: you need to set the signature for this backend
    antispam_signature = X-CRM114-CacheID

    #===================
    # spool2dir plugin

    # spam/not-spam spool2dir drop (default unset which will give errors)
    # The first %%lu is replaced by the current time.
    # The second %%lu is replaced by a counter to generate unique names.
    # These two tokens MUST be present in the template! However
    # you can insert any C-style modifier as shown.
    # antispam_spool2dir_spam    = /tmp/spamspool/%%020lu-%u-%%05lus
    # antispam_spool2dir_notspam = /tmp/spamspool/%%020lu-%u-%%05luh
}

плагин интересный, работает не только с DSPAM
Делаем необходимые нам изменения

antispam_debug_target = syslog 
antispam_verbose_debug = 1 
antispam_backend = dspam 
antispam_signature = X-DSPAM-Signature 
antispam_signature_missing = error  
# после того как заработает изменить на move
antispam_trash = Trash 
antispam_spam = Spam
antispam_allow_append_to_spam = yes 
antispam_dspam_binary = /usr/local/bin/dspam 
antispam_dspam_args = --deliver=;--user;%u;--source=error;--signature=%%s
# закомментить там все с pipe!

dovecot

допишем, что используем еще один plugin
/usr/local/etc/dovecot/conf.d/20-imap.conf
mail_plugins = $mail_plugins quota .......... antispam 

/usr/local/etc/rc.d/dovecot restart

Я плясал с бубном пару дней, прежде чем заработало, но конфиг выше правильный.
Чтобы понять работает оно или нет, смотрим пишется ли чего в базу dspam при перемещении писем
tail -f /var/log/mysql.log

и еще мне очень помог
tail -f /var/log/debug.log

Вместо концовки.
Надеюсь кому-нибудь вся эта писанина будет полезной.
Создал тему http://forum.lissyara.su/viewtopic.php?f=14&t=39481
Если есть замечания/ошибки, прошу. Постараюсь отвечать.



размещено: 2013-06-01,
последнее обновление: 2014-12-11,
автор: KontraBass



 

  Этот информационный блок появился по той простой причине, что многие считают нормальным, брать чужую информацию не уведомляя автора (что не так страшно), и не оставляя линк на оригинал и автора — что более существенно. Я не против распространения информации — только за. Только условие простое — извольте подписывать автора, и оставлять линк на оригинальную страницу в виде прямой, активной, нескриптовой, незакрытой от индексирования, и не запрещенной для следования роботов ссылки.
  Если соизволите поставить автора в известность — то вообще почёт вам и уважение.

© lissyara 2006-10-24 08:47 MSK

Время генерации страницы 0.1247 секунд
Из них PHP: 77%; SQL: 23%; Число SQL-запросов: 75 шт.
Исходный размер: 295109; Сжатая: 58309