Skip to main content

Mailbox Operations

Mailbox operations in EmailEngine allow you to list, manage, and work with email folders (also called mailboxes in IMAP terminology). Understanding folder structure and special-use folders is essential for properly routing messages and building email applications.

Understanding Mailboxes

What is a Mailbox?

In IMAP terms, a "mailbox" is what most users think of as a "folder." Each mailbox can contain:

  • Email messages
  • Sub-mailboxes (nested folders)
  • Metadata (message count, flags, etc.)

The Special INBOX

INBOX is unique:

  • It's the only guaranteed folder on every account
  • Name is case-insensitive (INBOX, Inbox, inbox all work)
  • All other folder names are case-sensitive
  • Cannot be deleted or renamed

It's entirely valid for an account to have only INBOX and no other folders.

Folder Hierarchies

Folders can be nested using a delimiter (usually / or .):

Special-Use Folders

What are Special-Use Folders?

Special-use folders indicate a folder's intended purpose regardless of its name. This solves the multi-language problem where "Sent Mail" might be "Saadetud kirjad" in Estonian or "Correo enviado" in Spanish.

Provider Support:

Different providers handle special-use folder detection differently:

  • Gmail (IMAP and API): Exposes special-use flags natively (most reliable)
  • Outlook IMAP: Does NOT expose special-use flags over IMAP (EmailEngine uses heuristics instead)
  • Outlook Graph API: Provides special-use flags natively
  • Generic IMAP: Many servers expose special-use flags natively, some don't

Special-Use Flags

EmailEngine recognizes these special-use flags:

FlagPurposeExample Names
\InboxMain inboxINBOX
\FlaggedStarred/flaggedStarred, Flagged
\SentSent emailsSent Mail, Saadetud kirjad, Enviados
\DraftsDraft emailsDrafts, Mustandid, Borradores
\TrashDeleted emailsTrash, Prügikast, Papelera
\JunkSpam emailsJunk, Rämps, Spam
\ArchiveArchived emailsArchive, Arhiiv, Archivo
\AllAll emails (virtual)All Mail, Todos

Special-Use Sources

EmailEngine indicates how it determined a folder's special-use flag:

extension - Server provided the hint (most reliable)

{
"path": "[Gmail]/Sent Mail",
"specialUse": "\\Sent",
"specialUseSource": "extension"
}

Available when:

  • Gmail (IMAP and API)
  • Microsoft Graph API
  • Many modern IMAP servers

name - Determined by folder name matching using heuristics (fallback)

{
"path": "Sent Items",
"specialUse": "\\Sent",
"specialUseSource": "name"
}

Used when:

  • Outlook IMAP (does not expose special-use flags)
  • Other IMAP servers without special-use extension
  • May be incorrect on localized accounts (e.g., "Gesendete Elemente" in German)

user - You explicitly configured it (highest priority, always correct)

{
"path": "My Custom Sent Folder",
"specialUse": "\\Sent",
"specialUseSource": "user"
}
Outlook IMAP and Localized Accounts

Outlook does not expose special-use flags over IMAP. EmailEngine uses heuristics (folder name matching) which may fail on localized accounts. If EmailEngine incorrectly identifies special folders on your Outlook IMAP account, manually set the correct paths using imap.sentMailPath, imap.draftsMailPath, etc.

Listing Mailboxes

Basic Listing

List all mailboxes for an account using the mailboxes API:

curl "https://your-emailengine.com/v1/account/example/mailboxes" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response:

{
"mailboxes": [
{
"path": "INBOX",
"delimiter": "/",
"parentPath": "",
"name": "INBOX",
"listed": true,
"subscribed": true,
"specialUse": "\\Inbox",
"specialUseSource": "name",
"noInferiors": false,
"messages": 1523,
"uidNext": 12456
},
{
"path": "[Gmail]/Sent Mail",
"delimiter": "/",
"parentPath": "[Gmail]",
"name": "Sent Mail",
"listed": true,
"subscribed": true,
"specialUse": "\\Sent",
"specialUseSource": "extension",
"noInferiors": false,
"messages": 891,
"uidNext": 2485
},
{
"path": "Work/Projects",
"delimiter": "/",
"parentPath": "Work",
"name": "Projects",
"listed": true,
"subscribed": true,
"noInferiors": false,
"messages": 45,
"uidNext": 78
}
]
}

Response Fields

