Skip to content

imap: key a reply that carries only In-Reply-To on its parent, as the mail-source contract requires #1919

Closed

Description

@potiuk

The mail-source contract's Thread identity section (added in #1811) keys a thread on the first References id, else the first In-Reply-To id, else the message's own Message-ID, even when that root is not in the archive. The maildir backend does all three. The imap backend skips the middle step: imap_source.searching.thread_root_of returns the first References id or the message's own id, so a reply carrying only In-Reply-To is its own thread on IMAP and joins its parent on maildir. An id recorded by a -sync run against one backend then fails to match on the other, and a duplicate tracker gets proposed. The contract and the maildir README currently note this gap.

Two changes close it:

  • thread_root_of (tools/mail-source/imap/src/imap_source/searching.py) falls back to the first bracketed In-Reply-To token before the message's own id. Only bracketed tokens count, so a comment beside the id (In-Reply-To: (was: report) <r@h>) is not taken as the root.
  • read_thread (tools/mail-source/imap/src/imap_source/read_thread.py) currently refuses a thread whose root message is not in the fetched window (thread root … not found). With the fallback, a thread can be keyed on a root the window does not hold, so it should return the reachable messages instead, the way maildir does, and only fail when nothing references the id.

Done when: both backends give the same thread_id for a reply carrying only In-Reply-To and for replies to a root missing from the archive, with a test for each in the IMAP suite, and the "does not take the In-Reply-To step yet" notes are removed from tools/mail-source/contract.md, tools/maildir/README.md and the read_archive.py docstring.

Activity

  1. sharpca commented on Oct 31, 2026

    @sharpca
    Contributor

    Thanks for filing it — I'll take #1919.

    Plan:

    • thread_root_of falls back to the first bracketed In-Reply-To token before
      the message's own id, so a comment beside the id ((was: report) <r@h>) is
      not taken as the root.
    • read_thread returns the reachable messages when the root is outside the
      fetched window, and fails only when nothing references the id.
    • The three "IMAP does not take the In-Reply-To step yet" notes go
      (tools/mail-source/contract.md, tools/maildir/README.md, the
      read_archive.py docstring), replaced by the rule as it now holds for both
      backends.
    • One test per case in the IMAP suite, plus a parity check that both backends
      give the same thread_id for a reply carrying only In-Reply-To.

    I'll rebase on the current main before opening the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    contract:mail-sourceTool capability: inbound-mail ingestion (mbox / IMAP / ...)family:toolstools/*

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions