Это моя любимая история из всего почтового переезда, потому что разгадка лежала там, где я не искал, — и потому что система молчала до последнего.
Жалоба звучала так: у пользователей в 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\<пользователь>. Это экономит порядка шестидесяти пяти символов и само по себе снимает проблему для всей существующей структуры.
По шагам:
- Полностью закрыть Thunderbird — не свернуть, а закрыть.
- Скопировать профиль в
C:\TB\user\. - В
%APPDATA%\Thunderbird\profiles.iniуказать новый путь:IsRelative=0 Path=C:\TB\user - Старый профиль не удалять, а переименовать — чтобы был откат.
- На проблемных папках: Свойства → Восстановить папку.
Четвёртый пункт стоит отдельного внимания. Профиль 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 ищет по содержимому мгновенно, и номер заявки находится независимо от того, в какой папке лежит письмо. Структура при этом становится плоской, а поиск — быстрее ручной навигации по пяти уровням.
Оговорюсь: это предложение, а не сделанный факт. Менять чужой устоявшийся порядок работы — решение не техническое, и принимать его должны те, кто в этом порядке работает.
Что я из этого забрал
Правила именования папок — это не эстетика, а эксплуатация.
Пока папки живут в веб-интерфейсе, длина имени не значит ничего. Как только та же структура зеркалится на файловую систему клиента, каждое лишнее слово в имени становится символами в пути, а путь — ограниченным ресурсом. Красивое подробное имя папки на пятом уровне вложенности однажды становится причиной, по которой у человека молча не работает почта.
И второе, более общее. Когда и клиент, и сервер говорят «у меня всё хорошо», причина находится не внутри них, а в стыке. Здесь стыком оказалась файловая система, о которой в задаче про почту не думаешь вовсе.