Skip to content

Commit 3891404

Browse files
committed
fix: resolve folder filtering bug and add inFolderOrLabel parameter
BREAKING CHANGE: Fixed folder filtering behavior in ListMessagesQueryParams and ListThreadsQueryParams - Fix bug where inFolder parameter only used the last folder ID instead of the first - Add new inFolderOrLabel parameter for single folder/label ID filtering - Deprecate inFolder parameter with backwards compatibility (uses first item only) - Add precedence logic: inFolderOrLabel takes priority over inFolder when both provided - Improve API ergonomics and accuracy (supports both folder and label IDs) Examples and Documentation: - Enhance MessagesExample.java and KotlinMessagesExample.kt with folder filtering demos - Add new standalone FolderFilteringExample.kt with focused demonstration - Update examples/README.md with comprehensive documentation - Add migration guide and usage patterns for new parameter - Document Google-specific requirements (folder IDs vs names) Tests and Quality: - All existing tests pass with backwards compatibility maintained - New functionality preserves API contract while fixing underlying bug - Proper deprecation warnings guide users to new parameter This resolves the customer-reported issue where multiple folder IDs in inFolder parameter resulted in inconsistent behavior. The new inFolderOrLabel parameter provides a clear, explicit API that matches the Nylas API specification.
1 parent 7406677 commit 3891404

File tree

9 files changed

+447
-46
lines changed

9 files changed

+447
-46
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99
* Support for `raw_mime` field in `Message` model to access Base64url-encoded message data
1010
* Support for query parameters in `Messages.find()` method to specify fields like `include_tracking_options` and `raw_mime`
1111
* Added `Builder` pattern to `FindMessageQueryParams` for consistency with other query parameter classes
12+
* Added new `inFolderOrLabel` parameter to `ListThreadsQueryParams` and `ListMessagesQueryParams` for filtering by folder or label ID
13+
14+
### Fixed
15+
* Fixed issue where `inFolder` parameter in `ListThreadsQueryParams` and `ListMessagesQueryParams` only used the last item in the list. The API only accepts a single folder or label ID, so the parameter has been changed to use only the first folder ID from the list for backwards compatibility.
16+
17+
### Deprecated
18+
* Deprecated `inFolder` parameter in `ListThreadsQueryParams` and `ListMessagesQueryParams` in favor of the new `inFolderOrLabel` parameter. The deprecated parameter will continue to work but only the first folder ID will be used if multiple are provided.
1219

1320
## [2.9.0] - Release 2025-05-27
1421

examples/README.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ The `MessagesExample` and `KotlinMessagesExample` demonstrate how to use the new
1313
- Retrieve raw MIME content for messages
1414
- Use the new `FindMessageQueryParams` to specify fields when finding specific messages
1515
- Compare different field options and their effects on returned data
16+
- **NEW**: Demonstrate folder/label filtering with the new `inFolderOrLabel` parameter
17+
- **NEW**: Show backwards compatibility with the deprecated `inFolder` parameter
18+
- **NEW**: Illustrate the precedence behavior when both parameters are used
19+
20+
### Folder Filtering Example
21+
22+
The `FolderFilteringExample` is a focused demonstration of the FIXED folder/label filtering functionality:
23+
24+
- Shows the NEW `inFolderOrLabel` parameter usage
25+
- Demonstrates backwards compatibility with the deprecated `inFolder` parameter
26+
- Explains the bug fix (previously used last folder ID, now uses first)
27+
- Illustrates precedence behavior between old and new parameters
28+
- Provides a clear migration guide for existing code
1629

1730
### Events Example
1831

@@ -42,7 +55,7 @@ cp .env.example .env
4255
```
4356

4457
Edit the `.env` file with your details:
45-
```
58+
```bash
4659
# Get your API key from the Nylas Dashboard
4760
NYLAS_API_KEY=your_api_key_here
4861

@@ -67,6 +80,11 @@ Run Kotlin Messages example:
6780
./gradlew :examples:run -PmainClass=com.nylas.examples.KotlinMessagesExampleKt
6881
```
6982

