const PAGE_LIMIT = 6;
const page = req.query.page >= 1 ? req.query.page : 1;
const threads = await nylas.threads.list({
in: "inbox",
unread: true,
view: "expanded",
limit: PAGE_LIMIT + 1,
offset: (page - 1) * PAGE_LIMIT
});
You might be wondering what limit, offset, and the page references in this example are. When users view their inbox, they’re most likely looking for their recent messages. If the user has hundreds, or thousands of unread messages in their inbox, they would have to wait for all of those messages to transfer from the API server before they can see their mail, even if they only want to look at the first one. This would create a poor user experience to say the least.
So, to keep apps performant and more useful, it’s a good idea to limit downloads to the smallest amount of information that’s useful to the user. One technique that can be used to accomplish this is pagination: breaking apart the total dataset into chunks that are of a more manageable size. You can think of paging just like pages in a book, you wouldn’t want one giant sheet of paper with all the words on it, so they’re split up over a series of pages for easier digestion.
The limit is the maximum number of thread objects that should be returned. The offset is how far down the list of threads we want to pull from. So, for example, let’s say we want the user to see 6 threads at a time. The first request would have an offset of 0 and a limit of 6. When the user clicks to the next page, the app would update the offset to 6 since it has already displayed the first group of threads. The limit would remain 6 to continue displaying the same number of messages.
An important aspect of pagination is making sure the user can actually navigate to the next page! However, we only want to display the next page button if there are additional threads to display, so the app needs to make a second request to the Nylas Email API to determine if there is another page to display. If so, the next page button is displayed.
Now, we have everything necessary to display a page of threads to the user!
res.send({
hasPrevious: page > 1,
hasNext: threads.length > PAGE_LIMIT,
threads: threads.slice(0, PAGE_LIMIT).map(thread => ({
id: thread.id,
subject: thread.subject,
from: thread.from,
date: thread.lastMessageTimestamp,
snippet: thread.snippet,
unread: thread.unread,
hasAttachments: thread.hasAttachments
}))
});
Display an Entire Email Conversation
Now that the user has a list of their threads, they’re probably going to want to read some of them. When the user clicks on one of the threads that was retrieved in the previous section, the thread ID is used to redirect them to that individual thread’s route. From there, we can use the Nylas SDK to get the contents of the individual messages. Inbox Zero starts by fetching the full thread data:
const id = req.params.id;
const thread = await nylas.threads.find(id, null, { view: "expanded" });
Line two of this example shows how to request a specific email thread using the expanded view query parameter. With a normal view, Nylas returns a message_ids attribute that lists the ids for all of the messages that are a part of the conversation. When you request an expanded view, Nylas replaces this attribute with a messages attribute that provides a list of message objects that include everything except for the email body.
This makes it possible for us to get the message’s subject, snippet, participants, and more without needing to make separate requests to the Nylas Email API, and it’s helpful in this situation because we don’t necessarily care about displaying all of the details for each of the historical messages in the conversation unless the reader clicks to expand one. When it’s time to render the individual email messages, the app makes a request to the Nylas Messages endpoint to get the entire message object.
const messages = await nylas.messages.list({ thread_id: id, view: "expanded" });
One last feature we want the user to have is the ability to navigate between email threads, so we should create previous and next buttons to do exactly that. To accomplish this, the Inbox Zero app gets the IDs for the two chronological email threads by making a request to the Nylas Threads endpoint using filters that are based on the timestamp for the current thread. Once it has identified the appropriate threads, it creates two buttons that let the user navigate to the route for the specific thread IDs.
const [previousThreadIds, nextThreadIds] = await Promise.all([
nylas.threads.list({
in: "inbox",
unread: true,
last_message_after: thread.lastMessageTimestamp,
limit: 1000,
view: "ids"
}),
nylas.threads.list({
in: "inbox",
unread: true,
last_message_before: thread.lastMessageTimestamp,
limit: 1,
view: "ids"
})
]);
const previousThreadId = previousThreadIds.length > 0 ? previousThreadIds[previousThreadIds.length - 1] : null;
const nextThreadId = nextThreadIds.length > 0 ? nextThreadIds[0] : null;
The very last step is to send all of the data to be rendered in the front end.
return res.status(200).json({
id,
subject: thread.subject,
from: threadFrom,
messages: messages.map(simplifyMessage),
date: thread.lastMessageTimestamp,
snippet: thread.snippet,
hasAttachments: thread.hasAttachments,
unread: thread.unread,
senderUnread,
previousThreadId,
nextThreadId
});
View Download File Attachments
Of course, no inbox app would be complete without the ability to download file attachments. Each of the message objects has an attribute named files that contains a list of IDs that represent file attachments. The Inbox Zero app uses these IDs to make requests to the Nylas Files endpoint to get the file name for display, and to provide the files for the user to download if they choose.
const id = req.query.id;
const file = await req.nylas.files.find(id);
const fileData = await file.download();
res.send(fileData.body);
Extend Your Email Functionality With Nylas
This article outlines what it takes to build a functional threaded view of a user’s email inbox, but why stop there? With Nylas, developers also unlock the full capability of users’ calendars and contact books too, and these combined with email functionality allow you to turn your app into a scheduling powerhouse. With Nylas, you can build deeply contextual experiences that let your users access their email, calendar, and contacts seamlessly from within your app. Get started today!