Переполненный ящик 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 мне кажутся разумным компромиссом: достаточно, чтобы пережить чужое обслуживание, и достаточно быстро, чтобы узнать о проблеме.

У нас в журнале ошибка не про квоту, а про нехватку хранилища. Это то же самое?

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

Нужна помощь с проектом?

Специалисты АйТи Фреш помогут с архитектурой, DevOps, безопасностью и разработкой — 15+ лет опыта

📞 Связаться с нами
#Zimbra#квоты#Postfix#очередь#почта
Комментарии 0

Оставить комментарий

загрузка...

Подпишитесь на рассылку ITfresh

Раз в неделю — практические гайды для руководителя IT и сисадмина: безопасность, 1С, миграции, резервные копии, лайфхаки из реальных проектов.

Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.