CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-sun-mail--jakarta-mail-api

Jakarta Mail API provides a platform-independent and protocol-independent framework to build mail and messaging applications

Pending
Overview
Eval results
Files

folder-operations.mddocs/

Folder Operations

This document covers folder management, message storage operations, hierarchical navigation, and folder-based message manipulation in the Jakarta Mail API.

Folder Management

The Folder class represents a container for messages with support for hierarchical organization and various access modes.

Folder Access and Navigation

abstract class Folder implements AutoCloseable {
    public abstract String getName() throws MessagingException;
    public abstract String getFullName() throws MessagingException;
    public URLName getURLName() throws MessagingException;
    public abstract Folder getParent() throws MessagingException;
    public abstract boolean exists() throws MessagingException;
}

Folder Hierarchy

abstract class Folder {
    public abstract Folder[] list() throws MessagingException;
    public abstract Folder[] list(String pattern) throws MessagingException;
    public abstract Folder[] listSubscribed() throws MessagingException;
    public abstract Folder[] listSubscribed(String pattern) throws MessagingException;
    
    public abstract char getSeparator() throws MessagingException;
    public abstract int getType() throws MessagingException;
    
    public abstract boolean create(int type) throws MessagingException;
    public abstract boolean delete(boolean recurse) throws MessagingException;
    public abstract boolean renameTo(Folder f) throws MessagingException;
}

Folder Types:

  • HOLDS_MESSAGES (0x01) - Can contain messages
  • HOLDS_FOLDERS (0x02) - Can contain subfolders

Access Modes:

  • READ_ONLY (1) - Read-only access
  • READ_WRITE (2) - Read-write access

Folder Lifecycle

abstract class Folder {
    public abstract void open(int mode) throws MessagingException;
    public abstract void close() throws MessagingException;
    public abstract void close(boolean expunge) throws MessagingException;
    public abstract boolean isOpen();
    
    public Store getStore();
    public int getMode();
    public String toString();
}

Usage Example

Store store = session.getStore("imap");
store.connect("imap.example.com", "username", "password");

// Navigate folder hierarchy
Folder defaultFolder = store.getDefaultFolder();
Folder[] folders = defaultFolder.list("*");

// Work with INBOX
Folder inbox = store.getFolder("INBOX");
if (inbox.exists()) {
    inbox.open(Folder.READ_WRITE);
    
    // Folder operations here
    
    inbox.close(false); // Don't expunge on close
}

// Create new folder
Folder customFolder = store.getFolder("My Messages");
if (!customFolder.exists()) {
    customFolder.create(Folder.HOLDS_MESSAGES);
}

Message Access and Counting

Message Retrieval

abstract class Folder {
    public abstract int getMessageCount() throws MessagingException;
    public abstract int getNewMessageCount() throws MessagingException;
    public abstract int getUnreadMessageCount() throws MessagingException;
    public abstract int getDeletedMessageCount() throws MessagingException;
    
    public abstract Message getMessage(int msgnum) throws MessagingException;
    public abstract Message[] getMessages() throws MessagingException;
    public abstract Message[] getMessages(int start, int end) throws MessagingException;
    public abstract Message[] getMessages(int[] msgnums) throws MessagingException;
}

Message Properties

abstract class Folder {
    public abstract boolean hasNewMessages() throws MessagingException;
    public abstract Flags getPermanentFlags() throws MessagingException;
    
    public void fetch(Message[] msgs, FetchProfile fp) throws MessagingException;
    public void setFlags(Message[] msgs, Flags flag, boolean value) throws MessagingException;
    public void setFlags(int start, int end, Flags flag, boolean value) throws MessagingException;
    public void setFlags(int[] msgnums, Flags flag, boolean value) throws MessagingException;
}

Usage Examples

folder.open(Folder.READ_ONLY);

// Get message counts
int totalMessages = folder.getMessageCount();
int newMessages = folder.getNewMessageCount();
int unreadMessages = folder.getUnreadMessageCount();

System.out.println("Total: " + totalMessages + ", New: " + newMessages + ", Unread: " + unreadMessages);

// Get all messages
Message[] messages = folder.getMessages();

// Get recent messages (last 10)
int count = folder.getMessageCount();
Message[] recent = folder.getMessages(Math.max(1, count - 9), count);

// Mark messages as read
folder.setFlags(messages, new Flags(Flags.Flag.SEEN), true);

