Mailbase
FeaturesPricingDocsBlogComparisonsChangelog
Sign inStart free
Home/Blog/Email Threading Headers: Message-ID, In-Reply-To, and References
Email infrastructureUpdated July 30, 20269 min read

Email Threading Headers: Message-ID, In-Reply-To, and References

A practical guide to the headers, data model, sending rules, and tests that keep transactional and support replies in the right email conversation.

By Mailbase Team · Target keyword: email threading headers
Mobile inbox showing a reply conversation — Email Threading Headers: Message-ID, In-Reply-To, and References
Photo from Unsplash
On this page
OverviewUnderstand the three-header contractBuild reply headers from the direct parentStore enough data to survive imperfect mailKeep message identity stable across retriesTest threading as an interoperability featureWhere Mailbase fits in a reply workflowCommon MistakesSources & Further ReadingRelated guidesFAQRelated reading

Overview

Email threading headers tell mail clients and receiving systems how messages relate. Give every outbound message a unique Message-ID. When sending a reply, set In-Reply-To to the direct parent's Message-ID and build References from the parent's existing reference chain plus that parent ID. Subject prefixes such as Re: may help people scan an inbox, but they are not a reliable relationship key. A production design stores the exact wire identifiers and also keeps its own immutable conversation ID, because external senders and mailbox clients do not always preserve a perfect chain.

Understand the three-header contract

Glowing network cables converging into a switch — Understand the three-header contract
Photo from Unsplash

RFC 5322 defines Message-ID as a single unique message identifier. It also says replies should include In-Reply-To and References where appropriate. The fields solve different jobs: Message-ID identifies this message, In-Reply-To names the message being answered directly, and References carries the ancestry that lets a client reconstruct a conversation.

Treat the values as opaque identifiers. Do not parse business meaning from the text around the @ sign, lowercase them, trim their angle brackets before storage, or regenerate a provider-returned value into your preferred format. Normalize only enough to compare safely in your own system, while retaining the original header value for later replies and diagnostics.

  • Generate one Message-ID per logical message, not per rendering attempt
  • Keep provider message identifiers separate from RFC Message-ID values
  • Use angle-bracketed message identifiers on the wire
  • Never use the subject as the database key for a conversation
HeaderWhat to writeWhat to persist
Message-IDOne globally unique ID for the new messageExact outbound ID and provider ID separately
In-Reply-ToThe direct parent message's IDExact parent ID used for the send
ReferencesPrior reference chain followed by the parent IDParsed ordered list and original raw header

Build reply headers from the direct parent

Hands typing on a laptop keyboard in an inbox view — Build reply headers from the direct parent
Photo from Unsplash

Suppose the original outbound message has Message-ID <welcome-42@mailer.example>. A customer reply should identify itself with a new Message-ID, set In-Reply-To to <welcome-42@mailer.example>, and include that ID in References. If your app then answers the customer, the new message points In-Reply-To at the customer's Message-ID and carries forward the customer's References chain before appending the customer ID.

The parent must be the actual message being answered, not merely the first message your application sent. That distinction matters in a shared support inbox: always pointing at the campaign root can flatten branches, confuse clients, and make operator replies appear out of order.

  1. Load the direct parent message selected by the user or automation.
  2. Read the parent's exact Message-ID and parsed References list.
  3. Create a new unique Message-ID for the reply.
  4. Set In-Reply-To to the parent's Message-ID.
  5. Set References to the parent's reference chain followed by the parent's Message-ID.
  6. Persist the relationship before enqueueing the send, then record the provider attempt separately.
MessageIn-Reply-ToReferences
A: original outboundNoneNone
B: recipient replies to A<A@example><A@example>
C: operator replies to B<B@example><A@example> <B@example>

Store enough data to survive imperfect mail

A robust data model separates a conversation from its transport headers. Store an internal conversation_id and message_id primary key, parent_message_id, direction, RFC Message-ID, raw and parsed References, provider message ID, sender, recipients, timestamps, and delivery state. Put a uniqueness constraint on normalized RFC Message-ID when one exists, but allow a quarantine path for malformed or missing identifiers instead of attaching them to a guessed thread.

Inbound matching should use a confidence ladder. First match In-Reply-To against a known RFC Message-ID. Then inspect References from newest to oldest for a known ancestor. A signed reply alias or tokenized reply-to address can provide a separate application correlation signal. Subject, sender, and time proximity are useful for a manual-review suggestion, not an automatic high-confidence join.

  • Keep raw headers for incident debugging and parser improvements
  • Deduplicate inbound delivery before creating a second message row
  • Do not merge conversations across workspaces or tenants
  • Record which signal produced the threading decision
SignalConfidenceRecommended action
Known In-Reply-To valueHighAttach as child of that message
Known ID in ReferencesHigh to mediumAttach to the conversation; record inferred parent
Valid signed reply tokenHigh for conversationAttach to token's conversation and retain header evidence
Matching normalized subject onlyLowQueue for review; do not auto-merge

Keep message identity stable across retries

A transport retry is not a new logical email. If a queue retries the same send after a timeout or temporary failure, reuse the logical message record and its Message-ID. Creating a fresh Message-ID on every attempt can produce duplicate visible messages if an earlier request succeeded but its acknowledgement was lost. Pair the logical record with an idempotency key and retain each provider attempt as a child event.

A deliberate resend is different. If a human chooses to send an updated message, create a new logical message and Message-ID. Decide explicitly whether it is a reply in the existing conversation or a new thread. That keeps audit history honest and prevents retry mechanics from leaking into the recipient experience.

  • Generate identity before the network call
  • Do not confuse provider acceptance IDs with internet message identifiers
  • Make retry workers idempotent
  • Audit every attempt without showing each attempt as a separate email
SituationMessage-ID ruleConversation rule
Temporary provider retryReuse the logical Message-IDSame message and conversation
Failover attempt for the same send intentReuse unless the provider contract prevents itSame logical message; log a new attempt
Human edits and resendsCreate a new Message-IDChoose reply or new conversation deliberately
Automated follow-upCreate a new Message-IDReference the intended parent if continuing the thread

Test threading as an interoperability feature

A unit test can prove header construction, but only mailbox tests reveal how clients display the result. Build fixtures for a new conversation, one reply, a three-message chain, an inbound reply with folded headers, missing In-Reply-To with usable References, duplicate webhook delivery, and a malformed identifier. Then send controlled conversations through the mailbox providers and clients your users actually use.

Your acceptance check should inspect both raw source and UI behavior. Confirm that each message has one expected Message-ID, reply headers point to known IDs, the visible order is correct, and the inbound parser attaches the reply to the right tenant and conversation. Include forwarding and support-system handoffs because intermediaries can alter the chain.

  • Test long chains and folded References headers
  • Include messages composed by humans outside your application
  • Log parser and matching reasons without logging sensitive bodies unnecessarily
  • Monitor orphaned replies and manual re-thread rates after release
  1. Assert exact header output from deterministic message fixtures.
  2. Round-trip replies through at least two external mailbox systems.
  3. Inspect raw message source instead of trusting only the threaded UI.
  4. Replay the same inbound event and verify that no duplicate message is created.
  5. Remove or corrupt each threading signal and confirm the fallback goes to review rather than a guessed conversation.
  6. Verify tenant boundaries with identical subjects and participants in separate workspaces.

Where Mailbase fits in a reply workflow

Mailbase's relevant role is the workflow around replies: a shared inbox, durable outbound work, event history, assignment, and AI-assisted drafts. Those features are useful only when transport identity is preserved accurately. Threading headers belong in the sending and inbound-ingestion contract; team workflow belongs above that contract.

If you build or integrate a similar system, keep the boundary explicit. The provider transports messages, RFC identifiers connect message ancestry, and the application controls tenant-safe conversation records, operators, status, and follow-up work. When the evidence is ambiguous, surface an orphaned reply for review rather than quietly merging customer conversations.

  • Show operators the whole conversation, not only the latest webhook event
  • Keep AI drafts attached to an internal conversation before they are sent
  • Preserve transport identifiers in the audit trail
  • Fail closed when a reply cannot be resolved to one workspace

Common Mistakes

  • Choosing a tool before deciding who owns deliverability.
  • Treating DNS authentication as a one-time checkbox instead of an operating baseline.
  • Mixing product-critical transactional email with experimental marketing sends, with no clear boundary.
  • Trusting headline metrics (like open rate) that privacy proxies now inflate.

Sources & Further Reading

Official docs for current setup details, pricing, and API behavior — verify specifics there, since they change.

RFC 5322: Internet Message Format

Related guides

More on email threading headers and the surrounding email infrastructure workflow:

Mailbase API docs
API token docs
transactional email for SaaS
email API vs SMTP
SMTP relay for SaaS
AWS SES email stack
reply inbox workflow
Try Mailbase free
Send 200 emails a month on us. Paid plans start at €9 — or bring your own useSend for €5.
See plans

FAQ

Which headers are used for email threading?

The core headers are Message-ID, In-Reply-To, and References. Message-ID identifies the current message, In-Reply-To identifies its direct parent, and References carries the prior message ancestry used to reconstruct the conversation.

Is Re: in the subject enough to thread an email?

No. Subject prefixes are presentation conventions and can collide across unrelated conversations. Use RFC message identifiers for transport relationships and an internal conversation ID for application state.

Should an email retry get a new Message-ID?

A transport retry of the same logical send should normally keep the same logical message identity and Message-ID, while each provider attempt is logged separately. A deliberate new or edited send should receive a new Message-ID.

How should inbound email be matched to a thread?

Match a known In-Reply-To first, then known identifiers in References, then a secure application correlation signal such as a signed reply token. Do not auto-merge on subject alone; quarantine ambiguous messages for review.

Related reading

Transactional email7 min read
Transactional Email for SaaS: The Practical Guide
A practical guide to transactional email for SaaS: what counts as transactional, choosing an API or SMTP provider, templates, deliverability, idempotency, and the operations that keep critical mail flowing.
Deliverability7 min read
Email API vs SMTP: Which Should You Use?
Email API vs SMTP compared for SaaS: how each works, reliability, speed, debugging, features, and portability — plus why many teams use both.
Transactional email7 min read
SMTP Relay for SaaS Apps: What to Use and Why
What an SMTP relay is, when a SaaS app should use one, how it differs from an email API, the providers to consider, and the DNS and production tradeoffs.
Transactional email7 min read
AWS SES Email Stack for SaaS Builders
How to think about Amazon SES as part of a SaaS email stack: what SES is and isn't, the layers you build on top of it, the sandbox/SNS setup, and where it fits versus a full API.
Product6 min read
Reply Inbox Email Workflow in Mailbase
A product guide to the Mailbase reply inbox for teams that want campaign replies, support context, and follow-up work in one place.
Email infrastructure9 min read
Email Webhook Events: A Practical Processing Guide
A practical email webhook events playbook for building idempotent ingestion, clean event models, suppression updates, and reliable analytics.
Mailbase
Product
FeaturesPricinguseSend integrationChangelog
Learn
BlogDocsAPI referenceResources
Compare
ComparisonsAlternatives
Guides
Transactional email servicesSelf-hosted useSend stackSelf-hosted email marketingSPF, DKIM & DMARCEmail deliverability
Legal
TermsPrivacy
© 2026 Mailbase · french-webEmail workflow for builders.