Skip to main content

Account Management

EmailEngine connects to email accounts via IMAP/SMTP or native APIs (Gmail API, Microsoft Graph). This section covers everything you need to know about adding, configuring, and managing accounts.

Choosing Your Setup Method

EmailEngine supports multiple ways to connect to email accounts, each with different trade-offs:

IMAP/SMTP (Standard Protocol)

Best for: Self-hosted email servers, simple setup (except Gmail/Outlook)

Pros:

  • Works with most email providers
  • Simple username/password authentication
  • Immediate setup

Cons:

  • Requires username and password
  • Some providers block IMAP access
  • Gmail requires app-specific password (not regular password)
  • Outlook/Microsoft 365 not supported (OAuth2 required)

Supported Providers:

  • Gmail (with app password)
  • Any IMAP/SMTP server (except Outlook/Microsoft 365)
  • Self-hosted email

Learn more about IMAP/SMTP accounts →

OAuth2 (IMAP/SMTP)

Best for: Gmail, Outlook/Microsoft 365, and Mail.ru accounts at scale

Pros:

  • No password storage
  • Automatic token refresh
  • Works with 2FA-enabled accounts
  • Better security and user experience
  • Required for Outlook/Microsoft 365 IMAP access

Cons:

  • Requires OAuth app registration (Google Cloud Console or Azure AD)
  • OAuth app verification needed for production

Use Cases:

  • SaaS applications connecting user Gmail/Outlook accounts
  • CRM systems syncing customer emails
  • Email automation tools

Setup Guides:

Gmail API (Native)

Best for: High-volume Gmail operations, when limited OAuth2 scopes are required

Pros:

  • Generally faster than IMAP (except message listing)
  • Access to Gmail-specific features (labels, drafts)
  • Better threading support
  • No IMAP connection limits
  • Faster message fetching and sending
  • Can use granular OAuth2 scopes (gmail.readonly, gmail.modify, etc.)

Cons:

  • Message listing slower than IMAP (due to data enrichment)
  • Requires Cloud Pub/Sub setup
  • Only works with Gmail
  • More complex configuration

Use Cases:

  • High-volume email processing
  • Applications needing Gmail-specific features
  • Systems requiring maximum performance
  • When Google requires limited OAuth2 scopes during app verification
OAuth2 Scope Requirements

IMAP/SMTP requires the full https://mail.google.com/ scope. Gmail API can use more limited scopes like gmail.readonly or gmail.modify. If Google's verification process requires you to use limited scopes, you must use Gmail API instead of IMAP/SMTP.

Gmail API Setup Guide →

Microsoft Graph API (Native)

Best for: Microsoft 365 and Outlook.com advanced features

Pros:

  • Faster than IMAP
  • Access to Microsoft 365 features
  • Better integration with Outlook features
  • Supports shared mailboxes natively
  • Works with both Microsoft 365 and Outlook.com (Hotmail)

Cons:

  • Very limited search capabilities compared to IMAP
  • Requires Microsoft Graph subscription setup
  • Only works with Microsoft accounts
  • More complex configuration

Use Cases:

  • Enterprise applications on Microsoft stack
  • Shared mailbox management
  • Advanced Microsoft 365 integrations
  • Outlook.com and Hotmail accounts

Microsoft Graph Setup →

Microsoft 365 Application Access (Client Credentials)

Best for: Enterprise deployments accessing mailboxes without interactive user login

Pros:

  • No interactive user login required
  • Admin grants access once for the entire organization
  • Access any mailbox with the same app credentials
  • Ideal for automated workflows and service integrations

Cons:

  • Microsoft 365 only (no personal accounts)
  • Requires Azure AD admin privileges and admin consent
  • MS Graph API only (no IMAP/SMTP)
  • Client secret has maximum 2-year lifetime

Use Cases:

  • Helpdesk and compliance systems
  • Shared mailbox management at scale
  • Automated email processing across an organization
  • Service integrations where interactive login is not possible

Outlook Application Access Setup →

How Credentials Are Stored

EmailEngine stores email account credentials in Redis. Understanding this is important for security planning.

What Gets Stored

  • IMAP/SMTP passwords
  • OAuth2 access tokens
  • OAuth2 refresh tokens
  • OAuth2 application client secrets
  • Service account private keys
info

Email message content is not stored in Redis. EmailEngine fetches messages from the mail server on demand and only caches metadata for synchronization.

Default Behavior (Development)

By default, credentials are stored in cleartext in Redis. This is acceptable for local development but not recommended for production.

Production Security (Required)

Configure the EENGINE_SECRET environment variable to enable AES-256-GCM encryption for all sensitive data. Generate the secret once and store it permanently - for example in an .env file or a secrets manager:

# Generate the secret once and persist it
echo "EENGINE_SECRET=$(openssl rand -hex 32)" >> .env

With encryption enabled, all credentials are encrypted before being written to Redis. The same secret value must be provided on every start.

Critical

