воскресенье, 26 января 2014 г.

Установка и настройка Dovecot

В прошлой заметке была рассмотрена настройка веб-интерфейса для управления почтовыми ящиками Postfixadmin.

В этой заметке рассмотрена настройка агента доставки почты (MDA) Dovecot для совместного использования с Postfixadmin. Рассмотрена вторая версия сервера, настройка которой несколько отличается от настройки первой версии. Я и раньше не считал документацию на Dovecot хорошей, но для настройки второй версии мне пришлось потратить ещё больше времени, потому что для неё документации ещё меньше. Собственно, всё, что есть из документации - это официальный сайт с wiki-страницами, больше напоминающими обрывки HowTo, нежели систематическую исчерпывающую документацию по каждой доступной опции.

Файл конфигурации Dovecot состоит из нескольких логических элементов: глобальные настройки, раздел настройки словарей, несколько разделов настройки сервисов, раздел настройки плагинов. Файл конфигурации не назовёшь логичным, поскольку плагины включаются в одном разделе файла, а настройки хранятся в другом. Взаимосвязи между плагинами и используемыми ими сервисами тоже не всегда кажутся очевидными.

Однако при всех указанных недостатках, Dovecot всё равно настраивается проще других подобных систем (Courier и Cyrus). Причин у этого, на мой взгляд, две: он лучше поддерживается разработчиками дистрибутива и в нём меньше исторических наслоений. (По непонятным причинам поддержка Courier оставляет желать лучшего: когда я пытался его настроить, мне пришлось пересобрать пакет с библиотекой SASL, чтобы она поддерживала прямую работу с courier-auth. После длительных мучений с его настройкой, я решил больше не биться головой в закрытую дверь, пытаясь исправить очередную кривизну в поставке по умолчанию, и настроил Dovecot. Собственно, я и пытался-то настроить Courier из простого любопытства).

Главное разочарование, постигшее меня при настройке второй версии Dovecot, заключалось в том, что теперь не работает придуманный мной метод аутентификации POP-before-SMTP. В новом Dovecot можно задавать только скрипты, выполняемые при отключении клиента от сервера POP3 или IMAP, а не в момент подключения, как это было раньше. В результате для того, чтобы отправить письмо, нужно не только подключиться к POP3 или IMAP-серверу, но и тут же отключиться от него. Впрочем, большинство современных почтовых клиентов имеет встроенную поддержку аутентификации на SMTP-сервере, поэтому утрата не выглядит сейчас столь уж серьёзной.

1. Установка Dovecot

Установим пакеты Dovecot, содержащие поддержку серверов POP3 и IMAP, а также пакет, позволяющий использовать данные из MySQL:
# apt-get install dovecot-core dovecot-imapd dovecot-pop3d dovecot-mysql
2. Подготовка системы

Создадим группу и пользователя vmail, от имени которого будет работать Dovecot и дадим этому пользователю доступ к каталогу, в котором будет храниться почта пользователей почтовой системы. На серверах для размещения почтовых ящиков, как и другой часто меняющейся информации, обычно используется раздел /var, который заранее делается достаточно большим. На настраиваемой мной системе больше всего свободного места на разделе home, поэтому я размещу почтовые ящики пользователей на нём:
# groupadd -g 120 -r vmail
# useradd -g 120 -r -u 120 vmail
# mkdir /home/vmail
# chown vmail:vmail /home/vmail
# chmod u=rwx,g=rx,o= /home/vmail
Добавляем пользователя dovecot для доступа к базе данных:
USE mysql;

INSERT INTO user(user, password, host) VALUES('dovecot', PASSWORD('dovecot_password'), 'localhost');

FLUSH PRIVILEGES;
Вместо пароля dovecot_password я сгенерировал случайный пароль при помощи программы pwgen из одноимённого пакета. Можно сгенерировать сразу длинный пароль, поскольку вводить вручную его не придётся:
$ pwgen 16
Здесь и ниже я оставил пароль dovecot_password для того, чтобы описание настройки было более наглядным. При реальной настройке Dovecot стоит использовать случайный пароль.

Таблица mailbox в базе данных postfixadmin содержит информацию о почтовых ящиках. Дадим пользователю dovecot доступ к таблице mailbox и её колонкам:
USE mysql;

INSERT INTO tables_priv(host, db, user, table_name, table_priv, column_priv) VALUES
('localhost', 'postfixadmin', 'dovecot', 'mailbox', '', 'Select');

INSERT INTO columns_priv(host, db, user, table_name, column_name, column_priv) VALUES
('localhost', 'postfixadmin', 'dovecot', 'mailbox', 'username', 'Select'),
('localhost', 'postfixadmin', 'dovecot', 'mailbox', 'local_part', 'Select'),
('localhost', 'postfixadmin', 'dovecot', 'mailbox', 'domain', 'Select'),
('localhost', 'postfixadmin', 'dovecot', 'mailbox', 'password', 'Select'),
('localhost', 'postfixadmin', 'dovecot', 'mailbox', 'quota', 'Select'),
('localhost', 'postfixadmin', 'dovecot', 'mailbox', 'active', 'Select');

FLUSH PRIVILEGES;
3. Базовая настройка Dovecot

Обратимся к странице Сравнение почтовых программ на Википедии. Судя по сводной таблице механизмов аутентификации, поддерживаемых разными почтовыми клиентами, большинство из них поддерживает механизмы PLAIN, LOGIN и CRAM-MD5.

