mirror of
https://gitverse.ru/kpa39l/email-assistant.git
synced 2026-09-29 09:15:09 +00:00
39df85b51c
Причина: himalaya message read и attachment download используют IMAP BODY[], который по RFC 3501 выставляет \Seen на сервере (Microsoft Exchange). Пользователь: письма в ящике после скачивания становятся прочитанными. Фикс: - чтение тела: himalaya message read --preview (не ставит Seen) - вложения: fetch_attachments_imaplib() — сырой IMAP stdlib (socket+ssl), UID FETCH (BODY.PEEK[]), папки в modified UTF-7, литералы до 1.5МБ, MIME-encoded words, фолбэк himalaya + flag remove seen Проверено живьём: UID 14200 (INBOX, docx 1.1МБ) флаги ()->() — Seen не выставлен. Openspec: change no-mark-seen-on-archive заархивирован (2026-09-14-no-mark-seen-on-archive), 7/7 validate OK
69 lines
4.2 KiB
Markdown
69 lines
4.2 KiB
Markdown
# email-storage-format Specification
|
||
|
||
## Purpose
|
||
Формат хранения архива писем: `email.md` (YAML-frontmatter + текст) в структуре
|
||
`/<folder>/YYYY/MM/<uid>/`, выбранный по итогам анализа STORAGE_ANALYSIS.md
|
||
(9 критериев: полнота заголовков, инкрементальность, идемпотентность, удобство
|
||
поиска и др.). Хранит полные заголовки письма в frontmatter и тело как Markdown;
|
||
доп. поля (classification, handled_*, attachments) расширяют frontmatter без
|
||
изменения формата.
|
||
|
||
## Requirements
|
||
|
||
### Requirement: REQ-EMA-STORAGE-001: Обоснование выбора формата хранения
|
||
|
||
**MUST** — проект должен содержать документ `STORAGE_ANALYSIS.md` в корне
|
||
`/opt/hermes/email-assistant/`, объективно сравнивающий текущий формат
|
||
хранения (`email.md` в `/<folder>/YYYY/MM/UID/`) с Maildir, MBOX и notmuch.
|
||
|
||
#### Scenario: Документ анализа существует
|
||
|
||
**GIVEN** файл `STORAGE_ANALYSIS.md` существует
|
||
**WHEN** его открывают
|
||
**THEN** он содержит:
|
||
- таблицу сравнения по критериям (производительность, устойчивость, интеграция,
|
||
пригодность для LLM, совместимость с MUA, масштабируемость, бэкапы)
|
||
- явную рекомендацию (остаться на текущем / мигрировать на Maildir / иное)
|
||
- обоснование рекомендации с учётом мотивации пользователя (локальная LLM
|
||
в скриптах, без облака)
|
||
|
||
### Requirement: REQ-EMA-STORAGE-002: Ссылка из README
|
||
|
||
**MUST** — `README.md` проекта должен содержать ссылку на `STORAGE_ANALYSIS.md`.
|
||
|
||
#### Scenario: README содержит ссылку
|
||
|
||
**GIVEN** `README.md` проекта
|
||
**WHEN** открываем его
|
||
**THEN** в разделе «Оценка альтернатив» (или аналогичном) есть ссылка
|
||
`[Анализ формата хранения (ФС vs Maildir)](STORAGE_ANALYSIS.md)`.
|
||
|
||
### Requirement: REQ-EMA-STORAGE-003: Без изменения данных
|
||
|
||
**MUST** — change не должен модифицировать, мигрировать или удалять
|
||
существующие письма в `/opt/hermes/email/`. Анализ — только документация.
|
||
|
||
#### Scenario: Архив не изменён
|
||
|
||
**GIVEN** архив `/opt/hermes/email/`
|
||
**WHEN** change применён
|
||
**THEN** файлы писем остаются без изменений (проверка: `find /opt/hermes/email -name 'email.md' | wc -l` — то же число, что и до change).
|
||
|
||
### Requirement: Архивация не помечает письмо прочитанным
|
||
|
||
Чтение тела письма при архивации MUST NOT выставлять IMAP-флаг `\Seen`.
|
||
`mail_archive.py` для получения тела использует `himalaya message read` с
|
||
флагом `--preview` (документировано: читает БЕЗ установки `\Seen`).
|
||
|
||
#### Scenario: Архивация непрочитанного письма
|
||
- **GIVEN** письмо в INBOX с флагами `()` (непрочитанное)
|
||
- **WHEN** `mail_archive.py` архивирует письмо (пишет `email.md`)
|
||
- **THEN** в frontmatter `email.md` флаг `Seen` отсутствует И на IMAP флаги
|
||
письма остаются `()`
|
||
|
||
#### Scenario: Флаги в frontmatter соответствуют IMAP
|
||
- **GIVEN** письмо заархивировано после фикса
|
||
- **WHEN** флаги письма на IMAP меняются (пользователь прочитал/ответил)
|
||
- **THEN** frontmatter `email.md` после следующей синхронизации отражает флаги
|
||
IMAP (Seen появляется только если письмо реально прочитано пользователем)
|