У клиента-гостиницы в Балашихе директор неделю не получал почту и узнал об этом от контрагента по телефону. Ящик был переполнен, письма честно лежали в очереди и ровно через пять суток начали улетать отправителям с отлупом. Разбираю механику отсрочки, объясняю, когда выгоднее отбивать сразу, и почему поднятая всем квота — это та же авария через полгода.
Переполненный ящик Zimbra копит deferred пять суток, потом bounce
«Мне неделю никто не писал»
Самая дорогая почтовая авария — та, которую никто не замечает. Ничего не падает. Ящик открывается, письма приходят, только их мало. Человек думает, что затишье. Контрагент думает, что письмо дошло.
А потом звонок: «Я вам неделю назад договор отправил, вы почему молчите?»
Если у вас на почтовом сервере стоят квоты — а они стоят почти везде, потому что включены по умолчанию, — вы в зоне риска ровно так же. Механика простая и на редкость коварная: пока ящик переполнен, ваш сервер вежливо просит отправителя подождать. Отправитель ждёт. Пять суток, то есть 120 часов. Потом сдаётся и возвращает письмо.
Пользователь при этом не видит ничего. Ни предупреждения, ни ошибки, ни пустого места в списке писем. Отправитель тоже долго ничего не видит — отлуп придёт только на 120-м часу, когда договариваться уже поздно. Всё это время письма лежат на диске сервера, в каталоге очереди Postfix.
Окно, в которое можно всё спасти, — эти самые пять суток. Дальше письма не восстановить ничем.
Гостиница в Балашихе, ноябрь 2019
Загородная гостиница на 41 рабочее место: администраторы, отдел бронирования, бухгалтерия, руководство. Корпоративные заезды и групповые брони идут почтой — агент присылает заявку, отдел подтверждает. Zimbra 8.6 Open Source, поставлена в 2016-м и с тех пор ни разу не обновлявшаяся: сервер обслуживался по остаточному принципу.
12 ноября 2019 года мне позвонил директор и сказал ровно ту фразу из заголовка. Разговор занял три минуты, я приехал через час.
Первое, что я сделал, — посмотрел не в ящик, а в журнал доставки. Это правило, которое я вывел для себя после нескольких таких историй: ящик показывает, что дошло, а журнал показывает, что было послано.
$ grep -c "quota exceeded" /var/log/maillog
4803
$ grep "quota exceeded" /var/log/maillog | tail -2
Nov 12 09:14:02 mail postfix/lmtp[28114]: 4A1E0C0A2F:
to=<direktor@hotel.example.ru>, relay=mail.example.ru[127.0.0.1]:7025,
delay=418211, delays=418210/0.02/0.01/0.3, dsn=4.2.2,
status=deferred (host mail.example.ru said: 452 4.2.2 Over quota)
Обратите внимание на delay: 418 211 секунд. Это четверо суток и двадцать часов, которые письмо провело в очереди, пытаясь попасть в ящик, — то есть принято оно было ещё 7 ноября в начале второго дня. Строк с отказом по квоте в журнале за неделю набралось 4803 штуки: каждое письмо стучится примерно раз в час, и они складываются. Квота ящика — 2 ГБ, и занята она под ноль: 2 147 290 112 байт из 2 147 483 648, то есть 99,99 % и 189 килобайт до потолка.
$ mailq | grep -c direktor@hotel.example.ru
68
Шестьдесят восемь писем ждали своей очереди. Ещё девять к тому моменту уже ушли обратно отправителям.
Ложная версия: «письма просто не отправляли»
Я обязан признаться, что перед журналом у меня была другая мысль, и я потратил на неё двадцать минут. Директор человек занятой, версия «контрагент забыл отправить и теперь оправдывается» звучала правдоподобно — такое бывает чаще, чем аварии.
Я попросил у контрагента идентификатор сообщения и время отправки, чтобы поймать письмо в /var/log/maillog и показать, что его не было. Письмо нашлось: принято 7 ноября в 13:03, дальше 103 попытки доставки по LMTP на порт 7025 и 103 отказа подряд — то самое письмо с delay=418211, которое я показывал выше.
Вторая версия была технически грамотнее и тоже неверной: фильтр в самом ящике. Кто-то настроил правило, письма от домена уезжают в подпапку, человек про неё не знает. Я такое разбирал трижды. Проверил:
$ zmmailbox -z -m direktor@hotel.example.ru getFilterRules
(пусто)
Ни одного правила. Папка «Спам» — семь писем, все действительно спам. Никаких скрытых подпапок.
Обе версии стоили мне получаса, и я их описываю намеренно: они естественные, их проверяет каждый, и они уводят в сторону. Прямой путь короче — идти в журнал доставки и считать строки про квоту.
Пять суток: механика отсрочки
Разберу по шагам, потому что здесь всё держится на одном различии.
Почтовые серверы разговаривают друг с другом кодами. Коды вида 4.x.x, а в разговоре по SMTP это 452, означают «сейчас не могу, попробуй позже» — временная ошибка, и отправитель обязан повторить попытку. Коды вида 5.x.x, в нашем случае 552, означают «не могу и не смогу» — постоянный отказ, письмо немедленно возвращается автору.
Переполненный ящик по умолчанию отвечает 452 — временной ошибкой. Письмо принимается на сервер, кладётся в очередь и начинает циклы повторных попыток с нарастающими паузами: их границы задают параметры postfix_minimal_backoff_time и postfix_maximal_backoff_time. Сколько всё это длится, определяет postfix_maximal_queue_lifetime, по умолчанию 5 суток. Всё это время письмо у вас. Оно физически лежит на диске, его можно посмотреть и можно доставить.
Через пять суток очередь сдаётся и отправляет письмо обратно с отчётом о невозможности доставки.
| Момент | Что происходит | Что видит пользователь |
|---|---|---|
| Час 0 | Письмо принято, ящик отказал временно, письмо в очереди | Ничего |
| Часы 1–24 | Повторы с растущей паузой, от нескольких минут до часа | Ничего |
| Сутки 2–4 | Повторы примерно раз в час, письма копятся | Ничего |
| Сутки 5 | Отправителю уходит отлуп, письмо удаляется из очереди | Ничего |
| После | Восстановить нечем | Звонок от контрагента |
Именно поэтому проблема выглядит как затишье, а не как поломка. Всё работает штатно. Каждый участник ведёт себя ровно так, как ему предписано.
Проверьте у себя за две минуты
Одна команда показывает состояние всех ящиков сразу, вторая — есть ли уже пострадавшие.
su - zimbra
zmprov gqu $(zmhostname) | awk '{if ($2>0 && $3/$2 > 0.85) print $1, int($3/$2*100)"%"}'
grep -c "quota exceeded" /var/log/maillog
mailq | grep -c "^[A-F0-9]"
Первая строка выводит ящики, занятые больше чем на 85%. Отчёт по квотам снимается за 3–8 секунд даже на 600 ящиках, журнал доставки лежит в /var/log/maillog. Трактовка:
| Что увидели | Что это значит | Когда действовать |
|---|---|---|
| Список пуст, в журнале ноль совпадений | Запас есть у всех | Ничего не трогать |
| Один-два ящика в диапазоне 85–95% | Упрутся в потолок в течение месяца-двух | Запланировать чистку |
| Есть ящики со 100%, в журнале ноль | Ящик полон, но пишут туда редко — время ещё есть | На этой неделе |
| В журнале есть строки про квоту | Письма уже лежат в очереди, отсчёт пяти суток идёт | Сегодня |
| Очередь больше сотни писем | Либо квота, либо диск — смотрите текст ошибки | Немедленно |
Разница между двумя последними строками важна. Переполненный ящик даёт сообщение про превышение квоты. Переполненный диск на сервере даёт другое — про нехватку системного хранилища, и лечится оно совсем иначе, добавлением тома. Не перепутайте: симптом для пользователя одинаковый, а работы разные.
Спасти то, что ещё в очереди
Порядок действий, когда счётчик уже тикает. Сначала место, потом доставка — иначе повторная попытка снова упрётся в ту же стену.
# 1. смотрим, чей ящик и насколько полон
zmprov gqu $(zmhostname) | grep direktor
direktor@hotel.example.ru 2147483648 2147290112
# 2. поднимаем квоту с запасом, временно
zmprov ma direktor@hotel.example.ru zimbraMailQuota 8589934592
# 3. толкаем очередь вручную, не дожидаясь следующего цикла
postqueue -f
# 4. проверяем, что ушло
mailq | grep -c direktor@hotel.example.ru
Все 68 писем доехали за 2 минуты 20 секунд. Девять, ушедших ранее отлупами, я вернуть не смог — их пришлось просить отправить заново, и один из отправителей к тому моменту уже разместил группу в другой гостинице.
Здесь моя ошибка того дня. Я поднял квоту и сказал директору: готово, проверяйте. Он проверил — пусто. Я забыл, что очередь работает своим расписанием: интервал выборки задаёт postfix_queue_run_delay, а пауза между попытками к пятым суткам растягивается до 60 минут, и письма никуда не торопятся. Выглядело так, будто я ничего не сделал. Команду принудительного проталкивания очереди я выполнил через пять минут, но осадок остался, и с тех пор я делаю это до того, как отчитаться.
Ещё одна полезная деталь: если непонятно, что за письма стоят в очереди, их можно прочитать не выходя из консоли.
$ postcat -q 4A1E0C0A2F | head -20
452 или 552: выбираем, как отказывать
После разбора мы обсуждали более принципиальный вопрос: правильно ли вообще держать письма пять суток.
Поведение переключается одним параметром. По умолчанию он в положении FALSE: переполненный ящик отвечает 452, и письмо ждёт. В положении TRUE тот же ящик отвечает 552, и отправитель получает отлуп через 5–10 секунд. Параметр живёт в Zimbra с версии 5.0.6.
$ zmprov gcf zimbraLmtpPermanentFailureWhenOverQuota
zimbraLmtpPermanentFailureWhenOverQuota: FALSE
$ zmprov mcf zimbraLmtpPermanentFailureWhenOverQuota TRUE
Аргументы за немедленный отказ: отправитель узнаёт о проблеме через минуту, а не через пять дней, и может позвонить. Ваш сотрудник узнаёт от него в тот же день. Очередь не пухнет. Никаких иллюзий, что письмо где-то есть.
Аргументы против: письмо потеряно окончательно, и если человек просто не успел почистить ящик в отпуске, вы отрезали ему входящую почту без единого шанса на автоматическое восстановление.
Я выбираю по типу организации. Там, где почта — это входящий поток заявок от внешних людей, немедленный отказ обычно выгоднее: молчание дороже отказа. Там, где переписка внутренняя и неспешная, оставляю отсрочку. В гостинице мы оставили FALSE, но сократили postfix_maximal_queue_lifetime с 5 суток до 2, чтобы отлуп приходил на 48-м часу, а не на 120-м:
zmlocalconfig -e postfix_maximal_queue_lifetime=2d
zmmtaconfig
Правки такого рода делаются именно через локальную конфигурацию, а не прямым редактированием файлов Postfix: сгенерированные конфиги перезаписываются при следующем перезапуске, и ваша правка исчезнет без следа.
«Поднимем квоту всем» — и вернёмся сюда через полгода
Первое, что предлагает почти каждый клиент: давайте дадим всем по двадцать гигабайт и забудем. Разберу, почему я так не делаю.
Арифметика. В гостинице 41 ящик. Поднять каждому с 2 ГБ до 20 ГБ — это потенциально 820 ГБ вместо 82 ГБ на томе /opt/zimbra/store. Люди не заполнят их завтра, но заполнят: почта растёт сама, никто ничего не удаляет, а вложения-сканы у бухгалтерии прибавляют по 200–400 МБ в месяц на человека.
Дальше начинается вторая история. Место кончается уже не в ящике, а на томе хранения, и симптом становится общесистемным: сервер начинает отбивать входящие для всех сразу. Это гораздо хуже, чем переполненный ящик одного директора, и чинится дольше — добавлением тома, а не одной командой.
Что я делаю вместо этого.
- Предупреждение. Настраивается заранее и стоит ноль. Человек получает письмо при заполнении на 90% и обычно чистит сам, не дожидаясь ни 452, ни звонка от контрагента.
- Разные квоты для разных ролей. Администратору стойки хватает 2 ГБ, бухгалтерии со сканами нужно 10 ГБ, директору с историей переписки — 20 ГБ. Один размер для всех — это либо тесно половине, либо расточительно всем.
- Ежемесячный взгляд на отчёт. Одна команда, тридцать секунд.
zmprov mc default zimbraQuotaWarnPercent 90
zmprov mc default zimbraQuotaWarnInterval 1d
zmprov ma buhgalter@hotel.example.ru zimbraMailQuota 10737418240
Ещё полезно объяснить людям, где у них на самом деле лежит объём. У директора 1,3 ГБ из 2 ГБ занимала папка «Отправленные»: он годами пересылал сканы договоров и ни разу туда не заглядывал. 15 минут чистки освободили 1,1 ГБ — больше, чем дало бы любое увеличение квоты.
Итог, цифры и что с этим делать вам
Хронология вышла такой. Ящик упёрся в потолок вечером 6 ноября. Пять суток очередь молча копила: к 11 ноября самые старые письма дожили до предела, и в тот день ушли первые девять отлупов. Директор позвонил 12-го — не потому что заметил сам, а потому что ему позвонил контрагент. Разобрались за 2 часа 10 минут.
| Показатель | Цифра |
|---|---|
| Писем спасено из очереди | 68 |
| Писем потеряно безвозвратно | 9 |
| Дней, когда почта директора не доходила | 6 (с 6 по 12 ноября) |
| Групповых броней, ушедших к конкурентам | 1, примерно 260 000 ₽ |
| Времени на разбор | 2 ч 10 мин, из них 30 мин на ложные версии |
| Стоимость профилактики | около 40 минут: предупреждения, роли, отчёт в регламент |
Сорок минут против шести дней невидимой аварии и одной потерянной брони. Разница не в сложности, а в том, что кто-то один раз посмотрел отчёт по квотам и настроил предупреждение.
Дальше мы завели у них ежемесячную проверку: отчёт по занятости ящиков и счётчик строк про квоту в журнале за месяц. За шесть с лишним лет повтора не было. Один раз, в 2022-м, отчёт показал бухгалтерский ящик на 96% — почистили за 20 минут, никто ничего не заметил.
Проверьте себя прямо сейчас: выполните три команды из раздела про двухминутную проверку. Если первая выдала хоть одну строку, а вторая — число больше нуля, у вас прямо сейчас идёт отсчёт, и в запасе меньше пяти суток. Пришлите мне вывод этих трёх команд — отвечу, есть ли у вас проблема, сколько писем ещё можно спасти и что менять в настройках, чтобы это не повторилось.
Частые вопросы
Пользователь удалил письма, а квота всё равно занята. Почему?
Потому что удалённое письмо не исчезает сразу: сначала оно лежит в корзине, потом попадает в область восстановления удалённого — в документации Zimbra она называется dumpster, — откуда его ещё можно достать. Обе области у большинства настроек учитываются в занятом объёме. Практический порядок: очистить корзину, дождаться или принудительно запустить очистку, и только потом смотреть отчёт. Часто именно на этом шаге выясняется, что человек честно почистил ящик, а цифра не изменилась, и он решает, что чистка не помогает.
Как понять, что письма ещё в очереди, а не потеряны?
Посмотреть очередь и посчитать в ней письма для конкретного адресата — это делается одной командой. Если письмо там есть, оно физически лежит на диске и его можно доставить в ту же минуту, как появится место. Дополнительно в /var/log/maillog у каждой попытки есть поле delay — сколько секунд письмо уже ждёт: разделите на 86 400 и получите число суток. Как только это число подбирается к пяти — счёт идёт на часы, дальше письмо уйдёт обратно и восстановить его будет нечем.
Стоит ли вообще отключить квоты, раз от них столько проблем?
Не стоит, и вот почему. Квота — это единственный механизм, который заставляет объём расти предсказуемо. Без неё вы узнаете о проблеме тогда, когда кончится место на томе хранения, а это уже авария для всех сразу, а не для одного ящика, и чинится она добавлением тома и переносом данных, а не одной командой. Правильный подход — не отключать, а сделать квоты разными по ролям и обязательно включить предупреждение при заполнении. Тогда система сама сообщает человеку, что пора прибраться.
Можно ли сократить пять суток до одних, чтобы отлупы приходили быстрее?
Можно, время жизни очереди задаётся параметром, и я иногда так делаю — в гостинице мы поставили двое суток. Только помните, что этот параметр общий: он повлияет не только на письма в переполненные ящики, но и на исходящую почту, которая не уходит из-за проблем на стороне получателя. Значение 1d — это довольно жёстко: при плановых работах у контрагента ваши письма начнут возвращаться уже на 24-м часу. 2d мне кажутся разумным компромиссом: достаточно, чтобы пережить чужое обслуживание, и достаточно быстро, чтобы узнать о проблеме.
У нас в журнале ошибка не про квоту, а про нехватку хранилища. Это то же самое?
Нет, и это принципиальная развилка. Сообщение про превышение квоты касается одного ящика и лечится квотой или чисткой. Сообщение про нехватку системного хранилища означает, что кончилось место на разделе сервера, и это бьёт по всем сразу: почта не принимается ни для кого. Второе лечится освобождением места, а если места взять неоткуда — подключением дополнительного тома хранения. Первое, что нужно сделать при таком сообщении, — посмотреть занятость разделов, а не отчёт по квотам.
Оставить комментарий