При использовании PLAIN и LOGIN пароль передаётся в открытом виде, а хранить в базе данных его можно в хэшированном виде. В случае с CRAM-MD5 дело обстоит с точностью до наоборот - пароль передаётся в хэшированном виде, но хранится - в открытом.

Что безопаснее? Если вы не собираетесь настраивать защищённые версии протоколов IMAP и POP3, то лучше использовать CRAM-MD5. На мой взгляд вероятность перехвата паролей выше, нежели вероятность получения не авторизованного доступа к базе данных. Если же предполагается всегда использовать шифрование, то безопаснее использовать PLAIN и LOGIN, потому что при их использовании можно хранить пароли в базе данных в хэшированном виде. Пароль при этом не получится перехватить, а в случае получения доступа к хэшам паролей воспользоваться ими напрямую не удастся, т.к. нужно будет подобрать пароль, который будет соответствовать хэшу.

Я буду использовать защищённые версии протоколов IMAP и POP3, поэтому настрою в файле /etc/dovecot/conf.d/10-auth.conf механизмы PLAIN и LOGIN, чтобы хранить пароли в базе данных в хэшированном виде:
disable_plaintext_auth = no
auth_default_realm = domain.tld
auth_mechanisms = plain login
!include auth-sql.conf.ext
Настроим использование учётных данных из базы данных SQL, прописав в файле /etc/dovecot/conf.d/auth-sql.conf.ext следующие секции:
passdb {
  driver = sql
  args = /etc/dovecot/dovecot-mysql.conf
}
userdb {
  driver = sql
  args = /etc/dovecot/dovecot-mysql.conf
}
Теперь нужно прописать в файл /etc/dovecot/dovecot-mysql.conf учётные данные для доступа к базе данных и запросы для извлечения из неё необходимой информации о почтовых ящиках:
driver = mysql

connect = host=localhost dbname=postfixadmin user=dovecot password=dovecot_password

default_pass_scheme = MD5-CRYPT

password_query = SELECT local_part AS username, \
                        domain, \
                        password, \
                        120 AS userdb_uid, \
                        120 AS userdb_gid, \
                        CONCAT('*:bytes=', quota) AS userdb_quota_rule \
                 FROM mailbox \
                 WHERE username = '%u' \
                   AND active = 1

user_query =  SELECT CONCAT('*:bytes=', quota) AS quota_rule, \
                     120 AS uid, \
                     120 AS gid \
              FROM mailbox \
              WHERE username = '%u' \
                AND active = 1

iterate_query = SELECT username AS user \
                FROM mailbox \
                WHERE active = 1
Выделенные жирным шрифтом части запросов используются плагином quota. Если вы не собираетесь настраивать этот плагин, то эти части запросов можно пропустить. Настройка этого плагина подробнее рассмотрена ниже.

Стоит сразу же изменить права доступа к этому файлу, чтобы посторонние пользователи системы не смогли увидеть пароль, под которым dovecot будет подключаться к базе данных:
# chown root:dovecot /etc/dovecot/dovecot-mysql.conf 
# chmod u=rw,g=r,o= /etc/dovecot/dovecot-mysql.conf
В противном случае потенциальный злоумышленник, получивший локальный непривилегированный доступ к системе, сможет получить список почтовых ящиков системы и хэши паролей от них (или сами пароли). Понятно, чем может быть опасно получение доступа к паролям или их хэшам - злоумышленник сможет получить полный доступ к ящикам. Не столь очевидной может показаться опасность получения злоумышленником списка почтовых ящиков - на них он может начать отправлять спам, что тоже не обрадует ни пользователей почтовой системы, ни её администратора.

Изменим форматирование отметок времени, вписав в файл /etc/dovecot/conf.d/10-logging.conf следующую настройку:
log_timestamp = "%Y-%m-%d %H:%M:%S "
На время отладки также можно включить другие опции из этого файла:
auth_verbose = yes
auth_verbose_passwords = yes
auth_debug = yes
mail_debug = yes
В файле /etc/dovecot/conf.d/10-mail.conf настроим путь к почтовым ящикам и пользователя, от имени которого dovecot будет работать с ящиками:
mail_home = /home/vmail/%Ld/%Ln
mail_location = maildir:/home/vmail/%Ld/%Ln
mail_uid = vmail
mail_gid = vmail
first_valid_uid = 120
last_valid_uid = 120
first_valid_gid = 120
last_valid_gid = 120
Сейчас придётся немного опять забежать вперёд и настроить SASL. Это сервис, при помощи которого Postfix будет проверять учётные данные почтовых клиентов. Для этого отредактируем файл /etc/dovecot/conf.d/10-master.conf и впишем в него путь к UNIX-сокету и права доступа к нему:
service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0600
    user = postfix
    group = postfix
  }
}
Сокет-файл размещается в chroot-окружении Postfix и доступен для чтения и записи только пользователю postfix.