FieldDescription
pathFull folder path (use this for API calls)
delimiterHierarchy delimiter (usually / or .)
parentPathParent folder path (empty for top-level)
nameDisplay name (last part of path)
listedWhether folder is listed (vs hidden)
subscribedWhether user is subscribed to folder
specialUseSpecial-use flag if applicable (\Sent, \Drafts, etc.)
specialUseSourceHow special-use was determined (extension, name, user)
noInferiorsWhether this mailbox can contain child mailboxes
messagesTotal message count
uidNextNext expected UID
statusAdditional statistics (messages count, unseen count)

Using Special-Use Folders

Find the sent folder regardless of name:

async function getSentFolder(accountId) {
const response = await fetch(`https://your-emailengine.com/v1/account/${accountId}/mailboxes`, {
headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
});

const data = await response.json();

// Find folder with \Sent special-use flag
const sentFolder = data.mailboxes.find((mailbox) => mailbox.specialUse === "\\Sent");

return sentFolder ? sentFolder.path : null;
}

List all messages from the sent folder:

async function listSentMessagesManual(accountId) {
const sentPath = await getSentFolder(accountId);

if (!sentPath) {
throw new Error("Sent folder not found");
}

const response = await fetch(`https://your-emailengine.com/v1/account/${accountId}/messages?path=${encodeURIComponent(sentPath)}`, {
headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
});

return await response.json();
}

List all messages from the sent folder using special-use flag alias:

async function listSentMessages(accountId) {
// Use special-use flag directly - EmailEngine resolves the actual path
const response = await fetch(`https://your-emailengine.com/v1/account/${accountId}/messages?path=${encodeURIComponent("\\Sent")}`, {
headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
});

return await response.json();
}
Special-Use Flag Aliases

EmailEngine allows using special-use flags (like \Sent, \Drafts, \Trash) directly as the path parameter. EmailEngine automatically resolves the flag to the actual folder path before executing the operation. This works regardless of the folder's actual name or location.

Creating Mailboxes

Create a New Folder

Create a mailbox folder using the create mailbox API:

curl -X POST "https://your-emailengine.com/v1/account/example/mailbox" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"path": ["Work", "NewProject"]
}'

Response:

{
"path": "Work/NewProject",
"mailboxId": "1439876283476",
"created": true
}

The mailboxId field is included if the server supports mailbox IDs.

Array Syntax for Subfolders

Use array syntax ["Parent", "Child"] instead of string "Parent/Child" when creating nested folders. Different servers use different delimiters (/ vs .), and the array syntax works universally across all IMAP servers.

Automatic Namespace Handling

EmailEngine automatically adds the server's namespace prefix if missing:

// If server namespace is "INBOX." and you create:
{ "path": "test" }

// EmailEngine creates:
"INBOX.test"

This ensures folder paths are always valid for the specific IMAP server configuration.

Create Nested Folders

EmailEngine creates parent folders automatically if needed:

async function createFolder(accountId, folderPath) {
const response = await fetch(`https://your-emailengine.com/v1/account/${accountId}/mailbox`, {
method: "POST",
headers: {
Authorization: "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ path: folderPath }),
});

return await response.json();
}

// Creates Personal/Finance/2025 (and parents if needed)
await createFolder("example", ["Personal", "Finance", "2025"]);

Renaming Mailboxes

Rename a Folder

Rename a mailbox using the rename mailbox API:

curl -X PUT "https://your-emailengine.com/v1/account/example/mailbox" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"path": "Work/OldProject",
"newPath": ["Work", "CompletedProject"]
}'

Response:

{
"path": "Work/OldProject",
"newPath": "Work/CompletedProject",
"renamed": true
}

Rename with Children

Renaming a parent folder renames all children automatically:

// Rename Work/Projects to Work/Archive
// Also renames:
// Work/Projects/ProjectA → Work/Archive/ProjectA
// Work/Projects/ProjectB → Work/Archive/ProjectB

await fetch(`https://your-emailengine.com/v1/account/example/mailbox`, {
method: "PUT",
headers: {
Authorization: "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({
path: "Work/Projects",
newPath: ["Work", "Archive"],
}),
});

Deleting Mailboxes

Delete a Folder

Delete a mailbox using the delete mailbox API:

curl -X DELETE "https://your-emailengine.com/v1/account/example/mailbox?path=Work%2FOldProject" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response:

{
"path": "Work/OldProject",
"deleted": true
}

Important Notes

Cannot delete INBOX:

// This will fail
await deleteFolder("example", "INBOX");
// Error: Cannot delete INBOX

Delete children first:

// Must delete child folders before parent
await deleteFolder("example", "Work/Projects/ProjectA");
await deleteFolder("example", "Work/Projects/ProjectB");
await deleteFolder("example", "Work/Projects");