83+
Run Folder Filtering example:
84+
```bash
85+
./gradlew :examples:run -PmainClass=com.nylas.examples.FolderFilteringExampleKt
86+
```
87+
7088
Run Java Events example:
7189
```bash
7290
./gradlew :examples:run -PmainClass=com.nylas.examples.EventsExample
@@ -128,6 +146,7 @@ examples/
128146
└── kotlin/ # Kotlin examples
129147
└── com/nylas/examples/
130148
├── KotlinMessagesExample.kt # NEW: Message features demo
149+
├── FolderFilteringExample.kt # NEW: Folder filtering fix demo
131150
└── KotlinNotetakerExample.kt # Notetaker API demo
132151
```
133152

@@ -147,6 +166,13 @@ The Messages examples showcase the following new features added to the Nylas SDK
147166
- `Messages.find()` now accepts `FindMessageQueryParams` to specify which fields to include
148167
- Both list and find operations support the new field options
149168

169+
4. **Fixed folder/label filtering (BREAKING CHANGE FIX):**
170+
- **NEW**: `inFolderOrLabel` parameter for filtering by a single folder or label ID
171+
- **DEPRECATED**: `inFolder` parameter (backwards compatible, only uses first folder ID)
172+
- The fix resolves the bug where only the last folder ID was used from the list
173+
- Demonstrates proper API usage for Google (requires folder IDs, not names)
174+
- Shows precedence behavior when both parameters are provided
175+
150176
## Additional Information
151177

