fix(email): RFC-correct In-Reply-To (§3.6.4) threading + RFC 2047 (§6.2) address display - #1185
fix(email): RFC-correct In-Reply-To (§3.6.4) threading + RFC 2047 (§6.2) address display#1185seonghobae wants to merge 3 commits into
Conversation
assign_thread_id() normalized the In-Reply-To header by stripping angle
brackets off the whole string. RFC 5322 §3.6.4 defines In-Reply-To as
"In-Reply-To:" 1*msg-id, so it may legitimately carry more than one
message-id. For a two-id value like "<a@x> <b@x>" the old code produced
the mangled id "a@x> <b@x", which matches no stored parent: the reply
failed to join its parent thread and, when References was absent, became
a bogus thread root.
Parse In-Reply-To with the same angle-bracket extractor used for
References and take the first parsed id as the immediate parent, matching
jwz "message threading" (extract the first message-id from In-Reply-To).
Single-id and bracket-less values are unchanged, so all existing tests
stay green.
Verification (backend/):
DISABLE_BACKGROUND_WORKERS=1 PYTHONWARNINGS=error python3 -m pytest \
tests/test_threading_service.py tests/test_threading_perf.py \
tests/test_threading_pipeline.py tests/test_email_parser.py \
tests/test_email_import_service.py -q
-> 75 passed, 0 warnings
python3 -m ruff check services/threading_service.py \
tests/test_threading_service.py -> All checks passed
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REEc4WtvMHbGD23XK6xbLK
|
Warning Review limit reached
Next review available in: 8 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
Comment |
_sanitize_address_display_text decoded From/To/Reply-To display names via getaddresses (correct), then passed them through email.utils.formataddr, which re-encodes any non-ASCII display name back into an RFC 2047 encoded-word. As a result a header such as `From: =?UTF-8?B?7ZmN6ri464+Z?= <hong@test.com>` was stored and shown as `=?utf-8?b?7ZmN6ri464+Z?= <hong@test.com>` instead of the decoded `홍길동 <hong@test.com>`. RFC 2047 §6.2 requires encoded-words in a displayed header to be presented in their decoded form. sender/recipients/reply_to are display (and fingerprint) fields that are never re-serialized into an outgoing message, so the decoded human-readable form is the correct value. Fix: format the already-decoded, sanitized display name with a local helper (_format_address_display) that mirrors formataddr's quoting/escaping for ASCII names (verified identical output) but never RFC 2047-re-encodes, keeping joined recipient lists unambiguous. Adds a regression test citing RFC 2047 §6.2 covering B- and Q-encoded display names. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01REEc4WtvMHbGD23XK6xbLK
|
Closing after Loop drain: permanently blocked — branch was updated onto develop for mergeability, which cleared prior APPROVED robot evidence; re-review (CodeRabbit/OpenCode) and/or central gate jobs (metadata-only gate evaluation, coverage-evidence) remained pending/stuck without a re-runnable workflow handle. Not force-merging (merge-gate policy). Re-open a focused PR when robot capacity is available. Related product security fixes that reimplemented cleanly remain on branch goal/carddav-path-traversal-decode (#1206) for relaunch. |
|
PR governance metadata gate is not ready for
|
|
Superseded by #1192 after current-head CodeGraph and branch comparison. #1192 preserves both behaviors from this PR (decoded RFC 2047 display names and RFC 5322 multi-ID In-Reply-To threading) and extends them with CFWS handling, folded Message-ID normalization, unknown-zone Date normalization, broader 100% parser/threading tests, and the standards-basis research pack. Closing the overlapping smaller PR to avoid competing edits to the same parser/threading files. |
Two small, independent, standards-grounded correctness fixes to Naruon email-header handling (one commit each).
1. RFC 5322 §3.6.4 — multi-id
In-Reply-Tothreading (4dadff0)assign_thread_idparsedIn-Reply-Towithnormalize_message_id, which only strips</>off the whole string. RFC 5322 §3.6.4 definesin-reply-to = "In-Reply-To:" 1*msg-id— it may carry multiple message-ids. A legal"<parent@x> <cc-parent@x>"became the corrupted id"parent@x> <cc-parent@x", so the reply failed to join its parent thread and, whenReferenceswas absent, became a mangled deterministic root (orphaned). Fixed to use the multi-idextract_reference_ids(...)[0](first parent, per §3.6.4 and jwz message threading). Single-id/absent paths unchanged.2. RFC 2047 §6.2 — encoded-word address display names (
4cb34fe)_sanitize_address_display_textdecodedFrom/To/Reply-Todisplay names viagetaddresses(correct), then passed them throughemail.utils.formataddr, whose defaultcharset='utf-8're-encodes any non-ASCII display name back into an RFC 2047 encoded-word. SoFrom: =?UTF-8?B?7ZmN6ri464+Z?= <hong@test.com>was stored/shown as=?utf-8?b?…?= <hong@test.com>instead of홍길동 <hong@test.com>. RFC 2047 §6.2 requires encoded-words in a displayed header to be shown decoded; these fields are display+fingerprint surfaces never re-serialized into an outgoing message. Fixed with a local_format_address_displaythat mirrorsformataddr's quoting/escaping (ASCII output byte-identical, verified) but never re-encodes. (Subjectwas already correct — it doesn't round-trip throughformataddr.)Type of change
Verification (from
backend/,DISABLE_BACKGROUND_WORKERS=1 PYTHONWARNINGS=error)develop(assert the mangled/re-encoded output) and pass after the fix.pytest tests/test_threading_service.py→ 8 passed; parser+threading+service → 39 passed.Timeout/Fatal/Warn/Denied.ruff checkon all changed files → clean.