Бухгалтерская фирма в Подольске, 12 рабочих мест. В июне 2022 их главбух удалила переписку по контракту, очистила корзину и через девять дней узнала, что письмо нужно в суд. Разворачивать весь сервер ради одного письма никто не собирался. Показываю три уровня возврата — от бесплатного за пять минут до архивного за сорок — и грабли с флагом, на которых я потерял час.
Вернуть одно удалённое письмо: dumpster, zmmailbox и флаг -A
«Я удалила и очистила корзину, это вообще можно вернуть?»
Звонок такого содержания я получаю несколько раз в год, и содержание всегда одинаковое. Человек разбирал почту, удалил ветку переписки, очистил корзину — и через неделю выяснилось, что именно эта ветка нужна. К налоговой, в суд, к контрагенту, в спор о поставке.
Дальше начинается разговор, который меня всегда огорчает. Администратор говорит: «есть ночной бэкап, надо восстанавливать сервер». Бухгалтерия слышит слово «восстанавливать» и представляет остановку работы на полдня ради одного письма. И часто просто машет рукой — мол, обойдёмся.
Восстанавливать сервер не нужно. В Zimbra есть три уровня возврата, и на полный разворот вы выходите только тогда, когда первые два не сработали. Первый уровень занимает пять минут и не требует ни одного бэкапа.
Ещё одна вещь, которая мешает людям вернуть письмо вовремя. Про первый уровень возврата почти никто не знает, потому что он спрятан в контекстном меню веб-почты и нигде не подписан словом «восстановление». Человек видит пустую корзину и делает вывод, что всё кончено. Хотя письмо лежит в двух кликах.
Про эти три уровня и про то, где я на них спотыкался, — дальше.
Июнь 2022, Подольск: 12 мест, ящик на 31 ГБ
Клиент — небольшая бухгалтерская фирма на Подольском проспекте, ведёт учёт примерно у сорока юрлиц. 12 рабочих мест, 14 ящиков, Zimbra 8.8.15 Open Source на своей виртуалке. Почта у них — рабочий инструмент номер один: акты, счета, требования, переписка с инспекциями. Всё живёт в письмах. Файловой шары у них нет вообще.
Ящик главбуха на тот момент — 31 ГБ, около 96 тысяч писем, 227 папок, разложенных по клиентам. Она сама раз в квартал разбирает почту и чистит лишнее — привычка хорошая, но именно она и создала проблему.
История простая. 6 июня она удалила ветку переписки с подрядчиком по договору на сопровождение, ветка ушла в корзину. 7 июня почистила корзину. 15 июня клиент подал претензию, и понадобилось письмо от 12 марта, где подрядчик письменно согласовал перенос срока.
Позвонили мне 15-го в 16:40. Само письмо вернулось на следующее утро, с 09:30 до 10:04, — тридцать четыре минуты. А между звонком и этими тридцатью четырьмя минутами уместился вечер 15-го, который я целиком потратил на совершенно другую версию. С неё и начну, чтобы не делать вид, что всё прошло гладко.
Ложный след: час сорок в правилах фильтрации
Сначала я не поверил, что письмо удалено. У главбуха было 27 правил фильтрации, часть — с раскладкой по папкам клиентов, и я решил, что письмо просто уехало не туда. Версия удобная: ничего восстанавливать не надо, достаточно найти.
Я честно прогнал поиск по всему ящику, включая архивные папки. Даты в поиске Zimbra пишутся в американском порядке — месяц, день, год, — и первый прогон я сделал по январю вместо марта, просто набрав дату привычно. Правильно так:
su - zimbra
zmmailbox -z -m glavbuh@example.ru search -l 50 \
'from:podryadchik.ru after:03/01/2022 before:04/01/2022'
zmmailbox -z -m glavbuh@example.ru getAllFilterRulesНоль результатов. Все 27 правил проверил построчно — ни одно не отправляло письма этого отправителя в сторону. 1 час 40 минут ушло на то, чтобы убедиться: письма в ящике действительно нет.
Мораль для меня самого простая. Факт удаления проверяется первым делом, а не последним. Всё это время ответ лежал в /opt/zimbra/log/mailbox.log за 7 июня — одна строка с операцией очистки папки. 5 минут работы вместо ста.
grep -i 'glavbuh@example.ru' /opt/zimbra/log/mailbox.log.2022-06-07 | \
grep -i 'emptyfolder\|itemaction.*op=delete' | headУровень 1: dumpster, и час, который я потерял на флаге
Dumpster — это то, куда попадают письма после очистки корзины. Не «безвозвратно удалены», а перемещены в служебную область, невидимую для обычного просмотра папок. Живут они там ограниченное время, заданное в классе обслуживания. Именно этот механизм и спас нас в Подольске.
Проверяем, включён ли он вообще и сколько хранит:
su - zimbra
zmprov gc default zimbraDumpsterEnabled zimbraMailDumpsterLifetime
zmprov ga glavbuh@example.ru zimbraDumpsterEnabledУ клиента zimbraDumpsterEnabled стоял в TRUE, а zimbraMailDumpsterLifetime — 30 дней. Само по себе это удача: по умолчанию механизм выключен, и включить его кто-то должен был руками. Письмо удалили 7 июня, обратились 15-го. Восемь суток из тридцати. Успели с запасом. Если бы срок стоял 7 дней — а такое я вижу часто, — мы бы опоздали на сутки.
Пользователю возврат доступен прямо из веб-почты: правой кнопкой на корзине, «Восстановить удалённые». Там открывается окно поиска по dumpster, письмо перетаскивается обратно в папку. Главбух сделала это сама за две минуты, я только подсказал, куда нажать.
А теперь мои грабли. Когда я потом писал скрипт, который раз в неделю чистит dumpster по всем ящикам старше срока, он падал на каждом аккаунте:
ERROR: service.PERM_DENIED (permission denied: cannot access dumpster)Я перебирал права, класс обслуживания, административные роли. Час. Ошибка PERM_DENIED выглядит как проблема с ролями, хотя дело совсем в другом: zmmailbox требует флаг -A, иначе доступа к служебной области ящика у команды нет — даже под административной учёткой, даже с ключом -z.
# без -A — PERM_DENIED
zmmailbox -z -m glavbuh@example.ru -A emptyDumpsterОдин символ. Час.
Уровень 2: развернуть архив нужной даты во временный ящик
Если срок хранения в dumpster вышел или он вообще выключен — идём в архив. Здесь важно не делать распространённую ошибку: не восстанавливать боевой ящик поверх самого себя.
Правильный порядок — завести временный ящик и развернуть архив нужной даты в него. Боевой при этом продолжает работать, человек читает почту и ничего не замечает.
su - zimbra
# 1. временный ящик
zmprov ca restore.tmp@example.ru 'Vremenn1y-Parol!' \
displayName 'RESTORE TEMP' zimbraMailQuota 0
# 2. разворачиваем архив нужной даты
/opt/zimbra/bin/zmmailbox -z -m restore.tmp@example.ru -t 0 \
postRestURL "//?fmt=tgz&resolve=reset" /backup/2022-06-05/glavbuh.tgz
# 3. нашли письмо — забираем его
# и удаляем временный ящик
zmprov da restore.tmp@example.ruДальше письмо переносится в боевой ящик обычным способом. Главбух заходит во временный ящик через веб-почту и перетаскивает нужное к себе. Две минуты. Боевой ящик за всё это время не тронут ни разу — в нём как было 96 тысяч писем, так и осталось.
Если архива нужной даты нет в готовом виде, ящик выгружается с любого сервера, где он ещё цел, той же парой команд:
/opt/zimbra/bin/zmmailbox -z -m glavbuh@example.ru -t 0 \
getRestURL "//?fmt=tgz" > /backup/glavbuh.tgzКлюч -t 0 — бесконечный таймаут. На ящике в 31 ГБ без него выгрузка обрывается на середине, и это самая частая причина жалобы «у меня не работает getRestURL». Архив кладите не в /tmp, а на том с запасом: 31 ГБ почты дали примерно 22 ГБ архива. Я видел, как забитый /tmp ронял операцию на 80 процентах.
Почему resolve=reset нельзя направлять в боевой ящик
Здесь я хочу задержаться, потому что это место, где самостоятельная попытка превращается из «не получилось» в «стало хуже».
Режим resolve=reset означает буквально следующее: целевой ящик полностью очищается перед импортом. Не дополняется. Не сливается. Очищается.
Сценарий катастрофы выглядит так. Нужно вернуть письмо от 12 марта. Есть архив ящика от 5 июня. Человек находит в сети команду импорта — почти всегда именно с resolve=reset, потому что так написано в большинстве инструкций, — и запускает её прямо в боевой ящик. Письмо от марта возвращается. А всё, что пришло с 5 по 15 июня, исчезает: 10 суток переписки, включая ту самую претензию, ради которой всё затевалось.
Правило простое. resolve=reset направляется только во временный ящик, созданный десять минут назад и пустой. Есть режимы разрешения конфликтов, которые не очищают цель, но полагаться на них в спешке я не советую: разница между ними — один параметр в строке, а последствия ошибки необратимы.
Второй момент — время. Импорт ящика на 31 ГБ шёл у нас 58 минут. Прерывать его нельзя: обрыв на середине способен повредить базу ящика. Поэтому запуск строго в отсоединяемой сессии — screen или tmux, по вкусу. Я на этом обжигался в 2020-м, на другом клиенте и на другой задаче.
screen -S restore
/opt/zimbra/bin/zmmailbox -z -m restore.tmp@example.ru -t 0 \
postRestURL "//?fmt=tgz&resolve=reset" /backup/2022-06-05/glavbuh.tgz
# Ctrl+A, DПроверьте у себя за 2 минуты
Эти команды покажут, есть ли у вас вообще первый уровень возврата. Ничего не меняют.
su - zimbra -c 'zmprov gc default zimbraDumpsterEnabled zimbraMailDumpsterLifetime'
su - zimbra -c 'for c in $(zmprov gac); do zmprov gc $c zimbraDumpsterEnabled; done'
ls -1 /путь/к/бэкапу/ | tail -5| Что получилось | Что это значит |
|---|---|
zimbraDumpsterEnabled: FALSE | Первого уровня у вас нет. Любое удалённое письмо сразу требует работы с архивом — это часы вместо минут. Включается одной командой. |
| Срок хранения меньше 30 дней | Типичная просьба приходит на 7–14 день после удаления. При сроке в неделю вы регулярно будете опаздывать. |
| Классов обслуживания несколько, значение разное | Часть сотрудников защищена, часть нет. Разбирается за пять минут, но обычно про это никто не знает. |
| Поящичных архивов в бэкапе нет, только образ машины | Второй уровень тоже недоступен. Ради одного письма придётся поднимать сервер целиком — это полдня. |
| Свежий архив ящика есть, дате больше месяца | Вы вернёте письмо, но потеряете границу: всё, что нужно из последнего месяца, придётся искать в другом месте. |
Включение и срок — 2 команды, применяются к классу обслуживания и подхватываются без перезапуска служб:
zmprov mc default zimbraDumpsterEnabled TRUE
zmprov mc default zimbraMailDumpsterLifetime 30dСколько это заняло и во что обошлось бы иначе
Возврат письма в Подольске занял 34 минуты: с 09:30 до 10:04 утра 16 июня. Из них 25 минут — проверка настроек и объяснение главбуху, куда нажимать. Плюс час сорок накануне вечером, потраченные мной на ложную версию, — их я в счёт не поставил, это моя цена, а не клиента. Счёт: одна консультация.
Альтернатива, которую предлагал их прежний подрядчик: развернуть вчерашний образ виртуалки на запасном хосте, поднять сервер, найти письмо, выгрузить. Оценка — от четырёх до шести часов работы плюс место под копию 31-гигабайтного ящика и всей машины. По их прайсу это выходило около 24 тысяч рублей и один занятый инженер на день.
Разница — не в квалификации. Разница в том, что первый уровень возврата у клиента был включён все эти годы, а прежний подрядчик про него просто не знал. По умолчанию dumpster в Zimbra выключен — значит, кто-то из прежних админов его когда-то включил и никому об этом не сказал, включая самого себя год спустя. Мы воспользовались настройкой, о существовании которой не знал ни один человек в этой истории.
Дальше цифры сложились сами. За следующие три года у этой фирмы было одиннадцать обращений «верните письмо». Девять закрылись через dumpster за 10–20 минут. Два потребовали разворота архива во временный ящик — по 40 и 55 минут. Полного восстановления сервера не понадобилось ни разу.
Одиннадцать обращений по четыре часа — это 44 часа, которых не случилось.
Что я теперь ставлю всем на входе
Когда я беру на обслуживание чужую Zimbra, три вещи по этой теме делаются в первый же день, до всякого аудита.
- Dumpster включён во всех классах обслуживания, срок — 30 дней. Дисковая цена есть, но умеренная: удалённые письма продолжают занимать место в
/opt/zimbra/storeещё месяц вместо того, чтобы освободить его сразу. На ящиках с большим оборотом это видно, на обычных — теряется в погрешности. - Поящичные tgz по расписанию для трёх-четырёх самых критичных ящиков: бухгалтерия, руководитель, общий ящик компании. Остальные — раз в неделю. У фирмы в Подольске это 4 ящика ежедневно и 10 еженедельно, суммарно 61 ГБ архивов на диске.
- Короткая инструкция для пользователей на полстраницы: «Восстановить удалённые» в веб-почте, что делать, если письма там нет, кому писать. Без неё люди не знают, что первый уровень вообще существует.
Последний пункт даёт больше всего. У бухгалтерской фирмы после появления инструкции 9 обращений из 11 закрылись без меня — люди вернули письма сами, за 10–20 минут каждое.
Если хотите проверить своё положение — не нужно ничего заказывать. Пришлите мне вывод первых двух команд из блока проверки и одной строкой напишите, есть ли у вас архивы отдельных ящиков или только образ машины. За день отвечу, какие уровни возврата у вас реально работают, а какие только предполагаются.
Частые вопросы
Сколько времени письмо лежит в dumpster и можно ли этот срок увеличить?
Срок задаётся в классе обслуживания и меняется одной командой. У большинства серверов, которые я вижу, стоит значение по умолчанию, а иногда механизм вообще выключен. Я ставлю 30 дней. Типичная просьба «верните письмо» приходит на 7–14 день после удаления, и месячного окна хватает почти всегда. Увеличивать сильно дальше смысла мало — письма всё это время занимают место в store, и на больших ящиках разница становится заметной. Если у вас есть требования по срокам хранения переписки, лучше решать их отдельным архивным механизмом, а не растягиванием dumpster до года.
Пользователь может сам вернуть письмо, без администратора?
Может, если dumpster включён. В веб-почте нужно щёлкнуть правой кнопкой по корзине и выбрать восстановление удалённых — откроется окно поиска, где письмо ищется по отправителю, теме или дате, а потом перетаскивается обратно в нужную папку. Занимает 2 минуты. Проблема исключительно в осведомлённости: об этой возможности не знает почти никто, потому что она спрятана в контекстном меню. Я раздаю клиентам инструкцию на полстраницы, и после этого половина обращений ко мне просто исчезает — люди справляются сами.
Почему скрипт по dumpster падает с PERM_DENIED, если я работаю под администратором?
Потому что административного входа недостаточно. Ключа -z мало. Нужен ещё флаг -A у самой команды zmmailbox. Без него доступ к служебной области ящика не открывается, и вы получаете отказ по правам, который выглядит как проблема с ролями или классом обслуживания. Я потратил на это 60 минут: перебирал права, смотрел роли, менял класс обслуживания, читал /opt/zimbra/log/mailbox.log построчно. Всё оказалось в одном символе. Если пишете свои скрипты обслуживания — проверьте этот флаг первым делом, он экономит вечер.
Можно ли восстановить письмо в боевой ящик напрямую из архива?
Технически можно, практически — не надо. Стандартный режим импорта полностью очищает целевой ящик перед записью, и если направить такую команду в живой ящик, вы вернёте старое письмо ценой всей переписки, накопившейся после даты архива. Правильный порядок другой: создаётся временный ящик, архив разворачивается в него, нужное письмо переносится в боевой обычным перетаскиванием, временный ящик удаляется. Занимает на 10 минут дольше. И полностью снимает риск. У нас через этот порядок прошли два обращения из одиннадцати, оба без единой потери.
Что делать, если dumpster был выключен и архива нужной даты тоже нет?
Остаются варианты, но они дороже и менее надёжны. Первое — почтовые клиенты: если человек работал через Outlook или мобильное приложение, локальная копия письма могла сохраниться на устройстве, даже когда на сервере её уже нет. Второе — вторая сторона переписки: письмо есть у отправителя или получателя, и запросить копию с корректной шапкой иногда быстрее всего. Третье — журналы сервера. Тело письма в /var/log/maillog не хранится, но факт и время доставки там есть, и в спорах это тоже имеет вес — при условии, что ротация не съела нужную дату. Полного восстановления содержимого это не заменит, поэтому первый уровень стоит включить заранее, а не после случая.
Оставить комментарий