152-
For more information about the Nylas API, refer to the [Nylas API documentation](https://developer.nylas.com/).
178+
For more information about the Nylas API, refer to the [Nylas API documentation](https://developer.nylas.com/).

examples/src/main/java/com/nylas/examples/MessagesExample.java

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
* - tracking_options property in Message model
2828
* - raw_mime property in Message model
2929
* - FindMessageQueryParams with fields parameter
30+
* - NEW: Fixed folder/label filtering with inFolderOrLabel parameter
31+
* - NEW: Backwards compatibility with deprecated inFolder parameter
32+
* - NEW: Demonstrates precedence behavior between old and new parameters
3033
*/
3134
public class MessagesExample {
3235
public static void main(String[] args) {
@@ -132,7 +135,10 @@ private static void runMessagesExample(NylasClient nylas, Map<String, String> co
132135
// 4. List messages with raw_mime field (new feature)
133136
demonstrateRawMimeListing(nylas, grantId);
134137

135-
// 5. Find a specific message with different field options
138+
// 5. Demonstrate folder/label filtering (FIXED BUG - new inFolderOrLabel parameter)
139+
demonstrateFolderLabelFiltering(nylas, grantId);
140+
141+
// 6. Find a specific message with different field options
136142
demonstrateMessageFinding(nylas, grantId);
137143
}
138144

@@ -242,8 +248,68 @@ private static void demonstrateRawMimeListing(NylasClient nylas, String grantId)
242248
}
243249
}
244250

251+
private static void demonstrateFolderLabelFiltering(NylasClient nylas, String grantId) throws NylasApiError, NylasSdkTimeoutError {
252+
System.out.println("📂 5. Demonstrating folder/label filtering (FIXED BUG - new inFolderOrLabel parameter):");
253+
254+
// Demonstrate the NEW inFolderOrLabel parameter
255+
System.out.println("\n ✅ Using the NEW inFolderOrLabel parameter (recommended):");
256+
ListMessagesQueryParams newQueryParams = new ListMessagesQueryParams.Builder()
257+
.limit(3)
258+
.inFolderOrLabel("INBOX") // Use folder ID or label ID
259+
.build();
260+
261+
ListResponse<Message> newMessages = nylas.messages().list(grantId, newQueryParams);
262+
263+
System.out.println(" Found " + newMessages.getData().size() + " messages using inFolderOrLabel parameter");
264+
for (Message message : newMessages.getData()) {
265+
System.out.println(" - ID: " + message.getId());
266+
System.out.println(" Subject: " + (message.getSubject() != null ? message.getSubject() : "No subject"));
267+
System.out.println(" Folders: " + (message.getFolders() != null ? String.join(", ", message.getFolders()) : "None"));
268+
System.out.println();
269+
}
270+
271+
// Demonstrate the DEPRECATED inFolder parameter (backwards compatibility)
272+
System.out.println("\n ⚠️ Using the DEPRECATED inFolder parameter (backwards compatible):");
273+
@SuppressWarnings("deprecation")
274+
ListMessagesQueryParams deprecatedQueryParams = new ListMessagesQueryParams.Builder()
275+
.limit(3)
276+
.inFolder(Arrays.asList("INBOX", "SENT")) // Only first folder ID will be used
277+
.build();
278+
279+
ListResponse<Message> deprecatedMessages = nylas.messages().list(grantId, deprecatedQueryParams);
280+
281+
System.out.println(" Found " + deprecatedMessages.getData().size() + " messages using deprecated inFolder parameter");
282+
System.out.println(" Note: Only the first folder ID ('INBOX') was used, 'SENT' was ignored");
283+
for (Message message : deprecatedMessages.getData()) {
284+
System.out.println(" - ID: " + message.getId());
285+
System.out.println(" Subject: " + (message.getSubject() != null ? message.getSubject() : "No subject"));
286+
System.out.println(" Folders: " + (message.getFolders() != null ? String.join(", ", message.getFolders()) : "None"));
287+
System.out.println();
288+
}
289+
290+
// Demonstrate precedence: inFolderOrLabel takes priority over inFolder
291+
System.out.println("\n 🏆 Demonstrating precedence: inFolderOrLabel overrides inFolder:");
292+
@SuppressWarnings("deprecation")
293+
ListMessagesQueryParams precedenceQueryParams = new ListMessagesQueryParams.Builder()
294+
.limit(2)
295+
.inFolder(Arrays.asList("SENT")) // This will be ignored
296+
.inFolderOrLabel("INBOX") // This takes precedence
297+
.build();
298+
299+
ListResponse<Message> precedenceMessages = nylas.messages().list(grantId, precedenceQueryParams);
300+
301+
System.out.println(" Found " + precedenceMessages.getData().size() + " messages");
302+
System.out.println(" Used 'INBOX' from inFolderOrLabel, ignored 'SENT' from inFolder");
303+
for (Message message : precedenceMessages.getData()) {
304+
System.out.println(" - ID: " + message.getId());
305+
System.out.println(" Subject: " + (message.getSubject() != null ? message.getSubject() : "No subject"));
306+
System.out.println(" Folders: " + (message.getFolders() != null ? String.join(", ", message.getFolders()) : "None"));
307+
System.out.println();
308+
}
309+
}
310+
245311
private static void demonstrateMessageFinding(NylasClient nylas, String grantId) throws NylasApiError, NylasSdkTimeoutError {
246-
System.out.println("🔍 5. Finding specific messages with query parameters (NEW FEATURE):");
312+
System.out.println("🔍 6. Finding specific messages with query parameters (NEW FEATURE):");
247313

248314
// First get a message ID to work with
249315
ListMessagesQueryParams listParams = new ListMessagesQueryParams.Builder()
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.nylas.examples
2+
3+
import com.nylas.NylasClient
4+
import com.nylas.models.*
5+
import okhttp3.OkHttpClient
6+
7+
/**
8+
* Simple example demonstrating the FIXED folder/label filtering in Nylas Java/Kotlin SDK.
9+
*
10+
* This example shows:
11+
* - The NEW inFolderOrLabel parameter for filtering by folder or label ID
12+
* - The DEPRECATED inFolder parameter (backwards compatible)
13+
* - How the fix resolves the bug where only the last folder ID was used
14+
* - Precedence behavior when both parameters are provided
15+
*/
16+
fun main() {
17+
// Initialize the Nylas client
18+
val nylas = NylasClient(
19+
"your_api_key_here",
20+
OkHttpClient.Builder(),
21+
"https://api.us.nylas.com"
22+
)
23+
24+
val grantId = "your_grant_id_here"
25+
26+
println("🔧 Demonstrating FIXED folder/label filtering in Nylas SDK\n")
27+
28+
// ✅ NEW WAY: Using inFolderOrLabel (recommended)
29+
println("✅ NEW: Using inFolderOrLabel parameter")
30+
val newParams = ListMessagesQueryParams.Builder()
31+
.limit(5)
32+
.inFolderOrLabel("INBOX") // Single folder or label ID
33+
.build()
34+
35+
println(" Query: inFolderOrLabel = 'INBOX'")
36+
println(" Result: Will filter messages in INBOX folder/label\n")
37+
38+
// ⚠️ OLD WAY: Using deprecated inFolder (backwards compatible)
39+
println("⚠️ DEPRECATED: Using inFolder parameter (backwards compatible)")
40+
@Suppress("DEPRECATION")
41+
val oldParams = ListMessagesQueryParams.Builder()
42+
.limit(5)
43+
.inFolder(listOf("INBOX", "SENT", "DRAFTS")) // Multiple folder IDs
44+
.build()
45+
46+
println(" Query: inFolder = ['INBOX', 'SENT', 'DRAFTS']")
47+
println(" Result: Only 'INBOX' (first item) will be used, others ignored")
48+
println(" Note: This fixes the bug where only the LAST item was used\n")
49+
50+
// 🏆 PRECEDENCE: inFolderOrLabel overrides inFolder
51+
println("🏆 PRECEDENCE: inFolderOrLabel takes priority")
52+
@Suppress("DEPRECATION")
53+
val precedenceParams = ListMessagesQueryParams.Builder()
54+
.limit(5)
55+
.inFolder(listOf("SENT")) // This will be ignored
56+
.inFolderOrLabel("INBOX") // This takes precedence
57+
.build()
58+
59+
println(" Query: inFolder = ['SENT'], inFolderOrLabel = 'INBOX'")
60+
println(" Result: 'INBOX' from inFolderOrLabel is used, 'SENT' is ignored\n")
61+
62+
// 📝 MIGRATION GUIDE
63+
println("📝 MIGRATION GUIDE:")
64+
println(" Before (buggy): inFolder(listOf('folder1', 'folder2')) -> used 'folder2' (last)")
65+
println(" After (fixed): inFolder(listOf('folder1', 'folder2')) -> uses 'folder1' (first)")
66+
println(" Recommended: inFolderOrLabel('folder1') -> uses 'folder1' (explicit)")
67+
println("\n 💡 For Google: Use folder IDs, not folder names!")
68+
69+
println("\n✨ The inFolderOrLabel parameter provides:")
70+
println(" - Clear, explicit API (no ambiguity about which folder is used)")
71+
println(" - Better Kotlin ergonomics (no backticks needed)")
72+
println(" - Accurate naming (works with both folders and labels)")
73+
println(" - Backwards compatibility (deprecated inFolder still works)")
74+
}

examples/src/main/kotlin/com/nylas/examples/KotlinMessagesExample.kt

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import kotlin.system.exitProcess
1414
* - tracking_options property in Message model
1515
* - raw_mime property in Message model
1616
* - FindMessageQueryParams with fields parameter
17+
* - NEW: Fixed folder/label filtering with inFolderOrLabel parameter
18+
* - NEW: Backwards compatibility with deprecated inFolder parameter
19+
* - NEW: Demonstrates precedence behavior between old and new parameters
1720
*/
1821
fun main() {
1922
try {
@@ -115,7 +118,10 @@ private fun runMessagesExample(nylas: NylasClient, config: Map<String, String>)
115118
// 4. List messages with raw_mime field (new feature)
116119
demonstrateRawMimeListing(nylas, grantId)
117120

118-
// 5. Find a specific message with different field options
121+
// 5. Demonstrate folder/label filtering (FIXED BUG - new inFolderOrLabel parameter)
122+
demonstrateFolderLabelFiltering(nylas, grantId)
123+
124+
// 6. Find a specific message with different field options
119125
demonstrateMessageFinding(nylas, grantId)
120126
}
121127

@@ -220,8 +226,68 @@ private fun demonstrateRawMimeListing(nylas: NylasClient, grantId: String) {
220226
}
221227
}
222228

229+
private fun demonstrateFolderLabelFiltering(nylas: NylasClient, grantId: String) {
230+
println("📂 5. Demonstrating folder/label filtering (FIXED BUG - new inFolderOrLabel parameter):")
231+
232+
// Demonstrate the NEW inFolderOrLabel parameter
233+
println("\n ✅ Using the NEW inFolderOrLabel parameter (recommended):")
234+
val newQueryParams = ListMessagesQueryParams.Builder()
235+
.limit(3)
236+
.inFolderOrLabel("INBOX") // Use folder ID or label ID
237+
.build()
238+
239+
val newMessages = nylas.messages().list(grantId, newQueryParams)
240+
241+
println(" Found ${newMessages.data.size} messages using inFolderOrLabel parameter")
242+
newMessages.data.forEach { message ->
243+
println(" - ID: ${message.id}")
244+
println(" Subject: ${message.subject ?: "No subject"}")
245+
println(" Folders: ${message.folders?.joinToString(", ") ?: "None"}")
246+
println()
247+
}
248+
249+
// Demonstrate the DEPRECATED inFolder parameter (backwards compatibility)
250+
println("\n ⚠️ Using the DEPRECATED inFolder parameter (backwards compatible):")
251+
@Suppress("DEPRECATION")
252+
val deprecatedQueryParams = ListMessagesQueryParams.Builder()
253+
.limit(3)
254+
.inFolder(listOf("INBOX", "SENT")) // Only first folder ID will be used
255+
.build()
256+
257+
val deprecatedMessages = nylas.messages().list(grantId, deprecatedQueryParams)
258+
259+
println(" Found ${deprecatedMessages.data.size} messages using deprecated inFolder parameter")
260+
println(" Note: Only the first folder ID ('INBOX') was used, 'SENT' was ignored")
261+
deprecatedMessages.data.forEach { message ->
262+
println(" - ID: ${message.id}")
263+
println(" Subject: ${message.subject ?: "No subject"}")
264+
println(" Folders: ${message.folders?.joinToString(", ") ?: "None"}")
265+
println()
266+
}
267+
268+
// Demonstrate precedence: inFolderOrLabel takes priority over inFolder
269+
println("\n 🏆 Demonstrating precedence: inFolderOrLabel overrides inFolder:")
270+
@Suppress("DEPRECATION")
271+
val precedenceQueryParams = ListMessagesQueryParams.Builder()
272+
.limit(2)
273+
.inFolder(listOf("SENT")) // This will be ignored
274+
.inFolderOrLabel("INBOX") // This takes precedence
275+
.build()
276+
277+
val precedenceMessages = nylas.messages().list(grantId, precedenceQueryParams)
278+
279+
println(" Found ${precedenceMessages.data.size} messages")
280+
println(" Used 'INBOX' from inFolderOrLabel, ignored 'SENT' from inFolder")
281+
precedenceMessages.data.forEach { message ->
282+
println(" - ID: ${message.id}")
283+
println(" Subject: ${message.subject ?: "No subject"}")
284+
println(" Folders: ${message.folders?.joinToString(", ") ?: "None"}")
285+
println()
286+
}
287+
}
288+
223289
private fun demonstrateMessageFinding(nylas: NylasClient, grantId: String) {
224-
println("🔍 5. Finding specific messages with query parameters (NEW FEATURE):")
290+
println("🔍 6. Finding specific messages with query parameters (NEW FEATURE):")
225291

226292
// First get a message ID to work with
227293
val listParams = ListMessagesQueryParams.Builder()

0 commit comments

Comments
 (0)