Message Storage Operations

Adding Messages

abstract class Folder {
    public abstract void appendMessages(Message[] msgs) throws MessagingException;
    
    public void copyMessages(Message[] msgs, Folder folder) throws MessagingException;
}

Message Deletion

abstract class Folder {
    public abstract Message[] expunge() throws MessagingException;
    public Message[] expunge(Message[] msgs) throws MessagingException;
}

Usage Examples

// Append new messages to folder
Message[] newMessages = createMessages(); // Your message creation logic
folder.appendMessages(newMessages);

// Copy messages to another folder
Folder sentFolder = store.getFolder("Sent");
sentFolder.open(Folder.READ_WRITE);
folder.copyMessages(messages, sentFolder);

// Delete messages (mark as deleted, then expunge)
folder.setFlags(messages, new Flags(Flags.Flag.DELETED), true);
Message[] expunged = folder.expunge(); // Permanently removes deleted messages

UID Support

The UIDFolder interface provides support for message UIDs (Unique Identifiers).

interface UIDFolder {
    public long getUID(Message message) throws MessagingException;
    public Message getMessageByUID(long uid) throws MessagingException;
    public Message[] getMessagesByUID(long start, long end) throws MessagingException;
    public Message[] getMessagesByUID(long[] uids) throws MessagingException;
    
    public long getUIDValidity() throws MessagingException;
    public long getUIDNext() throws MessagingException;
    
    static class FetchProfileItem extends FetchProfile.Item {
        static final FetchProfileItem UID;
    }
}

UID Usage Example

if (folder instanceof UIDFolder) {
    UIDFolder uidFolder = (UIDFolder) folder;
    
    // Get UID for a message
    long uid = uidFolder.getUID(message);
    
    // Retrieve message by UID
    Message msgByUID = uidFolder.getMessageByUID(uid);
    
    // Get UID validity (changes when folder is recreated)
    long uidValidity = uidFolder.getUIDValidity();
    
    // Get messages by UID range
    Message[] msgs = uidFolder.getMessagesByUID(100L, 200L);
}

Quota Management

The Quota class provides support for storage quotas on folders and stores.

class Quota {
    public String quotaRoot;
    public Resource[] resources;
    
    public Quota(String quotaRoot);
    
    static class Resource {
        public String name;
        public long usage;
        public long limit;
        
        public Resource(String name, long usage, long limit);
    }
}

interface QuotaAwareStore {
    public Quota[] getQuota(String quotaRoot) throws MessagingException;
    public void setQuota(Quota quota) throws MessagingException;
}

Quota Usage Example

if (store instanceof QuotaAwareStore) {
    QuotaAwareStore quotaStore = (QuotaAwareStore) store;
    
    // Get quota information
    Quota[] quotas = quotaStore.getQuota("INBOX");
    for (Quota quota : quotas) {
        for (Quota.Resource resource : quota.resources) {
            System.out.println("Resource: " + resource.name);
            System.out.println("Usage: " + resource.usage + "/" + resource.limit);
        }
    }
}

Message Searching in Folders

Search Operations

abstract class Folder {
    public abstract Message[] search(SearchTerm term) throws MessagingException;
    public abstract Message[] search(SearchTerm term, Message[] msgs) throws MessagingException;
}

Search Examples

// Search for messages from specific sender
SearchTerm fromTerm = new FromStringTerm("john@example.com");
Message[] fromJohn = folder.search(fromTerm);

// Search for unread messages with specific subject
SearchTerm unreadTerm = new FlagTerm(new Flags(Flags.Flag.SEEN), false);
SearchTerm subjectTerm = new SubjectTerm("Important");
SearchTerm combinedTerm = new AndTerm(unreadTerm, subjectTerm);
Message[] results = folder.search(combinedTerm);

// Search within a subset of messages
Message[] recentMessages = folder.getMessages(100, 200);
Message[] filteredResults = folder.search(fromTerm, recentMessages);

Store Implementation

The Store class provides access to message stores and folder hierarchies.

Store Connection and Access

abstract class Store extends Service {
    public abstract Folder getDefaultFolder() throws MessagingException;
    public abstract Folder getFolder(String name) throws MessagingException;
    public abstract Folder getFolder(URLName url) throws MessagingException;
}

Namespace Support