If you lose the EENGINE_SECRET, encrypted credentials cannot be recovered and every account must be re-authenticated. Store this secret securely and include it in your backup strategy.

Complete security guide | Encryption details

Decision Tree: Which Method Should I Use?

Account Management Tasks

Adding Accounts

Via API (Programmatic):

Use the register account API:

// Add account via REST API
const response = await fetch('https://emailengine.example.com/v1/account', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
account: 'user123',
name: 'John Doe',
email: 'john@example.com',
imap: {
host: 'imap.example.com',
port: 993,
secure: true,
auth: { user: 'john@example.com', pass: 'password' }
},
smtp: {
host: 'smtp.example.com',
port: 587,
secure: false,
auth: { user: 'john@example.com', pass: 'password' }
}
})
});

Via Hosted Authentication Form (User-Friendly):

Generate a form URL and redirect users to it. They enter their credentials, and EmailEngine handles the rest.

// Generate authentication form URL
const formResponse = await fetch('https://emailengine.example.com/v1/authentication/form', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
account: 'user123',
email: 'john@example.com',
redirectUrl: 'https://myapp.com/settings'
})
});

const { url } = await formResponse.json();
// Redirect user to: url

Learn about hosted authentication →

Via Web Interface:

Navigate to Accounts > Add an account in the EmailEngine dashboard. The dialog asks for a display name and an optional account identifier, and Continue opens the hosted authentication form.

note

The web interface is a shorthand for the hosted authentication form. EmailEngine generates a hosted authentication form URL and redirects your browser to it, so the experience is identical to what end users see when your application generates the URL via the API.

Updating Accounts

Use the update account API:

// Update account settings
await fetch('https://emailengine.example.com/v1/account/user123', {
method: 'PUT',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'John Doe Updated',
subconnections: ['\\Sent']
})
});
Partial updates for nested objects

The imap, smtp, and oauth2 objects are replaced whole unless the object carries "partial": true. This body changes only the Sent folder path and keeps the stored host, port, and credentials:

{
"imap": {
"partial": true,
"sentMailPath": "Sent Items"
}
}

Account States

StateDescriptionActions Available
initThe account was just registered and has not connected yetWait
connectingConnecting to the mail server or authorizing with the providerWait
syncingConnected and performing the initial or a periodic mailbox syncWait for the sync to complete
connectedConnected and watching for changes. This is the healthy steady stateAll operations available
disconnectedThe connection dropped and EmailEngine is retrying with backoffWait for the retry
authenticationErrorThe credentials were rejected. Requires re-authentication before syncing resumesUpdate credentials or re-authorize
connectErrorThe server could not be reached or the TLS handshake failed. Retried with backoffCheck connectivity, retry
pausedSyncing was paused through the API. No connection is maintainedResume syncing
unsetThe account is not syncing: either no IMAP or OAuth2 configuration is set, or syncing was switched off, by the operator or automatically after repeated authentication failuresFinish the setup, or re-enable the account

An unset account that EmailEngine switched off itself carries a non-null authFailureDisabledAt timestamp in the account object (since v2.79.4). See Accounts switched off after authentication failures for how to bring one back.

Reconnecting Accounts

If an account enters an error state, you can trigger a reconnection using the reconnect account API:

curl -X PUT https://emailengine.example.com/v1/account/user123/reconnect \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reconnect": true}'

The response is {"reconnect": true} when a reconnect was requested. Since v2.79.4 it is {"reconnect": false} for an account that EmailEngine switched off after repeated authentication failures, because a reconnect cannot bring such an account back; supply working credentials or use Resume syncing in the admin interface instead.

Flushing Accounts

The flush API resets the internal email index for an account and re-syncs from scratch. This is useful for:

  • Resetting corrupted index - Fix sync issues by rebuilding the index
  • Processing existing emails - Trigger messageNew webhooks for existing emails (IMAP only)
  • Changing indexer type - Switch between full and fast indexing strategies
# Basic flush - reset index, only notify about new messages going forward
curl -X PUT https://emailengine.example.com/v1/account/user123/flush \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"flush": true
}'

# Flush with options - process existing emails and change indexer
curl -X PUT https://emailengine.example.com/v1/account/user123/flush \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"flush": true,
"notifyFrom": "2024-01-01T00:00:00.000Z",
"imapIndexer": "full"
}'

Parameters:

ParameterTypeDescription
flushbooleanMust be true to confirm the flush operation
notifyFromstringOnly send webhooks for messages after this date (IMAP only). Defaults to current time, so only new messages trigger webhooks. Set to a past date like "1970-01-01T00:00:00.000Z" to process existing emails
imapIndexerstringSet indexing strategy: "full" or "fast" (IMAP only)
One flush at a time

Only one flush can run at a time across the whole instance. A second request while one is running fails with HTTP 429 and the error code LockFail.

API-Based Backends

For Gmail API and MS Graph accounts, notifyFrom has no effect. These backends only notify about new emails arriving after the account was connected, not existing emails.

Learn more about IMAP indexers →

