mirror of
https://gitverse.ru/kpa39l/email-assistant.git
synced 2026-09-29 21:25:10 +00:00
78 lines
6.4 KiB
Markdown
78 lines
6.4 KiB
Markdown
# Tasks: Потоковая синхронизация почты (IMAP IDLE) и онлайновая копия ящика
|
||
|
||
## Задачи
|
||
|
||
### Фаза 0: Подготовка и проверка авторизации
|
||
- [ ] 1. Установить/проверить `aioimaplib` (pip) — библиотека для IDLE-потока;
|
||
если не ставится — зафиксировать fallback на сырой socket.
|
||
(2026-09-15: `aioimaplib` НЕ установлен; на следующем шаге — решить
|
||
ставить или идти на сыром socket, т.к. imap_client.py уже это умеет.)
|
||
- [x] 2. **Проверить авторизацию** для stream-процесса:
|
||
himalaya логинится успешно (эталон), чистый IMAP-скрипт — нет.
|
||
Отработать AUTH=PLAIN (SASL-IR), формат login; зафиксировать рабочий
|
||
вариант в коде. (Блокер — без него stream не запустится.)
|
||
**Выполнено 2026-09-15**: создан `scripts/imap_client.py` с отдельной
|
||
функцией `imap_connect()` (STARTTLS + LOGIN + re-try против rate-limit).
|
||
Реальная проверка: LOGIN как e.storozhenko прошёл, `fetch_attachments_imaplib`
|
||
через неё скачал `Переместить стол.docx` 1.1 МБ (UID 14200) без \Seen.
|
||
Rate-limit Exchange: после серии быстрых попыток сервер молчит (timeout),
|
||
поэтому в `imap_connect()` re-try с экспоненциальной паузой.
|
||
- [x] 2b. **Логирование авторизации + метрики доступности/сессии**:
|
||
`imap_log()` пишет JSON-строки в `/opt/hermes/email/logs/imap_client.log`
|
||
(conn_ok / conn_error / auth_ok / auth_failed / session_started / session_ended);
|
||
`imap_metrics()` считает auth_success_rate, conn_error, sessions_active;
|
||
`imap_session` — контекстный менеджер (гарантирует session_ended).
|
||
Проверено: `python3 imap_client.py --metrics` показывает метрики.
|
||
Пароль никогда не логируется.
|
||
**TODO (позже)**: полноценный мониторинг — Prometheus-формат/статус-эндпоинт
|
||
для stream-сервиса, алерты при падении auth_success_rate / conn_error.
|
||
|
||
### Фаза 1: Скелет сервиса imap_stream.py
|
||
- [ ] 3. `scripts/imap_stream.py`: connect + STARTTLS + login; folder list
|
||
(get_inbox_subfolders); SELECT INBOX; IDLE-цикл с обработкой untagged
|
||
(EXISTS/EXPUNGE/FETCH FLAGS); reconnect при обрыве.
|
||
- [ ] 4. Реализовать reconcile: UID FETCH новых писем (>last_uid) → событие
|
||
`added` + архивация (переиспользовать mail_archive.py); сравнение FLAGS →
|
||
`flag_changed`; отсутствие после EXPUNGE → `deleted` (soft).
|
||
- [ ] 5. SQLite schema: `mailbox_state` + `mailbox_events` (ChangeLog) —
|
||
создать `/opt/hermes/email/state/mailbox.db`, функции init/insert/read.
|
||
|
||
### Фаза 2: Change Analyzer
|
||
- [ ] 6. `scripts/change_analyzer.py`: чтение mailbox_events от offset;
|
||
на `added` — классификация (email_classifier) + обработчики (email_handlers);
|
||
на `moved`/`deleted`/`flag_changed` — обновление mailbox_state, RAG-метка.
|
||
**Уведомления в ЛС Telegram уже проверены живьём (2026-09-15)**: письмо 3216
|
||
помечено urgent → доставка в private chat 281328953 (kpa39l), msg_id=60,
|
||
подтверждено пользователем. Для ЛС нужен явный `TELEGRAM_CHAT_ID=281328953`
|
||
(дефолт в email_handlers.py — канал @dedinit_vesti).
|
||
- [ ] 7. Обработка `replied`: \Answered или новое письмо с In-Reply-To на
|
||
известный Message-ID → событие `replied`; обновить thread в state.
|
||
|
||
### Фаза 3: systemd и интеграция
|
||
- [ ] 8. systemd user units (`email-imap-stream.service`,
|
||
`email-change-analyzer.service`), автозапуск; проверка auto-restart.
|
||
- [ ] 9. Hermes cron `mail-archive-every-5min` → fallback (идемпотентен с
|
||
stream; не дублирует). Проверить, что при работающем stream cron не
|
||
архивирует повторно (last_uid / state).
|
||
- [ ] 10. Живой тест: новое письмо (отправить себе/ждущее), перемещение
|
||
(через IMAP MOVE/клиент), удаление, ответ — всё фиксируется в ChangeLog
|
||
и mailbox_state; \Seen не ставится (проверка флагов до/после).
|
||
|
||
### Фаза 4: Документация и доводка
|
||
- [ ] 11. STATUS.md / README / WALKTHROUGH: сервисы, порты (нет новых внешних),
|
||
как смотреть ChangeLog (`sqlite3 mailbox.db 'select * from mailbox_events'`),
|
||
как перезапускать.
|
||
- [ ] 12. RAG-интеграция (опционально, Фаза 2 проекта): индексация событий
|
||
ChangeLog в Qdrant — чтобы агент мог ответить «что случилось с письмом».
|
||
|
||
## Верификация
|
||
|
||
- `systemctl --user status email-imap-stream email-change-analyzer` — active (running)
|
||
- `sqlite3 /opt/hermes/email/state/mailbox.db 'select count(*) from mailbox_state'` — растёт
|
||
- `sqlite3 ... 'select event, count(*) from mailbox_events group by event'` —
|
||
есть added/moved/deleted/flag_changed
|
||
- Новое письмо в INBOX → архив появляется в течение ~1-2 мин (не 5)
|
||
- Перемещение письма в клиенте → в mailbox_state folder обновлён, в ChangeLog `moved`
|
||
- Удаление письма → `deleted` в ChangeLog, файл email.md на месте (soft-delete)
|
||
- Ответ → `replied` или `flag_changed` (\Answered)
|
||
- Флаги непрочитанного письма на IMAP после архивации: `()` → `()` (Seen нет) |