abstract class Store {
    public Folder[] getPersonalNamespaces() throws MessagingException;
    public Folder[] getUserNamespaces(String user) throws MessagingException;
    public Folder[] getSharedNamespaces() throws MessagingException;
}

Store Events

abstract class Store {
    public void addStoreListener(StoreListener l);
    public void removeStoreListener(StoreListener l);
    public void addFolderListener(FolderListener l);
    public void removeFolderListener(FolderListener l);
}

Store Usage Example

Store store = session.getStore("imap");
store.connect();

// Get namespace folders
Folder[] personal = store.getPersonalNamespaces();
Folder[] shared = store.getSharedNamespaces();

System.out.println("Personal folders:");
for (Folder f : personal) {
    listFolderHierarchy(f, 0);
}

System.out.println("Shared folders:");
for (Folder f : shared) {
    listFolderHierarchy(f, 0);
}

store.close();

// Helper method for recursive folder listing
private void listFolderHierarchy(Folder folder, int depth) throws MessagingException {
    String indent = "  ".repeat(depth);
    System.out.println(indent + folder.getName() + " (" + folder.getMessageCount() + " messages)");
    
    if ((folder.getType() & Folder.HOLDS_FOLDERS) != 0) {
        Folder[] subfolders = folder.list();
        for (Folder subfolder : subfolders) {
            listFolderHierarchy(subfolder, depth + 1);
        }
    }
}

Fetch Profiles

The FetchProfile class optimizes message retrieval by specifying which data to prefetch.

class FetchProfile {
    public FetchProfile();
    
    public void add(Item item);
    public void add(String headerName);
    public boolean contains(Item item);
    public boolean contains(String headerName);
    
    public Item[] getItems();
    public String[] getHeaderNames();
    
    static class Item {
        static final Item ENVELOPE;
        static final Item CONTENT_INFO;
        static final Item FLAGS;
        static final Item SIZE;
        
        protected Item(String name);
    }
}

Fetch Profile Usage

// Create fetch profile for efficient access
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);  // From, To, Subject, Date
fp.add(FetchProfile.Item.FLAGS);     // Message flags
fp.add("X-Priority");                // Custom header

// Fetch data efficiently
Message[] messages = folder.getMessages();
folder.fetch(messages, fp);

// Access prefetched data
for (Message msg : messages) {
    // These accesses are now efficient (data already fetched)
    System.out.println("From: " + msg.getFrom()[0]);
    System.out.println("Subject: " + msg.getSubject());
    System.out.println("Seen: " + msg.isSet(Flags.Flag.SEEN));
}

Advanced Folder Operations

Subscription Management

abstract class Folder {
    public void setSubscribed(boolean subscribe) throws MessagingException;
    public boolean isSubscribed() throws MessagingException;
}

Access Rights

interface Rights {
    public Right[] getRights();
    
    static class Right {
        static final Right LOOKUP;    // 'l' - Lookup/visible
        static final Right READ;      // 'r' - Read
        static final Right KEEP_SEEN; // 's' - Keep \Seen flag  
        static final Right WRITE;     // 'w' - Write/flag except \Seen
        static final Right INSERT;    // 'i' - Insert/copy messages
        static final Right POST;      // 'p' - Post messages
        static final Right CREATE;    // 'c' - Create subfolders
        static final Right DELETE;    // 'd' - Delete messages
        static final Right ADMINISTER;// 'a' - Administer rights
    }
}

interface ACL {
    public void addRights(ACL.Rights rights) throws MessagingException;
    public void removeRights(ACL.Rights rights) throws MessagingException;
    public void setRights(ACL.Rights rights) throws MessagingException;
    public ACL.Rights[] listRights(String name) throws MessagingException;
    public ACL.Rights myRights(String name) throws MessagingException;
}

Exception Classes

class FolderClosedException extends MessagingException {
    public FolderClosedException(Folder folder);
    public FolderClosedException(Folder folder, String message);
    
    public Folder getFolder();
}

class FolderNotFoundException extends MessagingException {
    public FolderNotFoundException();
    public FolderNotFoundException(String s);
    public FolderNotFoundException(Folder f);
    public FolderNotFoundException(String s, Folder f);
    
    public Folder getFolder();
}

class ReadOnlyFolderException extends MessagingException {
    public ReadOnlyFolderException(Folder folder);
    public ReadOnlyFolderException(Folder folder, String message);
    
    public Folder getFolder();
}

class StoreClosedException extends MessagingException {
    public StoreClosedException(Store store);
    public StoreClosedException(Store store, String message);
    