Зададим в файле /etc/dovecot/conf.d/15-lda.conf адрес, с которого Dovecot будет отправлять сообщения об ошибках:
postmaster_address = postmaster@domain.tld
Осталось отредактировать файл /etc/dovecot/dovecot.conf, указав в нём адрес, на котором сервер будет ожидать подключений:
!include_try /usr/share/dovecot/protocols.d/*.protocol
listen = *
!include conf.d/*.conf
!include_try local.conf
Начальная настройка сервера окончена. Осталось перезапустить Dovecot, чтобы настройки вступили в силу:
# /etc/init.d/dovecot restart

4. Настройка плагина acl

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

В файле /etc/dovecot/conf.d/10-mail.conf включаем использование плагина:
mail_plugins = acl
В файле /etc/dovecot/conf.d/20-imap.conf включаем использование плагина в IMAP-сервере:
protocol imap {
  mail_plugins = $mail_plugins imap_acl
}
В файле /etc/dovecot/conf.d/10-mail.conf прописываем следующие настройки:
namespace inbox {
  type = private
  separator = /
  prefix =
  inbox = yes
}

namespace {
  type = shared
  separator = /
  prefix = shared/%%u/
  location = maildir:%%h:INDEX=%h/shared/%%u
  subscriptions = yes
  list = children
}
Эти настройки описывают два пространства имён: в первом хранится личная почта пользователя, а во втором будут отображаться каталоги других пользователей, к которым этот пользователь имеет доступ.

Поясню смысл настроек location для пространства имён общих каталогов:
  • maildir:%%h - означает место расположения чужого почтового ящика в формате Maildir,
  • %%h - полный путь к Maildir-каталогу чужого ящика,
  • INDEX=%h/shared/%%u - задаёт каталог, в который как бы монтируются каталоги чужой почты, к которым её владелец дал нам доступ,
  • %h - путь к Maildir-каталогу нашего ящика,
  • %%u - имя другого пользователя в виде box@domain.tld.

В файл /etc/dovecot/conf.d/90-acl.conf прописываем настройки плагина:
plugin {
  acl = vfile
  acl_shared_dict = file:/home/vmail/%Ld/shared-mailboxes.db
}
Значение vfile предписывает создавать внутри почтового ящика файл dovecot-acl, в котором и будут прописываться права доступа к нему со стороны других пользователей.

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

Заодно опишем в файле /etc/dovecot/conf.d/15-mailboxes.conf назначение различных каталогов внутри пространства имён, в котором хранится личная почта пользователя:
namespace inbox {
  mailbox Drafts {
    special_use = \Drafts
  }
  mailbox Junk {
    special_use = \Junk
  }
  mailbox Trash {
    special_use = \Trash
  }
  mailbox Sent {
    special_use = \Sent
  }
}
  • Drafts - каталог черновиков,
  • Junk - каталог для спама,
  • Trash - каталог для удалённых писем,
  • Sent - каталог для отправленных писем.
Современные почтовые программы смогут прямо по протоколу IMAP узнать назначение каждого из специальных каталогов, вне зависимости от их названия. Это бывает полезно, если каталог имеет нестандартное название или название на языке пользователя ящика, например "Входящие" или "Спам".

Чтобы настройки плагина acl вступили в силу, нужно перезапустить Dovecot:
# /etc/init.d/dovecot restart
5. Настройка плагина quota

Плагин quota позволяет назначить для почтового ящика ограничения на объём хранящихся в нём писем или даже на их общее количество. На мой взгляд, ограничение на общее количество писем имеет довольно мало смысла. Единственная польза, которая мне приходит на ум - это возможность защититься от исчерпания inode'ов в файловой системе, если кто-то намеренно решит отправить огромное количество мелких писем в ящики пользователей, с целью нарушить работу почтовой системы.

Мы настроим плагин так, чтобы он использовал значения квот, указанные в интерфейсе Postfixadmin. Эти квоты ограничивают только максимальный объём писем в ящике.

Включим использование плагина в файле /etc/dovecot/conf.d/10-mail.conf:
mail_plugins = acl quota
Жирным шрифтом показан добавленный текст, а курсивом - текст, добавленный нами при включении плагина acl. Если вы не включали плагин acl, то вписывать этот текст не нужно.
В файл /etc/dovecot/conf.d/15-lda.conf впишем, что в случае превышения квоты Dovecot должен сообщать о временной ошибке, но не отклонять письмо окончательно. Почтовый сервер отправителя (или наш MTA) будет периодически предпринимать повторные попытки в надежде на то, что адресат почистит свой ящик от ненужных писем.
quota_full_tempfail = yes
В файл /etc/dovecot/conf.d/20-imap.conf добавим поддержку квот в IMAP-сервере:
protocol imap {
  mail_plugins = $mail_plugins imap_acl imap_quota
}
Этот плагин позволит почтовым клиентам, работающим по протоколу IMAP, узнавать квоту почтового ящика и её текущее использование.

Укажем в файле /etc/dovecot/conf.d/90-quota.conf, что значения квот берутся из словаря и зададим пустое правило по умолчанию:
plugin {
  quota = dict:User quota::proxy::quota
  quota_rule = *:
}
Текст proxy задаёт использование прокси-сервера, который выполняет мультиплексирование подключений к базе данных. Прокси устанавливает постоянные подключения к базе данных и выполняет необходимые запросы через эти подключения. Таким образом снижаются накладные расходы на повторные переподключения и уменьшается количество одновременно установленных подключений, поскольку без использования прокси каждый процесс, обслуживающий одного клиента, устанавливал бы своё собственное подключение к базе данных.

Плагин quota использует сервис доступа к словарям данных. Включим и настроим этот сервис в файле /etc/dovecot/conf.d/10-master.conf:
service dict {
  unix_listener dict {
    mode = 0600
    user = vmail
    group = vmail
  }
}
Теперь укажем в файле /etc/dovecot/dovecot.conf, где хранятся настройки словаря с данными квот:
dict {
  quota = mysql:/etc/dovecot/dovecot-dict-mysql.conf
}
И укажем в файле с настройками /etc/dovecot/dovecot-dict-mysql.conf, в какой таблице хранятся данные о текущем использовании квот и как подключиться к базе данных с этой таблицей:
connect = host=localhost dbname=postfixadmin user=dovecot password=dovecot_password

map {
  pattern = priv/quota/storage
  table = quota2
  username_field = username
  value_field = bytes
}
Сразу же изменим права доступа к этому файлу, чтобы посторонние пользователи системы не смогли увидеть пароль, под которым dovecot будет подключаться к словарям в базе данных:
# chown root:dovecot /etc/dovecot/dovecot-dict-mysql.conf 
# chmod u=rw,g=r,o= /etc/dovecot/dovecot-dict-mysql.conf
Выдадим пользователю dovecot права на доступ к таблице quota2 и её колонкам:
USE mysql;

INSERT INTO tables_priv(host, db, user, table_name, table_priv, column_priv) VALUES
('localhost', 'postfixadmin', 'dovecot', 'quota2', 'Delete', 'Select,Insert,Update');

INSERT INTO columns_priv(host, db, user, table_name, column_name, column_priv) VALUES
('localhost', 'postfixadmin', 'dovecot', 'quota2', 'username', 'Select,Insert,Update'),
('localhost', 'postfixadmin', 'dovecot', 'quota2', 'bytes', 'Select,Insert,Update');

FLUSH PRIVILEGES;
Не забудьте вписать в файл /etc/dovecot/dovecot-mysql.conf текст, выделенный жирным шрифтом в разделе 3. Этот текст извлекает из базы данных настройки квот ящиков.

Настройка плагина закончена. Осталось перезапустить Dovecot:
# /etc/init.d/dovecot restart
6. Настройка плагина expire

Плагин expire позволяет автоматически удалять устаревшие письма из каталогов почтовых ящиков. Обычно это каталоги с удалённой почтой и спамом. Поскольку алгоритмы обнаружения спама не совершенны, не стоит удалять такие письма - нужно дать пользователю возможность прочитать письмо, ошибочно определённое как спам. С другой стороны, хочется избавить пользователя от утомительной привычки периодически чистить почтовый ящик, особенно для каталогов со спамом и удалёнными письмами - письма в этих каталогах обладают заведомо низкой ценностью.

Включим плагин в файле /etc/dovecot/conf.d/10-mail.conf:
mail_plugins = acl quota expire
Курсивом отмечены плагины, настройка которых была рассмотрена выше. Если вы пропустили их настройку, не нужно их вписывать - достаточно добавить текст, отмеченный жирным шрифтом.
Теперь настроим плагин в файле /etc/dovecot/conf.d/90-expire.conf:
plugin {
  expire = Trash 7            # Хранение писем в папке Trash - 7 дней
  expire2 = Trash/* 7         # Хранение писем в подпапках папки Trash - 7 дней
  expire3 = Junk 30           # Хранение писем в папке Junk - 30 дней
  expire_dict = proxy::expire # Использовать словарь для хранения отметок времени писем
}
Текст proxy задаёт использование прокси-сервера, который выполняет мультиплексирование подключений к базе данных (см. выше описание плагина quota). На самом деле для каждого каталога будет храниться лишь одна отметка времени для самого старого письма в каталоге, которая будет обновляться при очередной чистке каталога.

В файле /etc/dovecot/dovecot.conf укажем путь к файлу с настройками словаря, в котором будут храниться данные об отметках времени писем:
dict {
  quota = mysql:/etc/dovecot/dovecot-dict-mysql.conf
  expire = mysql:/etc/dovecot/dovecot-dict-mysql.conf
}
Курсивом отмечена строчка, которая была добавлена в процессе настройки плагина quota. Сейчас же нужно добавить строчку, отмеченную жирным шрифтом.

Настроим учётные данные для подключения к базе данных в файле /etc/dovecot/dovecot-dict-mysql.conf. Там же укажем, в какой таблице и в каких её полях хранить отметки времени.
connect = host=localhost dbname=postfixadmin user=dovecot password=dovecot_password

map {
  pattern = priv/quota/storage
  table = quota2
  username_field = username
  value_field = bytes
}

map {
  pattern = shared/expire/$user/$mailbox
  table = expire
  value_field = expire_stamp

  fields {
    username = $user
    mailbox = $mailbox
  }
}
Тут так же нужно добавить лишь текст, выделенный жирным шрифтом. Курсивом отмечен текст, добавленный при настройке плагина quota.

Если вы ещё не поменяли права доступа к этому файлу, стоит сделать это сейчас, чтобы посторонние пользователи системы не могли прочитать пароль, под которым dovecot будет подключаться к словарям в базе данных:
# chown root:dovecot /etc/dovecot/dovecot-dict-mysql.conf 
# chmod u=rw,g=r,o= /etc/dovecot/dovecot-dict-mysql.conf
Включим в файле /etc/dovecot/conf.d/10-master.conf сервис для доступа к словарям, если вы его ещё не включили при настройке плагина quota:
service dict {
  unix_listener dict {
    mode = 0600
    user = vmail
    group = vmail
  }
}
Поскольку по умолчанию в Postfixadmin нет таблицы, предназначенной для хранения информации плагина expire из Dovecot, создадим эту таблицу и дадим пользователю Dovecot права доступа к ней:
USE postfixadmin;

CREATE TABLE expire (
  username varchar(255) not null,
  mailbox varchar(255) not null,
  expire_stamp integer not null,
  primary key (username, mailbox)
);

USE mysql;
 
INSERT INTO tables_priv(host, db, user, table_name, table_priv, column_priv) VALUES
('localhost', 'postfixadmin', 'dovecot', 'expire', 'Delete', 'Select,Insert,Update');

INSERT INTO columns_priv(host, db, user, table_name, column_name, column_priv) VALUES
('localhost', 'postfixadmin', 'dovecot', 'expire', 'username', 'Select,Insert,Update'),
('localhost', 'postfixadmin', 'dovecot', 'expire', 'mailbox', 'Select,Insert,Update'),
('localhost', 'postfixadmin', 'dovecot', 'expire', 'expire_stamp', 'Select,Insert,Update');

FLUSH PRIVILEGES;
На этом настройку плагина можно считать оконченной. Осталось лишь перезапустить Dovecot, чтобы изменения вступили в силу:
# /etc/init.d/dovecot restart
7. Настройка SSL

Настройка SSL будет подробнее рассмотрена в одной из следующих заметок. Там будет описана настройка отдельных сертификатов SSL для разных доменов, а также будет освещён вопрос подготовки самих сертификатов - самоподписанных или подписанных центром сертификации.

Если у вас имеются готовый подписанный сертификат, можно включить поддержку SSL в файле /etc/dovecot/conf.d/10-ssl.conf и указать в нём пути к файлам сертификата:
ssl = yes
ssl_cert = </etc/ssl/mail_public.pem
ssl_key = </etc/ssl/mail_private.pem
После настройки сертификатов нужно перезапустить Dovecot, чтобы изменения вступили в силу:
# /etc/init.d/dovecot restart
8. Настройка плагина sieve

Sieve - это скрипты фильтрации почты, которые выполняются агентом локальной доставки (LDA) в момент получения письма от почтового сервера (MTA). Скрипты позволяют раскладывать письма в разные папки, ориентируясь на их содержимое - тему письма, получателей, отправителей и т.п. Можно удалить письмо, переслать его на другой ящик или отправить уведомление отправителю, причём использовать можно любое поле заголовка или содержимое тела письма.

Главное преимущество Sieve заключается в том, что пользователю не нужно настраивать правила фильтрации в каждом из используемых им почтовых клиентов - правила едины для всех почтовых клиентов сразу. Кроме того, фильтрация происходит вообще без участия клиента. Клиент, подключившись к почтовому ящику, имеет возможность работать уже с отсортированной почтой. Кроме того, отправка уведомлений о получении или пересылка писем на другой ящик вообще может происходить без участия почтового клиента.

Конечно, в наши времена больших почтовых сервисов типа Gmail или Яндекс-почты, этим никого не удивишь. Но тут плюс заключается в том, что перед нами не стоит дилемма "удобство" - "безопасность". Мы можем хранить почту у себя, не делясь ею с посторонними компаниями, имея над ней полный контроль, и в то же время можем пользоваться удобствами, характерными для больших почтовых сервисов.

Установим пакет с плагином Sieve:
# apt-get install dovecot-sieve
Включим использование плагина в файле /etc/dovecot/conf.d/15-lda.conf:
protocol lda {
  mail_plugins = $mail_plugins sieve
}
Укажем настройки плагина в файле /etc/dovecot/conf.d/90-sieve.conf:
plugin {
  sieve = /home/vmail/%Ld/%n/active.sieve # Расположение активного скрипта
  sieve_dir = /home/vmail/%Ld/%n/sieve    # Каталог для скриптов
  sieve_max_script_size = 1M              # Максимальный размер одного скрипта
  sieve_quota_max_scripts = 50            # Максимальное количество скриптов
  sieve_quota_max_storage = 1M            # Максимальный общий объём скриптов
}
Каждый пользователь может обладать собственным набором Sieve-скриптов, из которых в любой момент времени активным может быть только один. Каталог для скриптов указывается в настройке sieve_dir, а в настройке sieve указывается имя символической ссылки, которая будет указывать на активный скрипт.

После настройки плагина нужно перезапустить Dovecot, чтобы изменения вступили в силу:
# /etc/init.d/dovecot restart
Подробнее о скриптах Sieve можно почитать на Википедии, в статье Sieve.

9. Настройка сервиса managesieve

Плагин sieve не был бы столь полезным, если бы Sieve-скриптами нельзя было бы управлять прямо из почтового клиента. Именно эту функцию и реализует сервис ManageSieve. Он ожидает подключений клиентов на отдельном TCP-порту 4190. Для управления скриптами клиент использует учётные данные своего почтового ящика.

Для включения сервиса достаточно лишь установить дополнительный пакет:
# apt-get install dovecot-managesieve
В следующих заметках фильтрация писем при помощи Sieve будет рассмотрена подробнее - я покажу, как им пользоваться в почтовых клиентах.

10. Результирующий файл конфигурации

Поскольку настроек очень много, проверить их можно при помощи следующей команды:
$ doveconf -n
Опция n предписывает показывать только те настройки, которые отличаются от настроек по умолчанию. У меня со всеми плагинами, настройка которых была тут описана, команда выдаёт следующий результат:
# 2.1.7: /etc/dovecot/dovecot.conf
# OS: Linux 3.2.0-4-amd64 x86_64 Debian 7.3 ext4
auth_default_realm = domain.tld
auth_mechanisms = plain login
dict {
  expire = mysql:/etc/dovecot/dovecot-dict-mysql.conf
  quota = mysql:/etc/dovecot/dovecot-dict-mysql.conf
}
disable_plaintext_auth = no
first_valid_gid = 120
first_valid_uid = 120
last_valid_gid = 120
last_valid_uid = 120
listen = *
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_gid = vmail
mail_home = /home/vmail/%Ld/%Ln
mail_location = maildir:/home/vmail/%Ld/%Ln
mail_plugins = quota acl expire
mail_uid = vmail
managesieve_notify_capability = mailto
managesieve_sieve_capability = fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date ihave
namespace {
  list = children
  location = maildir:%%h:INDEX=%h/shared/%%u
  prefix = shared/%%u/
  separator = /
  subscriptions = yes
  type = shared
}
namespace inbox {
  inbox = yes
  location = 
  mailbox Drafts {
    special_use = \Drafts
  }
  mailbox Junk {
    special_use = \Junk
  }
  mailbox Sent {
    special_use = \Sent
  }
  mailbox Trash {
    special_use = \Trash
  }
  prefix = 
  separator = /
  type = private
}
passdb {
  args = /etc/dovecot/dovecot-mysql.conf
  driver = sql
}
plugin {
  acl = vfile
  acl_shared_dict = file:/home/vmail/%Ld/shared-mailboxes.db
  expire = Trash 7
  expire2 = Trash/* 7
  expire3 = Spam 30
  expire_dict = proxy::expire
  quota = dict:User quota::proxy::quota
  quota_rule = *:
  sieve = /home/vmail/%Ld/%n/active.sieve
  sieve_dir = /home/vmail/%Ld/%n/sieve
  sieve_max_script_size = 1M
  sieve_quota_max_scripts = 50
  sieve_quota_max_storage = 1M
}
postmaster_address = postmaster@stupin.su
protocols = " imap sieve pop3"
service auth {
  unix_listener /var/spool/postfix/private/auth {
    group = postfix
    mode = 0600
    user = postfix
  }
}
service dict {
  unix_listener dict {
    group = vmail
    mode = 0600
    user = vmail
  }
}
ssl_cert = </etc/ssl/mail.stupin.su.public.pem
ssl_key = </etc/ssl/mail.stupin.su.private.pem
userdb {
  args = /etc/dovecot/dovecot-mysql.conf
  driver = sql
}
protocol lda {
  mail_plugins = quota acl expire sieve
}
protocol imap {
  mail_plugins = quota acl expire imap_quota imap_acl
}
Примечание от 27 марта 2013 года: Дополнил описание плагина acl.

На этом заметку, посвящённую настройке Dovecot, можно считать оконченой. Продолжение: Установка и настройка Postfix, OpenDKIM, ClamAV-Milter, Milter-Greylist. Или можете продолжить настройку на основе Exim: Настройка Exim

37 комментариев:

Анонимный комментирует...

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

Анонимный комментирует...

Настроил плагин quota, как описано у Вас, но почему-то в таблице БД появляются 2 одинаковые записи на каждого пользователя (чтобы это увидеть, понадобилось убрать primary key при создании таблицы). В чем может быть проблема?

morbo комментирует...

В таблице обязательно должен быть первичный ключ. Без него СУБД не сможет отличить одну запись в таблице от другой.

Две одинаковые записи появляются потому, что вы удалили первичный ключ.

В результате, например, запросы вида INSERT INTO ... ON DUPLICATE KEY UPDATE будут каждый раз добавлять новую запись, поскольку нет ни первичного, ни уникального индекса, который бы мог этому препятствовать.

Roman комментирует...

В том то и проблема: при наличии ключа dovecot ругается, что запись с таким username уже существует. Ситуация: создал таблицу quota с необходимыми полями (3 штуки: username, bytes, messages как и требует конфиг довекот'а) и primery key (username). Изначально таблица пуста. Отправляю письмо пользователю: ругань в логах, о том, что запись уже существует. проверяю таблицу: ПУСТО! Решил проверить и пересоздал таблицу уже без primery key. Таблица пуста. Отпарвляю письмо, проверяю таблицу и вижу, что создано 2 одинаковые записи для отдного и того же пользователя. Отправляю еще письмо - ОБЕ записи обновляются. Поэтому и не понимаю пока, где подвох. Можете еще что-нибудь подсказать?

morbo комментирует...

В этой статье Dovecot использует для хранения счётчиков квот таблицу quota2, которая была создана при установке Postfixadmin.

Roman комментирует...

Проблему решил. На вики Довекот'а http://wiki2.dovecot.org/Quota/Dict есть строка: If you're using PostgreSQL, you'll need a trigger: Забил команды и все стало работать как часы. morbo, спасибо, что не остались равнодушным!

morbo комментирует...

В PostgreSQL нет аналога запроса INSERT INTO ... ON DUPLICATE KEY UPDATE, поэтому там обходятся триггерами.

Хотя правильнее, я считаю, было бы доработать сам Dovecot, чтобы он проверял наличие счётчика и добавлял/обновлял его внутри одной транзакции двумя отдельными запросами.

Roman комментирует...

Не могли бы вы описать, если знаете, как расшаривать каталоги? Прочитал много примеров, wiki довекота, но ничего не помогает. Каталоги вроде расшариваю, а другой пользователь подписаться не может, т.к. в списке подписки расшаренных каталогов нет.

Roman комментирует...

Расшарить получается только каталог "Входящие", остальные каталоги почему-то не видны у пользователя, при попытке подписаться, хотя делаю все аналогично.

Roman комментирует...

Проблему с расщариванием решил. Так как у меня в 10-mail.conf прописано
mail_location = maildir:~/Maildir:LAYOUT=fs
соответственно добавил LAYOUT=fs и в определение namespace, получил
location = maildir:%%h/Maildir:INDEX=~/Maildir/:LAYOUT=fs
и все заработало как часы.

morbo комментирует...

Прошу прощения, что пропустил настройку общих папок. Когда настраивал Dovecot первой версии, этот момент как-то не отложился в памяти.

Сегодня появилось свободное время, я разобрался и дополнил статью в главе по настройке плагина acl.

Спасибо за сообщение, Роман.

ascodts комментирует...

Добрый день! Наткнулся на Ваши материалы в поисках обеспечения возможности предоставления пользователем доступа к своему ящику другому пользователю. Я совсем начинающий в этих вопросах, использую установленный iRedMail.
Правильно ли я понимаю, что именно это позволяет сделать plugin acl и, если да, то где можно найти материалы как пользователь сможет управлять доступом к своей почте после применеия этого plugin'а

morbo комментирует...

Да, за это отвечает плагин acl.

В разных почтовых клиентах это делается по-разному. Описание для Thunderbird и Roundcube можно прочитать тут:
http://vladimir-stupin.blogspot.ru/2014/02/thunderbirdicedove.html
http://vladimir-stupin.blogspot.ru/2014/02/roundcube.html

Slavon комментирует...

Добрый день, у меня почему-то заработал нормально Dovecot только после того, как я в файле /etc/dovecot/dovecot-mysql.conf
указал sql-запросы в одной строке:
password_query = SELECT local_part AS username, domain, password, 120 AS userdb_uid, 120 AS userdb_gid, CONCAT('*:bytes=', quota) AS userdb_quota_rule FROM mailbox WHERE username = '%u' AND active = 1
и
user_query = SELECT CONCAT('*:bytes=', quota) AS quota_rule, 120 AS uid, 120 AS gid FROM mailbox WHERE username = '%u' AND active = 1
и
iterate_query = SELECT username AS user FROM mailbox WHERE active = 1

иначе в логе dovecot:
auth-worker(10788): Error: Error in configuration file /etc/dovecot/dovecot-mysql.conf line 8: Expecting '='
и т.д.

morbo комментирует...

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

Unknown комментирует...

Добрый день, всем,
подскажите, кто-то настраивал квоты Dovecot в связке c Microsoft Windows Active Directory?
Если есть какая либо инфа - прошу помощи в настройке или мануальчик.

Oleg комментирует...

Здравствуйте. Спасибо за статью!
Забыли указать что
в 10-mail.conf нужно внести
mail_home = /home/vmail/%Ld/%Ln

morbo комментирует...

Oleg, спасибо за подсказку. Заглянул в свой 10-mail.conf, нашёл опцию. Статью поправил.

dmitriy комментирует...

Здравствуйте. Спасибо за хорошее руководство!
Установил по вашим мануалам Dovecot + Poctfixadmin + Exim,
отправка почты проходит хорошо, но получение не проходит, вот что выдает
# cat /var/log/exim4/mainlog
H=mail-la0-f44.google.com [209.85.215.44] X=TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128 F=<777@gmail.com> temporarily rejected RCPT : MYSQL: query failed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '= mailbox.quota WHERE mailbox.username = LCASE('admin@host.ru') AND mailbox.' at line 1

подскажите, где я ошибся.

morbo комментирует...

Почитайте в статье про настройку Exim комментарии, связанные с message_size_limit. Проблема уже разобрана, насколько я понимаю.

Dmitriy комментирует...

Для исправления ошибки
dict: Error: sql dict set(unset/lookup): Invalid/unmapped key: priv/quota/messages

map {
pattern = priv/quota/messages
table = quota2
username_field = username
value_field = messages
}

USE mysql;
INSERT INTO columns_priv(host, db, user, table_name, column_name, column_priv) VALUES
('localhost', 'postfixadmin', 'dovecot', 'quota2', 'messages', 'Select,Insert,Update');
FLUSH PRIVILEGES;

morbo комментирует...

Dmitry, я специально не настраивал квоты по количеству сообщений, потому что считаю такие квоты бессмысленными. Пока есть место в ящике, никому не должно быть дела, сколько там сообщений. Откуда эти квоты взялись у вас - я не знаю.

Анонимный комментирует...

Здравствуйте! Настраивал dovecot по Вашей статье. Начальная настройка dovecot и плагин quota. Не могу подключится к dovecot. В логе это:
2016-03-03 19-50-04 auth-worker(5338): Debug: Loading modules from directory: /usr/lib/dovecot/modules/auth
2016-03-03 19-50-04 auth-worker(5338): Debug: Module loaded: /usr/lib/dovecot/modules/auth/libdriver_mysql.so
2016-03-03 19-50-04 auth-worker(5338): Debug: pam(user1@mydomain.org,192.168.3.2): lookup service=dovecot
2016-03-03 19-50-04 auth-worker(5338): Debug: pam(user1@mydomain.org,192.168.3.2): #1/1 style=1 msg=Password:
2016-03-03 19-50-07 auth-worker(5338): Info: pam(user1@mydomain.org,192.168.3.2): pam_authenticate() failed: Authentication failure (password mismatch?)
2016-03-03 19-50-07 auth-worker(5338): Debug: sql(user1@mydomain.org,192.168.3.2): query: SELECT local_part AS username, domain, password, 140 AS userdb_uid, 140 AS userdb_gid, CONCAT('*:bytes=', quota) AS userdb_quota_rule FROM mailbox WHERE username = 'user1@mydomain.org' AND active = 1
2016-03-03 19-50-07 auth-worker(5338): Info: sql(user1@mydomain.org,192.168.3.2): Password mismatch (given password: 123456)
2016-03-03 19-50-09 auth: Debug: client passdb out: FAIL 1 user=user1@mydomain.org original_user=user1

Сделал всё точно по статье. Подскажите пожалуйста как это исправить.
Спасибо.

morbo комментирует...

У вас в журналах фигурируют ошибки, относящиеся к системе аутентификации PAM. Может быть вы забыли включить аутентификацию по MySQL?

В файле /etc/dovecot/conf.d/10-auth.conf должна быть такая строчка:
!include auth-sql.conf.ext

Возможно также, что вы пропустили строчку в файле /etc/dovecot/dovecot-mysql.conf:
default_pass_scheme = MD5-CRYPT

Или в базе данных пароли хранятся в открытом виде, без хэширования функцией MD5.

Анонимный комментирует...

Верно, нужно чтобы в postfixadmin и в dovecot работал одинаковый алгоритм шифрования. У меня заработал только MD5.

Unknown комментирует...

Ксожалению я не увидел описания создания таблицы mailbox,по этому пришлось создать свою (не знаю , правильные ли я создал колонки) ,и теперь не знаю, правильно ли связана данная таблица со всей почтовой системой, остальное все сделал по инструкции, хотелось бы проверить из командной строки как проходит авторзаци, упоминания об этом нету. Так как первый раз настраиваю почту, возникает больше вопросов , чем ответов, хотя перечитал уже пару раз статью.

БОрис комментирует...

А где описание создания таблицы mailbox , про expire есть, апро более важную нет, не знаю. верно ли я её создал ? и как проверить правильно ли проходит авторизация из командной строки?

morbo комментирует...

Не увидели, потому что эту таблицу создаёт PostfixAdmin при установке. В начале этой статьи явным образом упоминается предыдущая, в которой описывается установка PostfixAdmin: http://vladimir-stupin.blogspot.ru/2014/01/postfixadmin.html

Elbars комментирует...

Поправьте, плиз. У вас где-то указано dovecot-dict-mysql.conf , а где-то dovecot-mysql-dict.conf
из-за этого небольшая путаница, копипастами простыми не оттделаешься..
Спасибо.

morbo комментирует...

Elbras, спасибо. Поправил.

Олег комментирует...

Спасибо за статью. Связка тут неполучается ))
Первое: (expire3 = Spam 30) хотя майлбокса такого нету, есть (mailbox Junk)
Второе: (CREATE .. expires.. expire_stamp) хотя (value_field = timestamp) Поправте пжлст.
А в целом достаточно всё подробно. Спасибо.

morbo комментирует...

Олег, спасибо, поправил. Почтовый ящик везде Junk, а поле должно называться expire_stamp, потому что timestamp - это название типа поля в MySQL.

Анонимный комментирует...

Добрый день! У меня проблемы с доставкой письма иногда уходят иногда нет

morbo комментирует...

>У меня проблемы с доставкой письма иногда уходят иногда нет.

Нужно понять, чем одно "иногда" отличается от другого и исправить неправильное "иногда".

Анонимный комментирует...

Добрый день.
А зачем создавать еще одного пользователя и группу vmail, если в системе уже есть пользователь и группа mail:
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin

morbo комментирует...

Добрый.

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

Пользователь и группа mail владеют файлами в каталоге /var/mail/

По сылке можно найти описание этого и других пользователей и групп: https://www.chiark.greenend.org.uk/doc/base-passwd/users-and-groups.html

Но то, что этот пользователь называется mail, не значит, что на него можно повесить всё, связанное с почтой. Например, в том же списке есть пользователь postfix, list, fetchmail.

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

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

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

Анонимный комментирует...

При настройке файла /etc/dovecot/dovecot-mysql.conf в запросах

password_query = SELECT local_part AS username, \
domain, \
password, \
120 AS userdb_uid, \
120 AS userdb_gid, \
CONCAT('*:bytes=', quota) AS userdb_quota_rule \
FROM mailbox \
WHERE username = '%u' \
AND active = 1

user_query = SELECT CONCAT('*:bytes=', quota) AS quota_rule, \
120 AS uid, \
120 AS gid \
FROM mailbox \
WHERE username = '%u' \
AND active = 1

Не могу понять что за числа 120 и от куда их берете?