Deleting Accounts

Use the delete account API:

curl -X DELETE https://emailengine.example.com/v1/account/user123 \
-H "Authorization: Bearer YOUR_TOKEN"

This removes the account from EmailEngine and closes all connections. Email data on the server remains unchanged.

Advanced Configuration

Sub-Connections

By default, EmailEngine monitors the INBOX folder in real-time but polls other folders periodically. Sub-connections allow instant notifications for additional folders.

{
"account": "user123",
"subconnections": [
"\\Sent",
"Important",
"Projects/Active"
]
}

Benefits:

  • Instant webhooks for sent emails
  • Real-time tracking of specific folders
  • Better CRM integration (know immediately when user sends email)

Trade-offs:

  • Opens additional IMAP connections
  • Most servers limit parallel connections (typically 10-15)
  • Use sparingly

Learn more in performance tuning →

Path Filtering

Limit which folders EmailEngine syncs and monitors to save resources:

{
"account": "user123",
"path": [
"INBOX",
"\\Sent",
"\\Drafts"
]
}

What this does:

  • EmailEngine syncs and monitors only the listed folders
  • Unlisted folders won't trigger webhooks
  • API access to unlisted folders still works

Learn more in performance tuning →

Custom Special Folder Paths

EmailEngine decides which folder is Sent, Drafts, Junk, Trash, or Archive from the paths you set, the server's SPECIAL-USE flags, and folder names, in that order. Outlook over IMAP advertises no flags at all, and a localized mailbox may name its folders in any language, so the guess is not always right.

Override any of them with sentMailPath, draftsMailPath, junkMailPath, trashMailPath, and archiveMailPath inside the account's imap object. See Custom special folder paths for the field reference and what specialUseSource reports.

OAuth2 Token Management

For OAuth2 accounts, EmailEngine automatically refreshes access tokens in the background. You never need to handle token expiration.

Using Tokens for Other APIs

You can retrieve valid access tokens for use in your own Google/Microsoft API calls:

// Get current OAuth2 access token
const tokenResponse = await fetch(
'https://emailengine.example.com/v1/account/user123/oauth-token',
{
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
}
);

const { account, user, accessToken, provider, expires } = await tokenResponse.json();

// Use token with Google/Microsoft APIs
const apiResponse = await fetch('https://www.googleapis.com/gmail/v1/users/me/profile', {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
Endpoint Disabled by Default

The /v1/account/{account}/oauth-token endpoint is disabled by default for security reasons. You must explicitly enable it before use.

To enable via Web UI:

  1. Navigate to Configuration > Security
  2. Check Allow OAuth2 Token Access via API
  3. Click Save

To enable via environment variable: Set EENGINE_ENABLE_OAUTH_TOKENS_API=true when starting EmailEngine.

This setting cannot be changed via the API - it must be configured through the web interface or environment variable.

Learn more about OAuth2 token management →

Service Accounts (Google Workspace)

For Google Workspace domains, you can use service accounts with domain-wide delegation to access any user's mailbox without individual OAuth2 consent.

Benefits:

  • No per-user OAuth2 flow
  • Centralized access management
  • Ideal for enterprise deployments

Requirements:

  • Google Workspace (not free Gmail)
  • Super admin access
  • Domain-wide delegation setup

Service Accounts Setup Guide →

Shared Mailboxes (Microsoft 365)

Microsoft 365 shared mailboxes can be accessed through two approaches:

  • Direct access - Add shared mailbox with its own OAuth2 credentials
  • Delegated access - Add main account, then reference it for shared mailboxes (recommended)

Delegated access allows one user to manage multiple shared mailboxes without re-authenticating.

Complete Shared Mailboxes Guide →

Authentication Server (External Token Management)

For advanced use cases where you already manage OAuth2 tokens in your application, you can use an external authentication server. EmailEngine will call your server to fetch access tokens instead of managing them internally.

Step 1: Configure the authentication server URL globally:

curl -X POST https://emailengine.example.com/v1/settings \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"authServer": "https://your-auth-server.com/authenticate"
}'

Step 2: Register accounts with useAuthServer: true:

For IMAP/SMTP accounts:

{
"account": "user123",
"name": "John Doe",
"email": "john@outlook.com",
"imap": {
"useAuthServer": true,
"host": "outlook.office365.com",
"port": 993,
"secure": true
},
"smtp": {
"useAuthServer": true,
"host": "smtp-mail.outlook.com",
"port": 587,
"secure": false
}
}

For Gmail API or MS Graph API accounts:

{
"account": "user123",
"name": "John Doe",
"email": "john@gmail.com",
"oauth2": {
"useAuthServer": true,
"provider": "<oauth2-app-id>",
"auth": {
"user": "john@gmail.com"
}
}
}

When EmailEngine needs to authenticate, it calls your server at GET {authServer}?account={account}&proto={proto} (where proto is imap, smtp, or api) and expects a response with user and either pass or accessToken fields.

Authentication Server Guide →

API Reference

See Also