Threads group related messages into conversations. When a new message arrives, Nuntly automatically determines whether it belongs to an existing thread or starts a new one.
Threading algorithm
Nuntly uses the following logic to match incoming messages to threads, evaluated in order:
- In-Reply-To header. If the incoming message has an
In-Reply-To header, Nuntly looks for a message in the same inbox with a matching Message-ID. If found, the new message joins that thread.
- References header. If no match is found via
In-Reply-To, Nuntly checks the References header for any matching Message-ID in the same inbox.
- Subject matching. If no header match is found, Nuntly normalizes the subject line (stripping prefixes like
Re: and Fwd:) and looks for a thread in the same inbox with a matching normalized subject that had activity within the last 7 days.
- New thread. If none of the above produce a match, a new thread is created.
List threads
You can list threads for a specific inbox. Filter by read status or spam flag.
import { Nuntly } from '@nuntly/sdk';
const nuntly = new Nuntly({
apiKey: process.env.NUNTLY_API_KEY,
});
// List all threads in an inbox
const threads = await nuntly.inboxes.listThreads('ibx_01kabn43yqyxn2bx4ve84mczd3');
// Filter unread threads
const unreadThreads = await nuntly.inboxes.listThreads('ibx_01kabn43yqyxn2bx4ve84mczd3', {
isRead: false,
});
// Filter spam threads
const spamThreads = await nuntly.inboxes.listThreads('ibx_01kabn43yqyxn2bx4ve84mczd3', {
isSpam: true,
});
Available filters
| Parameter | Description |
|---|
isRead | Filter by read status (true or false). |
isSpam | Filter by spam flag (true or false). |
cursor | Cursor for pagination. |
limit | Maximum number of results to return (1-30, default 30). |
Thread fields
| Field | Description |
|---|
id | The unique thread identifier. |
domainName | The domain name. |
inboxId | The inbox this thread belongs to. |
subject | The original subject line. |
lastMessageAt | The timestamp of the most recent message. |
messageCount | The number of messages in the thread. |
isRead | Whether the thread has been read. |
isSpam | Whether the thread is marked as spam. |
agentId | The AI agent identifier, or null. |
Retrieve a thread
Get the full details of a single thread. Retrieving a thread automatically marks it as read.
const thread = await nuntly.threads.retrieve('thr_01kabn43yqyxn2bx4ve84mczd3');
console.log('Subject:', thread.data.subject);
console.log('Messages:', thread.data.messageCount);
console.log('Last activity:', thread.data.lastMessageAt);
Retrieving a thread automatically sets isRead to true. If you need to mark it as unread again, use the update endpoint.
List thread messages
Retrieve the messages in a thread. Messages are returned in chronological order (oldest first).
const messages = await nuntly.threads.listMessages('thr_01kabn43yqyxn2bx4ve84mczd3');
for (const message of messages.data) {
const direction = message.direction === 'received' ? 'Received' : 'Sent';
console.log(`[${direction}] ${message.fromAddress}: ${message.subject}`);
}
Update a thread
Update thread properties such as read status, spam flag, or agent assignment.
// Mark as unread
await nuntly.threads.update('thr_01kabn43yqyxn2bx4ve84mczd3', {
isRead: false,
});
// Mark as spam
await nuntly.threads.update('thr_01kabn43yqyxn2bx4ve84mczd3', {
isSpam: true,
});
// Assign an AI agent
await nuntly.threads.update('thr_01kabn43yqyxn2bx4ve84mczd3', {
agentId: 'my-support-agent',
});
Update request fields
| Field | Description |
|---|
isRead | Set to true or false to mark as read or unread. |
isSpam | Set to true or false to mark as spam or not spam. |
agentId | The AI agent identifier. Set to null to remove the agent. |
Next steps