2025личный проект
Letter Box
Несколько ящиков в одном окне, синхронизация продолжается с закрытым приложением, непрочитанные размечает модель, запущенная дома.
- Electron
- NestJS
- BullMQ
- PostgreSQL
- Ollama
2025личный проект
Несколько ящиков в одном окне, синхронизация продолжается с закрытым приложением, непрочитанные размечает модель, запущенная дома.
Задачазачем это вообще
У меня три ящика — рабочий, личный и тот, куда уходят все регистрации. Каждое утро уходило минут двадцать на то, чтобы понять, что из этого вообще требует ответа. Разметку хотелось отдать модели, но отдавать ради тегов всю переписку в облако — плохой обмен. Значит, модель должна работать на моём железе, а почта — жить не в приложении, а на сервере, который не выключается вместе с ноутбуком.
Архитектура4 слоя, сверху вниз
Клиент
REST и Socket.IO
Сервер
задачи в очередь
Фон
соединения и инференс
Снаружи
Разборрешения и грабли
Первая версия держала IMAP прямо в Electron, и это разваливалось предсказуемо: закрыл окно — синхронизация встала, переустановил приложение — пароли приложений надо заводить заново, открыл на втором компьютере — состояние разъехалось.
Соединения, credentials и хранилище переехали в NestJS. Desktop стал тонким: он спрашивает данные по REST и слушает обновления по Socket.IO. Побочный выигрыш — веб-клиент теперь можно написать поверх того же API, ничего не трогая на сервере.
Соблазн был сделать «нажал на письмо — увидел тег». Но локальная модель отвечает секунды, а не миллисекунды, и на пачке в двести писем интерфейс превратился бы в спиннер.
Поэтому синхронизация и разметка стали задачами BullMQ. Worker разбирает их в своём темпе и присылает готовый результат событием. Письмо появляется в списке сразу, тег — когда доедет. Здесь же решается вторая проблема: очередь ограничивает параллельные вызовы модели, иначе локальный инференс просто съедает всю память.
Ollama подключается через переменные окружения. Если её нет, Letter Box остаётся обычным почтовым клиентом: пропадают только теги и часть дашборда. Такую зависимость нельзя делать обязательной — иначе приложение перестаёт запускаться у всех, кто не готов держать модель.
Провайдеры по-разному врут про IMAP. Mail.ru, Яндекс и Gmail расходятся в именах
системных папок, в поддержке CONDSTORE и в том, что считать «удалено». Логику
пришлось выносить в отдельный слой с правилами на провайдера, а не надеяться на
общий стандарт.
Второе — качество разметки на маленькой модели. Свободный ответ она даёт многословный и нестабильный, поэтому промпт пришлось сузить до выбора из закрытого списка категорий, а ответ — валидировать и отбрасывать, если он в список не попал. Это тот случай, когда точность берётся не из модели побольше, а из более узкой постановки задачи.
Экраны3 снимка

Обзор Letter Box — счётчики непрочитанных по аккаунтам, активность по дням и распределение писем по AI-тегам

Единый входящий с фильтрами по тегам и открытым письмом справа

Окно написания письма с выбором аккаунта-отправителя
Ссылкипосмотреть вживую