Files
hermes 39df85b51c fix: архивация/вложения больше не помечают письма прочитанными (Seen)
Причина: 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
2026-09-14 08:08:48 +00:00

2.5 KiB

email-attachments Specification

ADDED Requirements

Requirement: Скачивание вложений не помечает письмо прочитанным

Скачивание вложений MUST NOT выставлять IMAP-флаг \Seen (письмо не должно становиться «прочитанным» в почтовом ящике).

Способ: himalaya attachment download ставит \Seen (использует BODY[]), и флага --preview у него нет. Поэтому get_attachments() MUST использовать сырой IMAP-запрос BODY.PEEK[] через stdlib imaplib (не ставит \Seen на Microsoft Exchange, проверено) и распаковку MIME через stdlib email.

Scenario: Скачивание вложения у непрочитанного письма

  • GIVEN письмо в INBOX с флагами () (непрочитанное)
  • WHEN get_attachments() скачивает его вложения
  • THEN файлы вложений сохранены в attachments/, а флаги письма на IMAP остаются () (флаг \Seen не выставлен)

Scenario: Фолбэк при сбое сырого IMAP

  • WHEN fetch_attachments_imaplib() не может получить письмо (ошибка IMAP)
  • THEN вложения скачиваются через himalaya attachment download, после чего флаг \Seen снимается через himalaya flag remove (письмо временно помечается, но восстанавливается) ИЛИ операция помечается как недоступная — письмо НЕ остаётся прочитанным навсегда

Requirement: Пароль IMAP для скачивания вложений

fetch_attachments_imaplib() MUST брать учётные данные IMAP (host, port, login, пароль) из конфига himalaya (~/.config/himalaya/config.toml, секция [accounts.<default>], backend.*, пароль — backend.auth.raw) и MUST NOT логировать или выводить пароль.

Scenario: Доступ к конфигу

  • WHEN get_attachments() запускается для письма
  • THEN подключение к IMAP выполняется с учётными данными из конфига himalaya, пароль никуда не выводится