Files
email-assistant/openspec/changes/email-classification-handlers/specs/email-handlers/spec.md
T
hermes 7550aff102 feat: классификация писем Qwen3:8b + обработчики (urgent→TG, task→VTODO, meeting→VEVENT)
- mail_archive.py: фикс вложений himalaya --dir → --downloads-dir; attachments/ только при has_attachment; идемпотентно
- email_classifier.py: Qwen3:8b (Ollama) → теги info/urgent/task/meeting в frontmatter email.md
- email_handlers.py: urgent→Telegram (Bot API+SOCKS5), task→Radicale VTODO, meeting→Radicale VEVENT; handled_* идемпотентность; --dry-run
- .gitignore: игнор *.env.bak*
- openspec: чейндж email-classification-handlers (в работе)
- STATUS/TODO/WALKTHROUGH: прогресс сессии, подводные камни Radicale (http.client, Depth:1, формат дат)
2026-09-13 20:35:58 +00:00

4.3 KiB
Raw Blame History

Purpose

Подключение обработчиков по тегам классификации письма: уведомление в мессенджер для срочных писем, создание задачи в Vikunja для писем с задачей, создание события в Radicale для писем со встречей. Обработчики запускаются автоматически после классификации и работают идемпотентно.

ADDED Requirements

Requirement: Уведомление в мессенджер для срочных писем

Письмо с тегом urgent MUST вызывать отправку уведомления в мессенджер (Telegram) с отправителем, темой и первыми строками текста.

Scenario: Срочное письмо

  • WHEN email_classifier.py пометил письмо тегом urgent
  • THEN email_handlers.py отправляет в Telegram уведомление с from/subject/превью

Requirement: Создание задачи в Radicale (VTODO) для писем с задачей

Письмо с тегом task MUST создавать задачу в Radicale (CalDAV, календарь «Задачи») как VTODO с темой письма в SUMMARY и ссылкой на письмо в DESCRIPTION.

Scenario: Письмо с задачей

  • WHEN email_classifier.py пометил письмо тегом task
  • THEN в Radicale (календарь Задачи) создаётся VTODO: SUMMARY=тема письма, DESCRIPTION=ссылка на email.md

Requirement: Создание события в Radicale для писем со встречей

Письмо с тегом meeting MUST создавать событие в календаре Radicale (Рабочий) с темой письма как SUMMARY и извлечённой датой/временем, если они указаны.

Scenario: Письмо со встречей

  • WHEN email_classifier.py пометил письмо тегом meeting и в классификации есть дата/время
  • THEN в Radicale (календарь Рабочий) создаётся VEVENT с SUMMARY=тема письма

Requirement: Идемпотентность обработчиков

Обработчик MUST запускаться для каждого письма один раз; повторный запуск на уже обработанном письме MUST NOT создавать дубликат задачи/события/уведомления.

Scenario: Повторный запуск обработчиков

  • WHEN email_handlers.py запущен повторно на письме, для которого уже созданы задача/событие
  • THEN дубликаты не создаются (трекинг обработанных в state)

Requirement: Информационные письма не создают обработчиков

Письмо с тегом info MUST NOT вызывать уведомления, задач или событий; оно только помечается тегом в frontmatter.

Scenario: Информационное письмо

  • WHEN email_classifier.py пометил письмо тегом info
  • THEN email_handlers.py не создаёт ни уведомления, ни задачи, ни события

Requirement: Уведомление о недоступности обработчика

Если обработчик не может выполниться (Radicale недоступен, нет учётных данных), MUST быть записана ошибка в лог, и письмо MUST остаться помеченным тегом для повторной попытки (не теряться).

Scenario: Radicale недоступен

  • WHEN email_handlers.py пытается создать задачу/событие, но Radicale недоступен
  • THEN ошибка пишется в лог, письмо остаётся с тегом task/meeting, повторная попытка возможна