0
# Folder Operations
1
2
This document covers folder management, message storage operations, hierarchical navigation, and folder-based message manipulation in the Jakarta Mail API.
3
4
## Folder Management
5
6
The Folder class represents a container for messages with support for hierarchical organization and various access modes.
7
8
### Folder Access and Navigation
9
10
```java { .api }
11
abstract class Folder implements AutoCloseable {
12
public abstract String getName() throws MessagingException;
13
public abstract String getFullName() throws MessagingException;
14
public URLName getURLName() throws MessagingException;
15
public abstract Folder getParent() throws MessagingException;
16
public abstract boolean exists() throws MessagingException;
17
}
18
```
19
20
### Folder Hierarchy
21
22
```java { .api }
23
abstract class Folder {
24
public abstract Folder[] list() throws MessagingException;
25
public abstract Folder[] list(String pattern) throws MessagingException;
26
public abstract Folder[] listSubscribed() throws MessagingException;
27
public abstract Folder[] listSubscribed(String pattern) throws MessagingException;
28
29
public abstract char getSeparator() throws MessagingException;
30
public abstract int getType() throws MessagingException;
31
32
public abstract boolean create(int type) throws MessagingException;
33
public abstract boolean delete(boolean recurse) throws MessagingException;
34
public abstract boolean renameTo(Folder f) throws MessagingException;
35
}
36
```
37
38
**Folder Types:**
39
- `HOLDS_MESSAGES` (0x01) - Can contain messages
40
- `HOLDS_FOLDERS` (0x02) - Can contain subfolders
41
42
**Access Modes:**
43
- `READ_ONLY` (1) - Read-only access
44
- `READ_WRITE` (2) - Read-write access
45
46
### Folder Lifecycle
47
48
```java { .api }
49
abstract class Folder {
50
public abstract void open(int mode) throws MessagingException;
51
public abstract void close() throws MessagingException;
52
public abstract void close(boolean expunge) throws MessagingException;
53
public abstract boolean isOpen();
54
55
public Store getStore();
56
public int getMode();
57
public String toString();
58
}
59
```
60
61
### Usage Example
62
63
```java
64
Store store = session.getStore("imap");
65
store.connect("imap.example.com", "username", "password");
66
67
// Navigate folder hierarchy
68
Folder defaultFolder = store.getDefaultFolder();
69
Folder[] folders = defaultFolder.list("*");
70
71
// Work with INBOX
72
Folder inbox = store.getFolder("INBOX");
73
if (inbox.exists()) {
74
inbox.open(Folder.READ_WRITE);
75
76
// Folder operations here
77
78
inbox.close(false); // Don't expunge on close
79
}
80
81
// Create new folder
82
Folder customFolder = store.getFolder("My Messages");
83
if (!customFolder.exists()) {
84
customFolder.create(Folder.HOLDS_MESSAGES);
85
}
86
```
87
88
## Message Access and Counting
89
90
### Message Retrieval
91
92
```java { .api }
93
abstract class Folder {
94
public abstract int getMessageCount() throws MessagingException;
95
public abstract int getNewMessageCount() throws MessagingException;
96
public abstract int getUnreadMessageCount() throws MessagingException;
97
public abstract int getDeletedMessageCount() throws MessagingException;
98
99
public abstract Message getMessage(int msgnum) throws MessagingException;
100
public abstract Message[] getMessages() throws MessagingException;
101
public abstract Message[] getMessages(int start, int end) throws MessagingException;
102
public abstract Message[] getMessages(int[] msgnums) throws MessagingException;
103
}
104
```
105
106
### Message Properties
107
108
```java { .api }
109
abstract class Folder {
110
public abstract boolean hasNewMessages() throws MessagingException;
111
public abstract Flags getPermanentFlags() throws MessagingException;
112
113
public void fetch(Message[] msgs, FetchProfile fp) throws MessagingException;
114
public void setFlags(Message[] msgs, Flags flag, boolean value) throws MessagingException;
115
public void setFlags(int start, int end, Flags flag, boolean value) throws MessagingException;
116
public void setFlags(int[] msgnums, Flags flag, boolean value) throws MessagingException;
117
}
118
```
119
120
### Usage Examples
121
122
```java
123
folder.open(Folder.READ_ONLY);
124
125
// Get message counts
126
int totalMessages = folder.getMessageCount();
127
int newMessages = folder.getNewMessageCount();
128
int unreadMessages = folder.getUnreadMessageCount();
129
130
System.out.println("Total: " + totalMessages + ", New: " + newMessages + ", Unread: " + unreadMessages);
131
132
// Get all messages
133
Message[] messages = folder.getMessages();
134
135
// Get recent messages (last 10)
136
int count = folder.getMessageCount();
137
Message[] recent = folder.getMessages(Math.max(1, count - 9), count);
138
139
// Mark messages as read
140
folder.setFlags(messages, new Flags(Flags.Flag.SEEN), true);
141
```
142
143
## Message Storage Operations
144
145
### Adding Messages
146
147
```java { .api }
148
abstract class Folder {
149
public abstract void appendMessages(Message[] msgs) throws MessagingException;
150
151
public void copyMessages(Message[] msgs, Folder folder) throws MessagingException;
152
}
153
```
154
155
### Message Deletion
156
157
```java { .api }
158
abstract class Folder {
159
public abstract Message[] expunge() throws MessagingException;
160
public Message[] expunge(Message[] msgs) throws MessagingException;
161
}
162
```
163
164
### Usage Examples
165
166
```java
167
// Append new messages to folder
168
Message[] newMessages = createMessages(); // Your message creation logic
169
folder.appendMessages(newMessages);
170
171
// Copy messages to another folder
172
Folder sentFolder = store.getFolder("Sent");
173
sentFolder.open(Folder.READ_WRITE);
174
folder.copyMessages(messages, sentFolder);
175
176
// Delete messages (mark as deleted, then expunge)
177
folder.setFlags(messages, new Flags(Flags.Flag.DELETED), true);
178
Message[] expunged = folder.expunge(); // Permanently removes deleted messages
179
```
180
181
## UID Support
182
183
The UIDFolder interface provides support for message UIDs (Unique Identifiers).
184
185
```java { .api }
186
interface UIDFolder {
187
public long getUID(Message message) throws MessagingException;
188
public Message getMessageByUID(long uid) throws MessagingException;
189
public Message[] getMessagesByUID(long start, long end) throws MessagingException;
190
public Message[] getMessagesByUID(long[] uids) throws MessagingException;
191
192
public long getUIDValidity() throws MessagingException;
193
public long getUIDNext() throws MessagingException;
194
195
static class FetchProfileItem extends FetchProfile.Item {
196
static final FetchProfileItem UID;
197
}
198
}
199
```
200
201
### UID Usage Example
202
203
```java
204
if (folder instanceof UIDFolder) {
205
UIDFolder uidFolder = (UIDFolder) folder;
206
207
// Get UID for a message
208
long uid = uidFolder.getUID(message);
209
210
// Retrieve message by UID
211
Message msgByUID = uidFolder.getMessageByUID(uid);
212
213
// Get UID validity (changes when folder is recreated)
214
long uidValidity = uidFolder.getUIDValidity();
215
216
// Get messages by UID range
217
Message[] msgs = uidFolder.getMessagesByUID(100L, 200L);
218
}
219
```
220
221
## Quota Management
222
223
The Quota class provides support for storage quotas on folders and stores.
224
225
```java { .api }
226
class Quota {
227
public String quotaRoot;
228
public Resource[] resources;
229
230
public Quota(String quotaRoot);
231
232
static class Resource {
233
public String name;
234
public long usage;
235
public long limit;
236
237
public Resource(String name, long usage, long limit);
238
}
239
}
240
241
interface QuotaAwareStore {
242
public Quota[] getQuota(String quotaRoot) throws MessagingException;
243
public void setQuota(Quota quota) throws MessagingException;
244
}
245
```
246
247
### Quota Usage Example
248
249
```java
250
if (store instanceof QuotaAwareStore) {
251
QuotaAwareStore quotaStore = (QuotaAwareStore) store;
252
253
// Get quota information
254
Quota[] quotas = quotaStore.getQuota("INBOX");
255
for (Quota quota : quotas) {
256
for (Quota.Resource resource : quota.resources) {
257
System.out.println("Resource: " + resource.name);
258
System.out.println("Usage: " + resource.usage + "/" + resource.limit);
259
}
260
}
261
}
262
```
263
264
## Message Searching in Folders
265
266
### Search Operations
267
268
```java { .api }
269
abstract class Folder {
270
public abstract Message[] search(SearchTerm term) throws MessagingException;
271
public abstract Message[] search(SearchTerm term, Message[] msgs) throws MessagingException;
272
}
273
```
274
275
### Search Examples
276
277
```java
278
// Search for messages from specific sender
279
SearchTerm fromTerm = new FromStringTerm("john@example.com");
280
Message[] fromJohn = folder.search(fromTerm);
281
282
// Search for unread messages with specific subject
283
SearchTerm unreadTerm = new FlagTerm(new Flags(Flags.Flag.SEEN), false);
284
SearchTerm subjectTerm = new SubjectTerm("Important");
285
SearchTerm combinedTerm = new AndTerm(unreadTerm, subjectTerm);
286
Message[] results = folder.search(combinedTerm);
287
288
// Search within a subset of messages
289
Message[] recentMessages = folder.getMessages(100, 200);
290
Message[] filteredResults = folder.search(fromTerm, recentMessages);
291
```
292
293
## Store Implementation
294
295
The Store class provides access to message stores and folder hierarchies.
296
297
### Store Connection and Access
298
299
```java { .api }
300
abstract class Store extends Service {
301
public abstract Folder getDefaultFolder() throws MessagingException;
302
public abstract Folder getFolder(String name) throws MessagingException;
303
public abstract Folder getFolder(URLName url) throws MessagingException;
304
}
305
```
306
307
### Namespace Support
308
309
```java { .api }
310
abstract class Store {
311
public Folder[] getPersonalNamespaces() throws MessagingException;
312
public Folder[] getUserNamespaces(String user) throws MessagingException;
313
public Folder[] getSharedNamespaces() throws MessagingException;
314
}
315
```
316
317
### Store Events
318
319
```java { .api }
320
abstract class Store {
321
public void addStoreListener(StoreListener l);
322
public void removeStoreListener(StoreListener l);
323
public void addFolderListener(FolderListener l);
324
public void removeFolderListener(FolderListener l);
325
}
326
```
327
328
### Store Usage Example
329
330
```java
331
Store store = session.getStore("imap");
332
store.connect();
333
334
// Get namespace folders
335
Folder[] personal = store.getPersonalNamespaces();
336
Folder[] shared = store.getSharedNamespaces();
337
338
System.out.println("Personal folders:");
339
for (Folder f : personal) {
340
listFolderHierarchy(f, 0);
341
}
342
343
System.out.println("Shared folders:");
344
for (Folder f : shared) {
345
listFolderHierarchy(f, 0);
346
}
347
348
store.close();
349
350
// Helper method for recursive folder listing
351
private void listFolderHierarchy(Folder folder, int depth) throws MessagingException {
352
String indent = " ".repeat(depth);
353
System.out.println(indent + folder.getName() + " (" + folder.getMessageCount() + " messages)");
354
355
if ((folder.getType() & Folder.HOLDS_FOLDERS) != 0) {
356
Folder[] subfolders = folder.list();
357
for (Folder subfolder : subfolders) {
358
listFolderHierarchy(subfolder, depth + 1);
359
}
360
}
361
}
362
```
363
364
## Fetch Profiles
365
366
The FetchProfile class optimizes message retrieval by specifying which data to prefetch.
367
368
```java { .api }
369
class FetchProfile {
370
public FetchProfile();
371
372
public void add(Item item);
373
public void add(String headerName);
374
public boolean contains(Item item);
375
public boolean contains(String headerName);
376
377
public Item[] getItems();
378
public String[] getHeaderNames();
379
380
static class Item {
381
static final Item ENVELOPE;
382
static final Item CONTENT_INFO;
383
static final Item FLAGS;
384
static final Item SIZE;
385
386
protected Item(String name);
387
}
388
}
389
```
390
391
### Fetch Profile Usage
392
393
```java
394
// Create fetch profile for efficient access
395
FetchProfile fp = new FetchProfile();
396
fp.add(FetchProfile.Item.ENVELOPE); // From, To, Subject, Date
397
fp.add(FetchProfile.Item.FLAGS); // Message flags
398
fp.add("X-Priority"); // Custom header
399
400
// Fetch data efficiently
401
Message[] messages = folder.getMessages();
402
folder.fetch(messages, fp);
403
404
// Access prefetched data
405
for (Message msg : messages) {
406
// These accesses are now efficient (data already fetched)
407
System.out.println("From: " + msg.getFrom()[0]);
408
System.out.println("Subject: " + msg.getSubject());
409
System.out.println("Seen: " + msg.isSet(Flags.Flag.SEEN));
410
}
411
```
412
413
## Advanced Folder Operations
414
415
### Subscription Management
416
417
```java { .api }
418
abstract class Folder {
419
public void setSubscribed(boolean subscribe) throws MessagingException;
420
public boolean isSubscribed() throws MessagingException;
421
}
422
```
423
424
### Access Rights
425
426
```java { .api }
427
interface Rights {
428
public Right[] getRights();
429
430
static class Right {
431
static final Right LOOKUP; // 'l' - Lookup/visible
432
static final Right READ; // 'r' - Read
433
static final Right KEEP_SEEN; // 's' - Keep \Seen flag
434
static final Right WRITE; // 'w' - Write/flag except \Seen
435
static final Right INSERT; // 'i' - Insert/copy messages
436
static final Right POST; // 'p' - Post messages
437
static final Right CREATE; // 'c' - Create subfolders
438
static final Right DELETE; // 'd' - Delete messages
439
static final Right ADMINISTER;// 'a' - Administer rights
440
}
441
}
442
443
interface ACL {
444
public void addRights(ACL.Rights rights) throws MessagingException;
445
public void removeRights(ACL.Rights rights) throws MessagingException;
446
public void setRights(ACL.Rights rights) throws MessagingException;
447
public ACL.Rights[] listRights(String name) throws MessagingException;
448
public ACL.Rights myRights(String name) throws MessagingException;
449
}
450
```
451
452
## Exception Classes
453
454
```java { .api }
455
class FolderClosedException extends MessagingException {
456
public FolderClosedException(Folder folder);
457
public FolderClosedException(Folder folder, String message);
458
459
public Folder getFolder();
460
}
461
462
class FolderNotFoundException extends MessagingException {
463
public FolderNotFoundException();
464
public FolderNotFoundException(String s);
465
public FolderNotFoundException(Folder f);
466
public FolderNotFoundException(String s, Folder f);
467
468
public Folder getFolder();
469
}
470
471
class ReadOnlyFolderException extends MessagingException {
472
public ReadOnlyFolderException(Folder folder);
473
public ReadOnlyFolderException(Folder folder, String message);
474
475
public Folder getFolder();
476
}
477
478
class StoreClosedException extends MessagingException {
479
public StoreClosedException(Store store);
480
public StoreClosedException(Store store, String message);
481
482
public Store getStore();
483
}
484
485
class MessageRemovedException extends MessagingException {
486
public MessageRemovedException();
487
public MessageRemovedException(String s);
488
}
489
```
490
491
### Error Handling Example
492
493
```java
494
try {
495
folder.open(Folder.READ_WRITE);
496
Message[] messages = folder.getMessages();
497
498
for (Message msg : messages) {
499
try {
500
System.out.println("Subject: " + msg.getSubject());
501
} catch (MessageRemovedException e) {
502
System.out.println("Message was expunged: " + e.getMessage());
503
continue;
504
}
505
}
506
507
folder.close();
508
} catch (FolderNotFoundException e) {
509
System.err.println("Folder not found: " + e.getFolder().getFullName());
510
} catch (ReadOnlyFolderException e) {
511
System.err.println("Folder is read-only: " + e.getFolder().getName());
512
} catch (FolderClosedException e) {
513
System.err.println("Folder was closed: " + e.getFolder().getName());
514
} catch (StoreClosedException e) {
515
System.err.println("Store connection closed: " + e.getStore().getURLName());
516
}
517
```
518
519
## Complete Example: Folder Management
520
521
```java
522
public class FolderOperationsExample {
523
524
public void manageFolders(Session session) throws MessagingException {
525
Store store = session.getStore("imap");
526
store.connect("imap.example.com", "username", "password");
527
528
try {
529
// Create organizational folders
530
createFolderStructure(store);
531
532
// Process messages in INBOX
533
processInbox(store);
534
535
// Archive old messages
536
archiveOldMessages(store);
537
538
} finally {
539
store.close();
540
}
541
}
542
543
private void createFolderStructure(Store store) throws MessagingException {
544
String[] folderNames = {"Archive", "Projects", "Personal"};
545
546
for (String name : folderNames) {
547
Folder folder = store.getFolder(name);
548
if (!folder.exists()) {
549
boolean created = folder.create(Folder.HOLDS_MESSAGES | Folder.HOLDS_FOLDERS);
550
System.out.println("Created folder '" + name + "': " + created);
551
}
552
}
553
}
554
555
private void processInbox(Store store) throws MessagingException {
556
Folder inbox = store.getFolder("INBOX");
557
inbox.open(Folder.READ_WRITE);
558
559
try {
560
Message[] messages = inbox.getMessages();
561
System.out.println("Processing " + messages.length + " messages");
562
563
// Use fetch profile for efficiency
564
FetchProfile fp = new FetchProfile();
565
fp.add(FetchProfile.Item.ENVELOPE);
566
fp.add(FetchProfile.Item.FLAGS);
567
inbox.fetch(messages, fp);
568
569
for (Message msg : messages) {
570
processMessage(msg, store);
571
}
572
573
} finally {
574
inbox.close(false);
575
}
576
}
577
578
private void processMessage(Message message, Store store) throws MessagingException {
579
// Example: Move project-related emails to Projects folder
580
String subject = message.getSubject();
581
if (subject != null && subject.toLowerCase().contains("project")) {
582
Folder projectsFolder = store.getFolder("Projects");
583
projectsFolder.open(Folder.READ_WRITE);
584
585
try {
586
Message[] msgs = {message};
587
message.getFolder().copyMessages(msgs, projectsFolder);
588
message.setFlag(Flags.Flag.DELETED, true);
589
} finally {
590
projectsFolder.close(false);
591
}
592
}
593
}
594
595
private void archiveOldMessages(Store store) throws MessagingException {
596
Calendar cal = Calendar.getInstance();
597
cal.add(Calendar.MONTH, -6); // 6 months ago
598
Date cutoffDate = cal.getTime();
599
600
// Search for old messages
601
SearchTerm oldTerm = new ReceivedDateTerm(ComparisonTerm.LT, cutoffDate);
602
603
Folder inbox = store.getFolder("INBOX");
604
inbox.open(Folder.READ_WRITE);
605
606
try {
607
Message[] oldMessages = inbox.search(oldTerm);
608
if (oldMessages.length > 0) {
609
Folder archiveFolder = store.getFolder("Archive");
610
archiveFolder.open(Folder.READ_WRITE);
611
612
try {
613
inbox.copyMessages(oldMessages, archiveFolder);
614
inbox.setFlags(oldMessages, new Flags(Flags.Flag.DELETED), true);
615
inbox.expunge();
616
617
System.out.println("Archived " + oldMessages.length + " old messages");
618
} finally {
619
archiveFolder.close(false);
620
}
621
}
622
} finally {
623
inbox.close(false);
624
}
625
}
626
}
627
```