    public Store getStore();
}

class MessageRemovedException extends MessagingException {
    public MessageRemovedException();
    public MessageRemovedException(String s);
}

Error Handling Example

try {
    folder.open(Folder.READ_WRITE);
    Message[] messages = folder.getMessages();
    
    for (Message msg : messages) {
        try {
            System.out.println("Subject: " + msg.getSubject());
        } catch (MessageRemovedException e) {
            System.out.println("Message was expunged: " + e.getMessage());
            continue;
        }
    }
    
    folder.close();
} catch (FolderNotFoundException e) {
    System.err.println("Folder not found: " + e.getFolder().getFullName());
} catch (ReadOnlyFolderException e) {
    System.err.println("Folder is read-only: " + e.getFolder().getName());
} catch (FolderClosedException e) {
    System.err.println("Folder was closed: " + e.getFolder().getName());
} catch (StoreClosedException e) {
    System.err.println("Store connection closed: " + e.getStore().getURLName());
}

Complete Example: Folder Management

public class FolderOperationsExample {
    
    public void manageFolders(Session session) throws MessagingException {
        Store store = session.getStore("imap");
        store.connect("imap.example.com", "username", "password");
        
        try {
            // Create organizational folders
            createFolderStructure(store);
            
            // Process messages in INBOX
            processInbox(store);
            
            // Archive old messages
            archiveOldMessages(store);
            
        } finally {
            store.close();
        }
    }
    
    private void createFolderStructure(Store store) throws MessagingException {
        String[] folderNames = {"Archive", "Projects", "Personal"};
        
        for (String name : folderNames) {
            Folder folder = store.getFolder(name);
            if (!folder.exists()) {
                boolean created = folder.create(Folder.HOLDS_MESSAGES | Folder.HOLDS_FOLDERS);
                System.out.println("Created folder '" + name + "': " + created);
            }
        }
    }
    
    private void processInbox(Store store) throws MessagingException {
        Folder inbox = store.getFolder("INBOX");
        inbox.open(Folder.READ_WRITE);
        
        try {
            Message[] messages = inbox.getMessages();
            System.out.println("Processing " + messages.length + " messages");
            
            // Use fetch profile for efficiency
            FetchProfile fp = new FetchProfile();
            fp.add(FetchProfile.Item.ENVELOPE);
            fp.add(FetchProfile.Item.FLAGS);
            inbox.fetch(messages, fp);
            
            for (Message msg : messages) {
                processMessage(msg, store);
            }
            
        } finally {
            inbox.close(false);
        }
    }
    
    private void processMessage(Message message, Store store) throws MessagingException {
        // Example: Move project-related emails to Projects folder
        String subject = message.getSubject();
        if (subject != null && subject.toLowerCase().contains("project")) {
            Folder projectsFolder = store.getFolder("Projects");
            projectsFolder.open(Folder.READ_WRITE);
            
            try {
                Message[] msgs = {message};
                message.getFolder().copyMessages(msgs, projectsFolder);
                message.setFlag(Flags.Flag.DELETED, true);
            } finally {
                projectsFolder.close(false);
            }
        }
    }
    
    private void archiveOldMessages(Store store) throws MessagingException {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MONTH, -6); // 6 months ago
        Date cutoffDate = cal.getTime();
        
        // Search for old messages
        SearchTerm oldTerm = new ReceivedDateTerm(ComparisonTerm.LT, cutoffDate);
        
        Folder inbox = store.getFolder("INBOX");
        inbox.open(Folder.READ_WRITE);
        
        try {
            Message[] oldMessages = inbox.search(oldTerm);
            if (oldMessages.length > 0) {
                Folder archiveFolder = store.getFolder("Archive");
                archiveFolder.open(Folder.READ_WRITE);
                
                try {
                    inbox.copyMessages(oldMessages, archiveFolder);
                    inbox.setFlags(oldMessages, new Flags(Flags.Flag.DELETED), true);
                    inbox.expunge();
                    
                    System.out.println("Archived " + oldMessages.length + " old messages");
                } finally {
                    archiveFolder.close(false);
                }
            }
        } finally {
            inbox.close(false);
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-sun-mail--jakarta-mail-api@1.6.1

docs

core-messaging.md

event-handling.md

folder-operations.md

index.md

internet-messaging.md

search-capabilities.md

tile.json