Письмо видно в папке Zimbra, а поиск его не находит: как проверить индекс конкретного ящика
Если письмо открывается в папке, а поиск его не находит — проблема не в письме и не в диске, а в отдельном поисковом индексе ящика. Прежде чем запускать переиндексацию «на всякий случай», я всегда проверяю конкретный ящик командой zmprov verifyIndex — она за минуты показывает, действительно ли индекс повреждён, или дело в чём-то другом.
Почему письмо на месте, а поиск говорит, что его нет
В Zimbra хранилище писем и поисковый индекс — это две разные системы, и синхронность между ними не гарантирована на сто процентов. Само письмо (blob) лежит в message store на диске, метаданные — в базе MariaDB/MySQL для этого mailbox-сервера, а полнотекстовый поиск работает по отдельному индексу Lucene, который Zimbra строит и обновляет по мере поступления почты. Когда пользователь открывает папку по дате, он видит содержимое базы метаданных — и письмо там есть. Когда он вводит слово в поиск, сервер обращается к индексу — а в индексе записи может не быть или она может быть повреждена. Это ключевая вещь, которую я объясняю всем, кто приходит с фразой «Zimbra потеряла письмо»: чаще всего ничего не потеряно, солгал только указатель. Разобраться в этом важно и потому, что от диагноза зависит, какую именно корпоративную почту вы получите после ремонта — рабочую или с тем же дефектом через месяц.
Проблема в том, что администратор обычно не видит расхождение сразу. Пользователь пишет «поиск не работает», и первый рефлекс — переиндексировать весь почтовый сервер. На сервере в полсотни ящиков это часы нагрузки на диск и процессор ради диагностики одного случая. Я в таких ситуациях начинаю не с лечения, а с диагноза: смотрю, действительно ли повреждён индекс именно этого ящика, или сообщение просто ещё не попало в индекс, или файл письма на диске вообще отсутствует — это три разных причины с одинаковым симптомом и разными действиями.
Первый шаг: не веб-клиент, а zmprov verifyIndex по конкретному ящику
Прежде чем что-либо чинить, нужен ID или адрес нужного ящика — беру его командой zmprov getMailboxInfo user@example.com (сокращённо gmi). Дальше сама проверка:
zmprov verifyIndex user@example.comКоманда — штатная функция zmprov, описанная в официальном Command Line Utilities Zimbra: она блокирует индекс ящика на время работы, проверяет каждый байт индекса и пишет диагностику в stdout, а при найденных проблемах возвращает статус ошибки. Именно поэтому в документации отдельно оговорено, что verifyIndex не предназначена для регулярного запуска по крону — это диагностическая операция, а не мониторинг, и на ящике с десятками тысяч писем она сама по себе создаёт нагрузку и на время держит индекс заблокированным. Ещё одна деталь из исходников zmprov: verifyIndex (короткое имя vi), reIndexMailbox и compactIndexMailbox работают только через SOAP, поэтому запускаю их обычным zmprov от пользователя zimbra, без ключа -l (прямой LDAP-режим) — иначе zmprov ответит, что команда поддерживается только в SOAP-режиме.
Если verifyIndex возвращает статус ошибки, значит индекс действительно повреждён, и дальше есть однозначный путь — переиндексация именно этого ящика. Если ошибок нет, а поиск всё равно не находит письмо, причина не в целостности индекса, и переиндексация ничего не даст — нужно смотреть в другую сторону, о чём ниже. Я держу под рукой ещё одну команду из того же семейства — zmprov getIndexStats user@example.com (gis): она не чинит и не диагностирует ошибки, но показывает общую статистику индекса ящика и полезна, чтобы сверить масштаб (сколько документов проиндексировано) до и после операции.
Три причины с одинаковым симптомом: как их различить
Первая причина — реально повреждённый индекс: verifyIndex вернул ошибку, в mailbox.log может встречаться предупреждение вида WARN ... Possibly corrupt index. Это тот случай, который я разбирал в статье про переиндексацию, которая зацикливалась — там индекс не просто был неполным, а сама попытка его пересобрать вставала на одном конкретном письме. Важно понимать: то предупреждение в логе может проскочить и не привести к заметной ошибке в интерфейсе поиска — пользователь просто не находит письмо, лог никто не читает, а сообщение в логе тем временем уже есть.
Вторая причина — индексация ещё не завершена. В штатном режиме Zimbra индексирует письмо при доставке, но если ящик только что восстанавливали, переносили на другой сервер или по нему идёт переиндексация — часть писем может быть ещё не в индексе. Официальное руководство Zimbra 10 прямо предупреждает: пока идёт переиндексация, ящик доступен, но поиск может находить не все результаты. В этом случае verifyIndex не покажет ошибку, потому что с точки зрения целостности индекс исправен — в нём просто ещё нет записи. Отличить это от повреждения помогает zmprov rim user@example.com status (см. ниже): если по ящику идёт активная переиндексация, статус это покажет.
Третья причина — реже, но обиднее всего: сам файл письма отсутствует в message store, хотя метаданные о нём в базе есть (например, после неудачного переноса тома или ручного вмешательства в файловую структуру). Переиндексация в этом случае не поможет в принципе — переиндексация читает существующие данные и строит по ним указатель заново, она не восстанавливает отсутствующие файлы писем. Если после чистой переиндексации ящика конкретное письмо по-прежнему не находится и не открывается — проверяйте целостность самого message store и наличие бэкапа, а не гоняйте индекс по кругу.
Как безопасно переиндексировать один ящик
Если verifyIndex подтвердил повреждение, переиндексирую только пострадавший ящик — не сервер целиком:
zmprov reIndexMailbox user@example.com startКоманда reIndexMailbox (сокращённо rim) поддерживает три действия — start, status, cancel. Смотреть прогресс без остановки процесса:
zmprov reIndexMailbox user@example.com statusВо время переиндексации ящик остаётся доступным — почта принимается и отправляется как обычно, страдает только поиск по этому ящику, пока процесс не закончится.
Под капотом rim дёргает SOAP-запрос ReIndexRequest с атрибутом action="start|status|cancel". У запроса есть необязательные параметры types и ids, но, согласно официальной SOAP-спецификации zm-mailbox, они взаимоисключающие — можно указать что-то одно, не оба сразу. types принимает список через запятую из фиксированного набора значений: conversation, message, contact, appointment, task, note, wiki, document. Это удобно, если проблема локализована — например, ломался только календарь, и гонять индекс по письмам не нужно. В zmprov тип передаётся после действия: zmprov rim user@example.com start types appointment (или ids и список ID через запятую). Ответ на status содержит statusCode и, если процесс идёт, блок progress с полями numSucceeded, numFailed, numRemaining — по ним я слежу, движется ли переиндексация и сколько объектов осталось.
Практическое правило: переиндексацию отдельного ящика можно запускать в рабочее время без серьёзных последствий — задета только выдача поиска по этому одному ящику. А вот массовую переиндексацию нескольких ящиков подряд я планирую на ночь, потому что процесс ощутимо нагружает дисковую подсистему сервера. Ошибочно запущенную операцию можно остановить: zmprov reIndexMailbox user@example.com cancel.
verifyIndex не нашёл ошибок, а письмо всё равно не ищется — что дальше
Первое, что проверяю — не Trash ли и не Dumpster ли это. Dumpster (хранилище окончательно удалённых писем) обычный поиск не охватывает: в SOAP это отдельный флаг inDumpster у SearchRequest. Пользователь достаёт такие письма через правый клик по «Корзине» → «Восстановить удалённые элементы» (Recover deleted items), а администратор ищет их командой zmmailbox -z -m user@example.com search --dumpster -l 50 --types message "договор". Если письмо было удалено и ушло в Dumpster, отсутствие его в обычном поиске — ожидаемое поведение, а не баг.
Второе — квота и место на диске сервера, на котором физически лежит индекс. Если раздел с индексами Zimbra переполнен или близок к этому, построение индекса для новых писем может тормозить или прерываться, хотя явной ошибки в mailbox.log для конкретного письма может не быть. Свободное место смотрю через df -h по разделу /opt/zimbra, а если store уже внушительный, полезно один раз посчитать реальный объём Zimbra по составляющим — store, index, db — а не гадать по общей цифре.
Третье — поисковый запрос пользователя. Zimbra по умолчанию ищет по определённым полям и учитывает синтаксис операторов (from:, subject:, after: и так далее); неверно набранный оператор или опечатка в адресе иногда маскируется под «поиск не работает». Прошу пользователя показать точный текст запроса, прежде чем лезть в администраторскую консоль — экономит часы.
Кейс: типография «ПринтМастер», потерянный договор, который никуда не делся
В типографии «ПринтМастер» (50 рабочих мест) бухгалтер не смогла найти по поиску письмо с подписанным договором поставки бумаги трёхнедельной давности — притом что письмо открывалось из папки «Поставщики», если листать её вручную. Заказчик уже был готов считать, что «Zimbra теряет письма», и просил массовую переиндексацию всего сервера на полсотни ящиков.
Я начал с zmprov gmi по адресу бухгалтера, затем zmprov verifyIndex — индекс её ящика вернул статус ошибки. При этом остальные ящики компании не проверялись и не трогались: смысла гонять переиндексацию по всем пятидесяти ящикам ради одного повреждённого не было. Переиндексация одного ящика командой zmprov reIndexMailbox <account> start заняла около 20 минут — ящик бухгалтера был небольшим, на несколько гигабайт. Через status я видел, как numRemaining уменьшается, а numFailed оставался нулевым — значит, все объекты действительно читались и переиндексировались, а не просто пропускались.
После завершения письмо стало находиться по поиску за секунды. Причину порчи индекса мы не установили однозначно — по логам это совпало по времени с перезапуском сервиса mailboxd на фоне планового обновления пакетов ОС, без явного краша. Что важно: обошлось без простоя остальных сорока девяти ящиков и без ночного окна — вся диагностика и починка заняли меньше часа в рабочее время, потому что мы с самого начала целились в один конкретный ящик, а не в сервер целиком.
Отдельно я объяснил бухгалтеру и директору типографии, почему массовая переиндексация была бы плохим решением именно в их случае: сервер обслуживает рабочую переписку с поставщиками бумаги и типографским оборудованием, и любая пауза в поиске по всем ящикам сразу означала бы, что менеджеры на несколько часов теряют доступ к истории переговоров с контрагентами. Точечная диагностика — это не только быстрее, это ещё и предсказуемый риск: я точно знаю, какой один ящик временно неполно ищется, а не гадаю, как поведут себя все пятьдесят одновременно.
Что делать регулярно, чтобы не искать иголку в стоге сена
Держать этот сценарий диагностики под рукой стоит на любом сервере Zimbra, даже если жалобы редки. Я советую клиентам простое правило: жалоба на «письмо есть, но не ищется» — это всегда verifyIndex конкретного ящика первым шагом, а не переиндексация сервера. Второй шаг — только если первый подтвердил порчу. Такая последовательность экономит часы дисковой нагрузки и не создаёт лишнего риска на здоровых ящиках.
Второе правило касается мониторинга: если подобные жалобы участились, стоит один раз завести регулярную проверку логов на предупреждения об индексе, а не ждать очередного тикета от бухгалтерии — я обычно встраиваю такую проверку в общий регламент ежемесячной проверки Zimbra, туда же уместно добавить наблюдение за свободным местом под индексами.
Частые вопросы
Письма пропали или просто не находятся поиском?
Почти всегда — просто не находятся. Откройте папку по дате и найдите письмо глазами: если оно открывается и читается, само письмо и его метаданные целы, страдает только поисковый индекс. Проверить это за минуту можно командой zmprov verifyIndex по конкретному ящику.
Можно ли проверить индекс одного ящика, не трогая остальной сервер?
Да, именно так и нужно делать. zmprov verifyIndex user@example.com и, при подтверждённой порче, zmprov reIndexMailbox user@example.com start работают только с указанным ящиком и не задевают остальные.
Сколько времени занимает переиндексация одного ящика?
Зависит от числа объектов в ящике и скорости дисков: небольшой ящик обычно укладывается в десятки минут, ящик на десятки гигабайт может идти часами. Прогресс показывает zmprov reIndexMailbox <account> status — поля numSucceeded, numFailed и numRemaining.
Можно ли переиндексировать не весь ящик, а только письма?
Да: zmprov rim user@example.com start types message — переиндексируются только объекты указанных типов (допустимы conversation, message, contact, appointment, task, note, wiki, document). Вместо types можно передать ids со списком ID, но не оба сразу.
verifyIndex не нашёл ошибок, но письмо всё равно не ищется — что проверять?
Проверьте, не лежит ли письмо в Dumpster (обычный поиск его не охватывает — нужен «Восстановить удалённые элементы» или zmmailbox search --dumpster), свободное место под /opt/zimbra и точный синтаксис поискового запроса пользователя.
Можно ли запускать verifyIndex регулярно по расписанию, как проверку здоровья?
Нет. Команда блокирует индекс на время выполнения и проверяет каждый байт — в официальной документации Zimbra прямо указано не запускать её по крону, а использовать только для точечной диагностики конкретной жалобы.
Источники
- Zimbra Daffodil (v10) Administrator Guide — Fixing Corrupted Mailbox Index, Managing the Dumpster — Проверено: WARN «Possibly corrupt index» в mailbox.log, доступность ящика и неполный поиск во время переиндексации, zmprov verifyIndex / reIndexMailbox start, поиск по Dumpster через zmmailbox search --dumpster и «Recover deleted items». https://zimbra.github.io/documentation/zimbra-10/adminguide.html
- Zimbra Admin Guide (GitHub, официальный репозиторий) — Command Line Utilities — Проверено (раздел Detecting Corrupted Indexes): точный синтаксис и назначение verifyIndex, getIndexStats, reIndexMailbox (rim), compactIndexMailbox (cim), getMailboxInfo (gmi); предупреждение не запускать verifyIndex по крону. https://github.com/Zimbra/adminguide/blob/develop/cmdlineutils.adoc
- Zimbra zm-mailbox — SOAP Admin API, ReIndexRequest/ReIndexResponse — Проверено: точная XML-схема запроса/ответа, action=start|status|cancel, статус-коды -3..2, взаимоисключающие ids/types, легальные значения types, поля numSucceeded/numFailed/numRemaining. https://github.com/Zimbra/zm-mailbox/blob/develop/store/docs/soap-admin.txt
- Zimbra zm-mailbox — ProvUtil.java (исходный код zmprov) — Проверено: синтаксис reIndexMailbox (rim) {name@domain|id} {start|status|cancel} [{types|ids} ...], вывод numSucceeded/numFailed/numRemaining, SOAP-only режим команд индекса. https://github.com/Zimbra/zm-mailbox/blob/develop/store/src/java/com/zimbra/cs/account/ProvUtil.java



