Threads
Threads group related messages into conversations. AgentSend automatically threads messages based on standard email headers so your agents always have the full context of a conversation.
Overview
Every email conversation in AgentSend is organized into a thread. A thread collects all related messages — the original email, every reply, and every reply-to-reply — into a single, ordered conversation object. This makes it easy for agents to read the full history before composing a response.
Threads are created automatically. When AgentSend receives or sends a message that starts a new conversation, a thread is created. When a reply arrives, AgentSend matches it to the existing thread and appends the new message.
Threads are scoped to an inbox. The same email chain received by two different inboxes will produce two separate thread objects.
How Threading Works
AgentSend follows the standard email threading model used by every major email client. When a reply arrives, AgentSend inspects the In-Reply-To and References headers to identify which existing thread the message belongs to. If a match is found, the message is appended to that thread. If no match is found, a new thread is created.
You can also explicitly associate a message with a thread by including the threadId field when sending. This is useful when you are initiating a follow-up from your agent's side and want to keep it grouped with a prior conversation, even if the recipient starts a fresh reply chain.
Always read the threadId from incoming webhook payloads and pass it back when replying. This guarantees correct grouping even when recipients change their subject line.
Matching algorithm
- Check the
In-Reply-Toheader against all known message IDs in the inbox. - If no match, scan the
Referencesheader list from right (most recent) to left. - If still no match, create a new thread for this message.
Thread Properties
Each thread object has the following fields:
| Property | Type | Description |
|---|---|---|
id |
string | Unique identifier for the thread. |
inboxId |
string | The inbox this thread belongs to. |
subject |
string | Subject line of the first message in the thread. |
messageCount |
integer | Total number of messages in this thread. |
lastMessageAt |
string (ISO 8601) | Timestamp of the most recent message. |
createdAt |
string (ISO 8601) | Timestamp when the thread was first created. |
Listing Threads
Retrieve all threads for an inbox using a GET request. Results are ordered by lastMessageAt descending so the most active conversations appear first.
// GET /inboxes/{id}/threads?limit=20&offset=0 const res = await fetch( `https://api.agentsend.io/inboxes/${inboxId}/threads?limit=20&offset=0`, { headers: { "x-api-key": process.env.AGENTSEND_API_KEY } } ); const { data, total } = await res.json(); for (const thread of data) { console.log(thread.id, thread.subject, thread.messageCount); }
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 20 | Maximum number of threads to return. Max 100. |
offset |
integer | 0 | Number of threads to skip for pagination. |
Getting Thread Messages
Fetch every message in a thread in chronological order. This gives your agent the complete conversation history it needs to compose a contextually aware reply.
// GET /threads/{id}/messages const res = await fetch( `https://api.agentsend.io/threads/${threadId}/messages`, { headers: { "x-api-key": process.env.AGENTSEND_API_KEY } } ); const { data } = await res.json(); // Build a conversation history for your LLM const history = data.map(msg => ({ role: msg.direction === "outbound" ? "assistant" : "user", content: msg.bodyText, })); console.log(`Loaded ${history.length} messages from thread`);
Messages within a thread are returned in ascending chronological order (sentAt oldest first). This matches the natural order expected by most LLM conversation APIs.
Replying in a Thread
To continue an existing conversation, include the threadId when sending a message. AgentSend will automatically set the correct In-Reply-To and References headers so the reply appears in the recipient's email client as part of the same conversation.
// POST /inboxes/{id}/messages — reply within an existing thread await fetch(`https://api.agentsend.io/inboxes/${inboxId}/messages`, { method: "POST", headers: { "x-api-key": process.env.AGENTSEND_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ to: ["customer@example.com"], subject: "Re: Your support request", bodyText: "Thanks for reaching out! Here is the information you requested...", threadId: "thrd_abc123", // ties this message to the existing conversation }), });
If you omit threadId, the outbound message will start a new thread even if you use the same subject line. Always pass threadId when continuing a conversation.
Use Cases
Threads unlock a set of workflows that require memory across multiple email exchanges.
- Customer support — Load the full thread before generating a reply so your support agent has all prior context. Assign threads to human agents only when needed.
- Sales follow-ups — Track multi-touch outreach sequences. Know when a prospect last replied and how many messages are in a chain before escalating.
- Scheduling & coordination — Run back-and-forth negotiations (meeting times, contract terms) inside a single thread so the conversation history is always accessible.
- Research collection — Send an initial query, collect responses, and follow up with clarifying questions — all within one organized thread per contact.