Messages are deleted: When you delete a folder, all messages in it are permanently deleted (unless the server automatically moves them to Trash).

Overriding Special-Use Folders

Setting Custom Special-Use Paths

You can explicitly configure which folders to use for special purposes:

curl -X PUT "https://your-emailengine.com/v1/account/example" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"imap": {
"partial": true,
"sentMailPath": "Custom/Sent Emails",
"draftsMailPath": "Custom/Drafts",
"junkMailPath": "Custom/Spam",
"trashMailPath": "Custom/Trash",
"archiveMailPath": "Custom/Archive"
}
}'

Important: Always set "partial": true to merge with existing config. Otherwise, you'll overwrite the entire IMAP configuration.

Available Overrides:

  • sentMailPath - Where sent messages are stored
  • draftsMailPath - Where drafts are saved
  • junkMailPath - Where spam/junk goes
  • trashMailPath - Where deleted messages go
  • archiveMailPath - Where archived messages are stored

Example:

async function setCustomSentFolder(accountId, folderPath) {
const response = await fetch(`https://your-emailengine.com/v1/account/${accountId}`, {
method: "PUT",
headers: {
Authorization: "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({
imap: {
partial: true,
sentMailPath: folderPath,
},
}),
});

return await response.json();
}

// Now all sent emails will go to "My Company/Sent"
await setCustomSentFolder("example", "My Company/Sent");

Working with Gmail Labels and Outlook Categories

EmailEngine uses the labels array for both Gmail labels and Microsoft Outlook/Graph API categories.

Gmail Labels

Gmail uses labels instead of folders. EmailEngine maps labels to the folder structure:

Traditional IMAPGmailDescription
INBOXINBOXMessages with \Inbox label
Sent Mail[Gmail]/Sent MailMessages with \Sent label
Drafts[Gmail]/DraftsMessages with \Drafts label
-[Gmail]/All MailAll messages except Trash and Spam (virtual folder)

Multiple Labels:

A Gmail message can have multiple labels, which EmailEngine represents in the labels array:

{
"id": "AAAAAQAAMqo",
"path": "[Gmail]/All Mail",
"labels": ["\\Inbox", "Work", "Important"],
"specialUse": "\\All"
}

Gmail label characteristics:

  • Labels must be pre-created in Gmail
  • Labels map to folders (e.g., label "Work" corresponds to a folder)
  • Used with Gmail IMAP and Gmail API accounts

Microsoft Outlook Categories

For accounts using Microsoft Graph API backend, EmailEngine uses the labels array for Outlook categories:

{
"id": "AAMkADU1...",
"path": "Inbox",
"labels": ["Blue category", "Red category"]
}

Outlook category characteristics:

  • Categories are automatically created when you set them (no pre-creation needed)
  • Categories are not folders - they're an additional filter/tag
  • Categories don't map to mailbox folders (unlike Gmail labels)
  • Only available when using Microsoft Graph API backend

Limitations:

  • Names only - EmailEngine only works with category names, not colors. Colors are assigned by Outlook when categories are created.
  • Create only - EmailEngine can create new categories (by assigning a non-existent category name to a message) but cannot delete or rename categories.
  • No category management - To manage category colors, rename, or delete categories, use Outlook directly.
Important

Outlook categories are not a replacement for folders. Unlike Gmail where a label creates a folder, Outlook categories are independent color-coded tags that don't affect folder structure.

Common Folder Patterns

Finding Inbox

async function getInboxPath(accountId) {
const response = await fetch(`https://your-emailengine.com/v1/account/${accountId}/mailboxes`, {
headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
});

const data = await response.json();

// INBOX is guaranteed to exist
const inbox = data.mailboxes.find((m) => m.path.toUpperCase() === "INBOX");

return inbox.path; // Returns "INBOX" or "Inbox" etc.
}

Finding All Special-Use Folders

async function getSpecialUseFolders(accountId) {
const response = await fetch(`https://your-emailengine.com/v1/account/${accountId}/mailboxes`, {
headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
});

const data = await response.json();

const specialFolders = {};

data.mailboxes.forEach((mailbox) => {
if (mailbox.specialUse) {
const key = mailbox.specialUse.replace(/\\/g, "").toLowerCase();
specialFolders[key] = mailbox.path;
}
});

return specialFolders;
}

// Returns:
// {
// inbox: "INBOX",
// sent: "[Gmail]/Sent Mail",
// drafts: "Drafts",
// trash: "Deleted Items",
// junk: "Spam",
// archive: "[Gmail]/All Mail"
// }