Хранение счётчиков квот в MySQL настроил быстро, формирование правил квот по данным из MySQL тоже настроил быстро. Однако после настройки текущие значения счётчиков квот становились отрицательными и со временем только уменьшались. Я сразу подумал, что POP3-сервер обновляет счётчики квот, т.к. его задача лишь забирать почту из ящика, а вот LDA (агент локальной доставки) - не обновляет, т.к. именно он кладёт почту в ящики и должен увеличивать значения счётчиков.
В конечном итоге оказалось, что вместо LDA delivery из Dovecot по-прежнему используется LDA virtual из Postfix. Произошло это потому что действие настройки virtual_transport = dovecot перекрывается настройкой transport_maps = mysql:/etc/postfix/sql/transport.cf, где для тестируемого домена был настроен транспорт virtual. Здесь можно поблагодарить Вьетце Венема за отличную документацию - это я прочитал прямо в man 5 postconf. Dovecot практически не документирован, а вики-страницы с Howto по настройке различных фишек Dovecot за документацию я не считаю.
После исправления значения транспорта в базе данных возникло ещё несколько проблем:
1. В настройках LDA Dovecot не был указан параметр postmaster_address,
2. Не был настроен сокет /var/run/dovecot/auth-master,
3. Имена каталогов, в которые LDA delivery из Dovecot складывал почту, были строчными, а имена существующих каталогов почтовых ящиков, в которые складывал почту LDA virtual из Postfix, содержали символы в разном регистре.
Проблемы решались следующим образом:
1. Указан параметр postmaster_address,
2. Прописана секция master в секции socket listen из секции auth default,
3.1. Добавлены буквы L в настройке mail_location, которые указывают принудительно использовать нижний регистр для каталогов почтовых ящиков.
3.2. Использована команда rename 'y/A-Z/a-z/' * для того, чтобы переименовать каталоги почтовых ящиков. Некоторые каталоги, из которых уже успели попробовать забрать почту, пришлось обрабатывать вручную - нужно было перенести письма из старых каталогов в новые, а старые затем удалить.
Итоговые конфигурационные файлы Dovecot помещаю сюда, чтобы в следующий раз не наступать на те же грабли:
protocols = pop3 disable_plaintext_auth = no log_timestamp = "%Y-%m-%d %H:%M:%S " mail_location = maildir:/var/mail/virtual/%Ld/%Ln first_valid_uid = 999 first_valid_gid = 999 dict { quotadict = mysql:/etc/dovecot/dovecot-dict-mysql.conf } plugin { quota = dict:user::proxy::quotadict # Квота по умолчанию - объём ящика 1 гигабайт, # не более 1000 писем в ящике # Эта квота заменяется квотой, найденной в БД quota_rule = *:storage=1G:messages=1000 } protocol pop3 { mail_plugins = quota mail_executable = /etc/dovecot/pop-update-lastlog.sh } protocol lda { # Ящик администратора почтовой системы postmaster_address = postadmin@domain.tld mail_plugins = quota } # Домен по умолчанию для пользователей, пытающихся # аутентифицироваться в Dovecot без указания домена auth_default_realm = domain.tld auth default { mechanisms = plain login passdb sql { args = /etc/dovecot/dovecot-mysql.conf } userdb sql { args = /etc/dovecot/dovecot-mysql.conf } socket listen { client { path = /var/spool/postfix/private/auth mode = 0660 user = postfix group = postfix } master { path = /var/run/dovecot/auth-master mode = 0660 user = vmail group = vmail } } }Уже знакомый скрипт /etc/dovecot/pop-before-smtp.sh для аутентификации POP before SMTP:
#!/bin/sh mysql -uuser -ppassword -h127.0.0.1 mail <<END UPDATE users SET lasttime = NOW(), lastip='$IP' WHERE login = '$USER'; END exec /usr/lib/dovecot/pop3 "$@"Файл настроек для хранения счётчиков квот в БД MySQL /etc/dovecot/dovecot-dict-mysq.conf:
connect = host=127.0.0.1 dbname=mail user=user password=password map { pattern = priv/quota/storage table = users username_field = login value_field = bytes } map { pattern = priv/quota/messages table = users username_field = login value_field = messages }Файл настроек для проверки учётных данных пользователя и его квот по таблице в БД MySQL /etc/dovecot/dovecot-mysql.conf:
driver = mysql connect = host=127.0.0.1 dbname=mail user=user password=password default_pass_scheme = CRYPT password_query = SELECT password \ FROM users \ WHERE login = '%u' user_query = SELECT CONCAT(SUBSTRING_INDEX(login, '@', -1), '/', SUBSTRING_INDEX(login, '@', 1), '/'), \ 999 AS uid, \ 999 AS gid, \ CONCAT('*:bytes=', max_bytes, ':messages=', max_messages) AS quota_rule \ FROM users \ WHERE login = '%u'В настройки postfix добавлен LDA delivery из Dovecot, в файл /etc/postfix/master.cf добавлены две строчки:
dovecot unix - n n - - pipe flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient}Столбцы со счётчиками и со значениями квот для пользователей добавлены с помощью четырёх SQL-запросов:
ALTER TABLE users ADD COLUMN bytes bigint default 0; ALTER TABLE users ADD COLUMN messages integer default 0; ALTER TABLE users ADD COLUMN max_bytes bigint default 1073741824; ALTER TABLE users ADD COLUMN max_messages bigint default 1000;Значения квот по умолчанию можете поменять на свои. Я поставил ограничения в 1 гигабайт на общий объём ящика и не более 1000 писем в одном почтовом ящике.
В таком виде Dovecot не будет принимать от Postfix письма для адресатов, превысивших квоту. Но такие письма будут просто попадать в очередь отложенных писем Postfix. Нужно же, чтобы письмо не занимало дисковое пространство ни в почтовом ящике получателя, ни в очереди отложенных писем, а отклонялось сразу же с соответствующим сообщением отправителю о том, что адресат превысил квоту.
Для этого нужно настроить проверку квот при приёме почты самим Postfix'ом. Для этого воспользуемся правилом check_recipient_access mysql:/etc/postfix/sql/quotas.cf, которое нужно поместить в том числе до правил permit_mynetworks и permit_sasl_authenticated. Если поместить его после этих двух проверок, то квоты получателя просто не будут проверяться, если отправитель аутентифицировался на почтовом сервере или он отправляет почту из доверенной сети.
Файл /etc/postfix/sql/quotas.cf для проверки квоты получателя:
user = user password = password dbname = mail hosts = 127.0.0.1 query = SELECT '452 Mailbox is over quota' FROM users WHERE login = '%s' AND ((bytes >= max_bytes AND max_bytes > 0) OR (messages >= max_messages AND max_messages > 0))О расширенных статусах REJECT я прочитал в man 5 access, а подходящий код статуса подобрал в RFC2821 на этой странице: http://tools.ietf.org/html/rfc2821.
В случае если квота по объёму или по количеству сообщений равна нулю, то этот SQL-запрос такую квоту не проверяет. Таким образом значения 0 в полях max_bytes или max_messages означают, что ограничение по этому параметру не действует.
При попытке отправить письмо на ящик, превысивший квоту, Outlook Express сообщает следующее:
Не удается отправить сообщение, поскольку сервер отказался принять адрес одного из получателей. В письме был указан адрес: 'user@domain.tld'. Тема 'test1', Учетная запись: 'mail', Сервер: 'domain.tld', Протокол: SMTP, Ответ сервера: '452 4.7.1 <user@domain.tld>: Recipient address rejected: Mailbox is over quota', Порт: 25, Защита (SSL): Нет, Ошибка сервера: 452, Код ошибки: 0x800CCC79
5 комментариев:
А проверялось что письмо возвращается на тот же mail.ru? Просто с 452 кодом ни мэйл.ру, ни гмыло, ни любой другой в моем случае не захотели генерировать анделайверед сообщение пока не поставил 550 или 551 код.
Может быть сгенерируют, но попозже, когда письмо проваляется в очереди недоставленным с недельку? Потому что 452 код - это код временной ошибки.
Я считаю, что правильно использовать именно его, потому что в другой раз то же самое письмо может дойти, если адресат почистит свой ящик и квота перестанет действовать.
И потом, этот код описан в RFC именно для этого случая.
А как можно настроить квоту не на каждый ящик по отдельности, а на домен?
Можно переделать SQL-запрос так, чтобы он суммировал место, занятое письмами во всех почтовых ящиков домена проверяемого ящика и сравнивал это место с лимитом из другой таблицы.
Хотя мне квоты для домена кажутся несколько глупыми. Представьте, что есть ящик, на который приходит масса спама, но владелец которого им уже не пользуется. В итоге его ящик будет использовать 99% квоты, а остальные, активные пользователи, будут ютиться на 1% квоты, удаляя даже те письма, которые они хотели бы оставить.
Благодаря тому, что действуют квоты - ящик не переполнится, так как не примет писем сверх нормы. В итоге bytes всегда меньше max_bytes и до ошибки 452 дело не доходит. Воркераунды находили?
Отправить комментарий