Это моя любимая история из всего почтового переезда, потому что разгадка лежала там, где я не искал, — и потому что система молчала до последнего.

Жалоба звучала так: у пользователей в Thunderbird часть папок видна в списке, но пустая. В веб-почте SOGo те же самые папки — с письмами.

Thunderbird при этом не показывал никакой ошибки. Ни предупреждения, ни значка, ни записи в логе. Просто пустая папка, как будто в ней ничего нет.

Коротко

  • Пустыми оказались только глубоко вложенные папки — это и было ключом.
  • Thunderbird зеркалит иерархию IMAP на диск каталогами .sbd; кириллица и длинные имена плюс путь профиля упираются в лимит Windows в 260 символов.
  • Файл индекса .msf не создаётся, и папка остаётся пустой молча.
  • Лечится переносом профиля в короткий путь; опционально — сокращением имён папок на сервере.
  • Попутно выяснилось, что почту использовали вместо трекера задач: папка на каждую заявку, статус и номера — прямо в имени.

Куда я смотрел сначала

Как положено, начал с клиента: где Thunderbird пишет логи и что в них.

Потом пошёл на сервер смотреть IMAP-сессии — сколько подключений, живые ли они, что делают. С сервером всё было в порядке: сессии активные, ящики отдаются. (Про то, как смотреть IMAP-сессии в Dovecot, я написал отдельно — там набор команд, который пригодился и потом.)

То есть обе очевидные стороны — клиент и сервер — отвечали «у меня всё хорошо». А папки оставались пустыми.

Перелом

Он наступил, когда я перестал спрашивать «что сломано» и посмотрел, что общего у сломанного.

Закономерность нашлась сразу: пустые — только глубоко вложенные папки. Верхние уровни работали у всех.

Структура у людей была до пяти уровней, имена кириллицей, с пробелами, запятыми, скобками и знаком «№». Примерно такой формы:

Объекты/Объект А/Корпус №12/выполнено/1 234, 5 678, 9 012 (закрыта)

Дальше всё сложилось за минуту.

Причина

Thunderbird зеркалит иерархию IMAP-папок на диск: каждая папка с вложенными становится каталогом .sbd, внутри которого лежат следующие. Пять уровней вложенности — пять каталогов в глубину.

Теперь сложите: путь профиля внутри AppData, плюс пять уровней, плюс имена кириллицей — а кириллица в кодировке занимает больше места, чем выглядит, — плюс пробелы, запятые и скобки.

Полный путь упирается в лимит Windows MAX_PATH — 260 символов.

Файл индекса .msf, в котором Thunderbird держит содержимое папки, создать не удаётся. Папка при этом остаётся в списке — её имя пришло по IMAP, — но показывать ей нечего. Ошибки не будет: с точки зрения Thunderbird индекс просто пуст.

Как я подтвердил, а не предположил

Гипотеза стала диагнозом ровно в тот момент, когда появились числа.

Подтвердил на машине пользователя — перечислил пути файлов .msf и их длину:

$p = "$env:APPDATA\Thunderbird\Profiles"
Get-ChildItem $p -Recurse -Filter *.msf -ErrorAction SilentlyContinue |
  ForEach-Object { [PSCustomObject]@{ Len = $_.FullName.Length; Path = $_.FullName } } |
  Sort-Object Len -Descending | Select-Object -First 15

Если верхние значения около 240–260 — причина подтверждена. Стало видно прямо: у работающих папок путь укладывается, у пустых — нет.

Это важный для меня момент. До замера у меня была красивая версия, которая объясняла всё, — а красивая версия, объясняющая всё, ровно так же выглядит и когда она неверна. Разница между догадкой и диагнозом — в числе, которое можно показать.

Лечение

Основное — перенести профиль Thunderbird в короткий путь, вида C:\TB\<пользователь>. Это экономит порядка шестидесяти пяти символов и само по себе снимает проблему для всей существующей структуры.

По шагам:

  1. Полностью закрыть Thunderbird — не свернуть, а закрыть.
  2. Скопировать профиль в C:\TB\user\.
  3. В %APPDATA%\Thunderbird\profiles.ini указать новый путь:
    IsRelative=0
    Path=C:\TB\user
  4. Старый профиль не удалять, а переименовать — чтобы был откат.
  5. На проблемных папках: Свойства → Восстановить папку.

Четвёртый пункт стоит отдельного внимания. Профиль Thunderbird — это вся локальная почта человека, включая то, что могло не успеть уехать на сервер. Переименование вместо удаления стоит ноль и покупает возможность вернуться.

Дополнительно — сократить имена папок на стороне сервера через doveadm mailbox rename. Перед этим — снять список папок, потому что переименование необратимо:

docker compose exec dovecot-mailcow doveadm mailbox list -u otdel@example.com \
  > /root/mailboxes-$(date +%F).txt

docker compose exec dovecot-mailcow doveadm mailbox rename -u otdel@example.com \
  'Объекты/Объект А/Корпус №12/выполнено/1 234, 5 678, 9 012 (закрыта)' \
  'Объекты/Объект А/Корпус №12/выполнено/1234-5678-9012'

Второе не обязательно, но полезно: оно лечит не симптом у одного пользователя, а причину у всех сразу, и на будущее тоже.

А теперь о том, чего в задаче не было

Пока я разбирал эту структуру, стало видно кое-что помимо длины пути.

Каждая закрытая заявка — отдельной папкой на пятом уровне вложенности. Это не почтовая структура, это использование почты вместо трекера задач. Папка создаётся под каждый объект, и её имя несёт номера заявок, этап и статус «(закрыта)» — то есть в имя папки записаны те данные, которые в трекере были бы полями.

Работает это ровно до тех пор, пока не упирается во что-нибудь. Упёрлось в MAX_PATH, но могло и в другое: спецсимволы и длинные имена бьют ещё и по бэкапам, по imapsync при следующем переезде и по любому новому почтовому клиенту, у которого свои ограничения.

Разумнее схлопнуть это в одну папку «выполнено» и искать по номеру — Dovecot ищет по содержимому мгновенно, и номер заявки находится независимо от того, в какой папке лежит письмо. Структура при этом становится плоской, а поиск — быстрее ручной навигации по пяти уровням.

Оговорюсь: это предложение, а не сделанный факт. Менять чужой устоявшийся порядок работы — решение не техническое, и принимать его должны те, кто в этом порядке работает.

Что я из этого забрал

Правила именования папок — это не эстетика, а эксплуатация.

Пока папки живут в веб-интерфейсе, длина имени не значит ничего. Как только та же структура зеркалится на файловую систему клиента, каждое лишнее слово в имени становится символами в пути, а путь — ограниченным ресурсом. Красивое подробное имя папки на пятом уровне вложенности однажды становится причиной, по которой у человека молча не работает почта.

И второе, более общее. Когда и клиент, и сервер говорят «у меня всё хорошо», причина находится не внутри них, а в стыке. Здесь стыком оказалась файловая система, о которой в задаче про почту не думаешь вовсе.