The short answer
Commune uses RFC 5322In-Reply-To and References headers with real SMTP Message-IDs for standards-compliant threading across Gmail, Outlook, Apple Mail, and Thunderbird. Every outbound email also includes a routing token in the Reply-To address as a secondary resolution mechanism. When a reply arrives, Commune resolves the thread using multiple signals — SMTP headers first, then routing tokens, then subject matching as a last resort.
Why subject matching fails
Subject lines are unreliable thread identifiers:- Email clients prepend prefixes inconsistently —
Re:,RE:,Aw:,Sv:,Re: Re:,Fwd: Re: - Users edit subjects mid-thread (“Following up on our call” → no match)
- Forwarding strips the original subject context entirely
- Corporate gateways (Outlook, Exchange) rewrite subjects with ticket numbers or legal footers
- International clients use localized reply prefixes that English normalization rules miss
RFC 5322 threading (outbound)
When Commune sends a follow-up email in a thread, it sets the standardIn-Reply-To and References headers with the real SMTP Message-ID of the previous message. This is the same mechanism every email client uses to build conversation threads.
Commune captures the real Message-ID via a silent self-BCC — completely invisible to the recipient — and stores it for use in follow-up headers. This ensures threading works correctly across all email clients, not just Gmail.
Priority order (inbound resolution)
When an inbound reply arrives, Commune resolves the thread in this order:- Routing token in Reply-To — extracted from
agent+{token}@commune.email; resolves immediately if present - In-Reply-To header — standard RFC 5322 header; matched against stored Message-IDs
- References header chain — the full chain of
Message-IDs in the thread; matched against any known message - Subject normalization — strips prefixes (
Re:,Fwd:, etc.), lowercases, trims; last resort only
How routing tokens work
When Commune sends an email, it sets theReply-To header to a token-encoded address:
thread_id directly. When the recipient hits reply, their email client sends to that address. Commune’s inbound processor decodes the token from the address — no database lookup required.
Key properties of routing tokens:
- Survive forwarding — the
Reply-Toaddress travels with the email regardless of how many hops it takes - Stateless decode — the thread context is encoded in the token itself, not referenced from a lookup table
- One token per thread — the same token is reused across all outbound messages in a thread, so any reply in a long chain resolves correctly
The thread_id field
Every message object has athread_id. The first outbound message in a new conversation starts the thread. All subsequent messages — inbound or outbound — that resolve to the same thread share that thread_id.
The webhook payload includes thread_id on every inbound event:
thread_id to fetch thread history before generating a reply.
Fetch thread history
Messages are returned in chronological order. The first item is the original outbound message that started the thread.
What can still break threading
Even with routing tokens, some edge cases exist:- Manual forward without quoting — the user creates a new email from scratch; no token, no
In-Reply-To, no references; Commune may start a new thread - Corporate email gateways rewriting Reply-To — some Exchange and Proofpoint configurations strip or overwrite custom
Reply-Toaddresses before delivery - User switches email client mid-thread — a new client may not preserve the
Referencesheader chain from the previous client, breaking fallback resolution - Delayed replies across long time windows — subject normalization fallback only matches against recent threads; very old threads may not match if the sender is new to the inbox
Related
How Email Threading Works
In-depth explanation of routing tokens, RFC 5322 headers, and thread resolution edge cases.
Threads
Thread management API for fetching conversation history and resolving message chains.
Webhooks
Webhook payload reference including the thread_id field on every inbound event.

