Skip to main content

EmailEngine AI Agent Reference

This document is designed for AI coding assistants helping developers integrate with the EmailEngine API. It provides a consolidated, machine-parseable overview of all capabilities, endpoints, and patterns.

What EmailEngine Does

EmailEngine is a self-hosted email API gateway that provides REST API access to email accounts via:

  • IMAP/SMTP protocols
  • Gmail API (native)
  • Microsoft Graph API (native)
  • OAuth2 authentication

Key value proposition: Instead of dealing with IMAP/SMTP protocols directly, developers interact with a single REST API. EmailEngine handles connection management, authentication, synchronization, and real-time notifications via webhooks.

Quick Facts

AspectDetails
Reference versionEmailEngine 2.79.4 (the OpenAPI spec this page is checked against)
API StyleRESTful JSON
AuthenticationBearer token (Authorization: Bearer TOKEN)
Base URLhttps://emailengine.example.com/v1 (a fresh local install listens on http://127.0.0.1:3000)
WebhooksHTTP POST to configured endpoint
Data StorageRedis (credentials encrypted with EENGINE_SECRET)
Message StorageNone - fetched from mail server on demand
Admin AuthPassword + TOTP, passkeys (WebAuthn), SSO (OpenID Connect, Okta)
AI AgentsMCP server at POST /mcp, off by default (see MCP)

Core Capabilities Matrix

CapabilityEndpointKey Parameters
Register accountPOST /v1/accountaccount, imap, smtp, or oauth2
List accountsGET /v1/accountspage, pageSize, state
Get accountGET /v1/account/{account}-
Update accountPUT /v1/account/{account}Partial updates supported
Delete accountDELETE /v1/account/{account}optional ?revoke=true to revoke the OAuth2 grant
Reconnect accountPUT /v1/account/{account}/reconnectreconnect: true; answers {"reconnect": false} when syncing was switched off after repeated authentication failures
Send emailPOST /v1/account/{account}/submitto, subject, text/html
Send stored draftPOST /v1/account/{account}/message/{message}/submitoptional delivery options
List messagesGET /v1/account/{account}/messagespath, page, pageSize
Get messageGET /v1/account/{account}/message/{message}textType, embedAttachedImages, preProcessHtml, webSafeHtml (shorthand for all three; an explicit embedAttachedImages=false still overrides it)
Get message textGET /v1/account/{account}/text/{text}textType, maxBytes, webSafeHtml (returns a single sanitized HTML rendering)
Search messagesPOST /v1/account/{account}/searchsearch object
Update messagePUT /v1/account/{account}/message/{message}flags, labels, seen
Delete messageDELETE /v1/account/{account}/message/{message}-
Move messagePUT /v1/account/{account}/message/{message}/movepath (destination)
Download attachmentGET /v1/account/{account}/attachment/{attachment}-
List mailboxesGET /v1/account/{account}/mailboxes-
Create mailboxPOST /v1/account/{account}/mailboxpath
Delete mailboxDELETE /v1/account/{account}/mailboxpath
Configure webhooksPOST /v1/settingswebhooks, webhookEvents
Manage templatesPOST /v1/templates/templatename, content, format
View outboxGET /v1/outbox-
Cancel queued emailDELETE /v1/outbox/{queueId}-
Generate auth formPOST /v1/authentication/formaccount, redirectUrl

Complete API Endpoints

Account Management

MethodEndpointDescription
POST/v1/accountRegister new email account
GET/v1/accountsList all accounts (paginated)
GET/v1/account/{account}Get account details and status
PUT/v1/account/{account}Update account configuration
DELETE/v1/account/{account}Delete account
PUT/v1/account/{account}/reconnectForce reconnection
PUT/v1/account/{account}/flushReset sync state, re-index
PUT/v1/account/{account}/syncTrigger immediate sync
GET/v1/account/{account}/oauth-tokenGet current OAuth2 access token
POST/v1/verifyAccountTest account credentials
POST/v1/authentication/formGenerate hosted auth form URL
GET/v1/autoconfigAuto-detect IMAP/SMTP settings
GET/v1/account/{account}/server-signaturesList server signatures for account

Message Operations

MethodEndpointDescription
GET/v1/account/{account}/messagesList messages in mailbox
GET/v1/account/{account}/message/{message}Get message details
GET/v1/account/{account}/message/{message}/sourceGet raw RFC822 source
PUT/v1/account/{account}/message/{message}Update flags/labels
DELETE/v1/account/{account}/message/{message}Delete message
PUT/v1/account/{account}/message/{message}/moveMove to another mailbox
POST/v1/account/{account}/messageUpload message to mailbox
POST/v1/account/{account}/searchSearch messages
GET/v1/account/{account}/text/{text}Get message text part
GET/v1/account/{account}/attachment/{attachment}Download attachment

Bulk Message Operations

MethodEndpointDescription
PUT/v1/account/{account}/messagesUpdate flags or labels on every message matching a search
PUT/v1/account/{account}/messages/moveMove multiple messages
PUT/v1/account/{account}/messages/deleteDelete multiple messages

Export Operations (Beta)

MethodEndpointDescription
POST/v1/account/{account}/exportCreate new bulk message export
GET/v1/account/{account}/exportsList account exports (paginated)
GET/v1/account/{account}/export/{exportId}Get export status and details
GET/v1/account/{account}/export/{exportId}/downloadDownload completed export file
DELETE/v1/account/{account}/export/{exportId}Cancel or delete export

Mailbox Operations

MethodEndpointDescription
GET/v1/account/{account}/mailboxesList all mailboxes/folders
POST/v1/account/{account}/mailboxCreate mailbox
PUT/v1/account/{account}/mailboxRename mailbox
DELETE/v1/account/{account}/mailboxDelete mailbox

Sending Emails

MethodEndpointDescription
POST/v1/account/{account}/submitSend/queue email
POST/v1/account/{account}/message/{message}/submitSend a stored draft by message ID
GET/v1/outboxList queued emails
GET/v1/outbox/{queueId}Get queued email details
DELETE/v1/outbox/{queueId}Cancel queued email

Templates

MethodEndpointDescription
GET/v1/templatesList all templates
POST/v1/templates/templateCreate template
GET/v1/templates/template/{template}Get template
PUT/v1/templates/template/{template}Update template
DELETE/v1/templates/template/{template}Delete template
DELETE/v1/templates/account/{account}Delete all templates for an account

Settings & Configuration

MethodEndpointDescription
GET/v1/settingsGet all settings
POST/v1/settingsUpdate settings
GET/v1/settings/queue/{queue}Get queue configuration
PUT/v1/settings/queue/{queue}Update queue configuration

Webhooks

MethodEndpointDescription
GET/v1/webhookRoutesList webhook routes
GET/v1/webhookRoutes/webhookRoute/{webhookRoute}Get a webhook route

Webhook routes are read-only through the API - create and edit them in the EmailEngine dashboard. Webhook delivery itself is configured via POST /v1/settings (webhooks, webhooksEnabled, webhookEvents).

OAuth2 Applications

MethodEndpointDescription
GET/v1/oauth2List OAuth2 apps
POST/v1/oauth2Register OAuth2 app
GET/v1/oauth2/{app}Get OAuth2 app
PUT/v1/oauth2/{app}Update OAuth2 app
DELETE/v1/oauth2/{app}Delete OAuth2 app
POST/v1/oauth2/{app}/verifyVerify OAuth2 app setup (read-only diagnostic)

SMTP Gateway

MethodEndpointDescription
GET/v1/gatewaysList SMTP gateways
POST/v1/gatewayRegister gateway
GET/v1/gateway/{gateway}Get gateway
PUT/v1/gateway/edit/{gateway}Update gateway
DELETE/v1/gateway/{gateway}Delete gateway

Access Tokens

MethodEndpointDescription
GET/v1/tokensList tokens, each with id, the SHA-256 hash identifying it. Add ?account={account} to narrow it to one account
POST/v1/tokensCreate token
GET/v1/tokens/{token}Get one token's metadata
GET/v1/tokens/{token}/logRead the token's audit log, when the audit log is enabled
DELETE/v1/tokens/{token}Delete token (accepts the token value or its id hash)

Blocklists

MethodEndpointDescription
GET/v1/blocklistsList blocklists
GET/v1/blocklist/{listId}Get blocklist entries
POST/v1/blocklist/{listId}Add to blocklist
DELETE/v1/blocklist/{listId}Remove from blocklist

Monitoring & Stats

MethodEndpointDescription
GET/v1/statsGet usage statistics
GET/v1/logs/{account}Get account logs
GET/v1/changesGet recent changes
GET/v1/licenseGet license info
POST/v1/licenseRegister a license key
DELETE/v1/licenseRemove the license key
GET/v1/pubsub/statusList Pub/Sub subscription status

Deliverability Testing

MethodEndpointDescription
POST/v1/delivery-test/account/{account}Start delivery test
GET/v1/delivery-test/check/{deliveryTest}Check test results

MCP Endpoint (AI Agents)

EmailEngine also serves the Model Context Protocol, so an AI agent can call a curated tool set instead of the REST API. Off by default; an admin enables it under Configuration > MCP (mcpEnabled setting). Full docs: MCP for AI Agents.

AspectDetails
EndpointPOST /mcp
TransportStreamable HTTP, JSON-RPC 2.0, stateless (no session id)
Protocol revisions2026-07-28 (modern, per-request _meta plus mirrored headers), 2025-11-25 and 2025-06-18 (legacy initialize handshake)
AuthenticationAuthorization: Bearer <token>. Prefer a token with the mcp scope, which opens this endpoint only
Methodsinitialize, server/discover, ping, tools/list, tools/call, resources/list, resources/read, resources/templates/list, subscriptions/listen
Resourcesemailengine://account/{account} per connected account
OAuthmcpOAuthEnabled plus a Service URL adds dynamic client registration and an authorization code + PKCE flow for web connectors

Every tool call is dispatched as the equivalent REST request with the caller's own credential, so scopes, permission narrowing, account binding, IP and referrer restrictions, rate limits and the audit log all apply unchanged. tools/list is filtered per credential, and a token bound to one account gets tools with no account argument (the binding is applied on dispatch).

Tool schemas are narrower than the endpoints they wrap: operator-level fields are hidden (send_message has no gateway, envelope, headers, raw, tracking or mailMerge), rendering options are pinned, and every paged listing caps pageSize at 100. get_message returns the body inline as sanitized web-safe HTML (32768-character budget, text.hasMore when longer, quoted history wrapped in <details class="ee-collapsed-thread">); get_message_text returns the same rendering with a 65536-character budget. A tool result is truncated above 128 KB.

MCP Tools

ToolBehaviorWraps
list_accountsread-onlyGET /v1/accounts
get_accountread-onlyGET /v1/account/{account}
list_mailboxesread-onlyGET /v1/account/{account}/mailboxes
list_messagesread-onlyGET /v1/account/{account}/messages
search_messagesread-onlyPOST /v1/account/{account}/search
get_messageread-onlyGET /v1/account/{account}/message/{message} (body inline)
get_message_textread-onlyGET /v1/account/{account}/text/{text}
get_attachmentread-onlyGET /v1/account/{account}/attachment/{attachment}
update_messagewritePUT /v1/account/{account}/message/{message}
move_messagewritePUT /v1/account/{account}/message/{message}/move
delete_messagedestructiveDELETE /v1/account/{account}/message/{message}
create_draftwritePOST /v1/account/{account}/message
send_messagesends emailPOST /v1/account/{account}/submit
get_outboxread-onlyGET /v1/outbox
list_templatesread-onlyGET /v1/templates

MCP Access Levels

LevelPermissions record
Read-only (default){"actions":["read"],"groups":["account","mailbox","message","outbox","template"]}
Mail agent{"actions":["read","write","send"],"groups":["account","mailbox","message","submit","outbox","template"]}
Full accessno permissions record; the mcp scope is the bound

Bind an agent token to one account whenever possible - a bound credential loses the instance-wide tools (list_accounts, get_outbox), reaches nothing else, and its remaining tools drop the account argument.

Replies and forwards go through the reference block on send_message and create_draft: {message, action: reply|reply-all|forward, inline, forwardAttachments}. EmailEngine derives the subject, the recipients and the threading headers from the referenced message.

Webhook Events

Message Events

EventDescriptionKey Payload Fields
messageNewNew email receiveddata.id, data.from, data.to, data.subject, data.text
messageDeletedEmail deleteddata.id
messageUpdatedFlags/labels changeddata.id, data.changes
messageMissingMessage not founddata.id

Delivery Events

EventDescriptionKey Payload Fields
messageSentEmail sent successfullydata.messageId, data.response
messageDeliveryErrorDelivery attempt faileddata.error, data.job.attemptsMade
messageFailedDelivery permanently faileddata.error, data.messageId
messageBounceBounce notification receiveddata.recipient, data.bounceMessage
messageComplaintSpam complaint (ARF)data.recipient

Account Events

EventDescriptionKey Payload Fields
accountAddedAccount registeredaccount
accountDeletedAccount removedaccount
accountInitializedAccount ready, first sync doneaccount, data.initialized
authenticationErrorAuth failedaccount, data.response
authenticationSuccessAuth succeededaccount
connectErrorConnection failedaccount, data.response

Mailbox Events

EventDescriptionKey Payload Fields
mailboxNewFolder createddata.path
mailboxDeletedFolder deleteddata.path
mailboxResetFolder UIDVALIDITY changeddata.path

Tracking Events

EventDescriptionKey Payload Fields
trackOpenEmail openeddata.messageId, data.recipient
trackClickLink clickeddata.messageId, data.url
listUnsubscribeUser unsubscribeddata.recipient
listSubscribeUser re-subscribeddata.recipient

Export Events

EventDescriptionKey Payload Fields
exportCompletedExport finished successfullydata.exportId, data.messagesExported, data.bytesWritten
exportFailedExport faileddata.exportId, data.error

Common Patterns

Pattern 1: Register an IMAP/SMTP Account

curl -X POST "https://emailengine.example.com/v1/account" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"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": 465,
"secure": true,
"auth": {
"user": "john@example.com",
"pass": "password"
}
}
}'

Pattern 2: Register OAuth2 Account (Gmail/Outlook/Mail.ru)

curl -X POST "https://emailengine.example.com/v1/account" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"account": "user123",
"email": "john@gmail.com",
"oauth2": {
"provider": "OAUTH_APP_ID",
"refreshToken": "REFRESH_TOKEN",
"auth": {
"user": "john@gmail.com"
}
}
}'

Pattern 3: Send a Simple Email

curl -X POST "https://emailengine.example.com/v1/account/user123/submit" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": [{"address": "recipient@example.com", "name": "Recipient"}],
"subject": "Hello",
"text": "Plain text body",
"html": "<p>HTML body</p>"
}'

Pattern 4: Send Email with Attachments

curl -X POST "https://emailengine.example.com/v1/account/user123/submit" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": [{"address": "recipient@example.com"}],
"subject": "Document attached",
"text": "Please find the document attached.",
"attachments": [
{
"filename": "document.pdf",
"content": "BASE64_ENCODED_CONTENT",
"contentType": "application/pdf"
}
]
}'

Pattern 5: Reply to an Email

curl -X POST "https://emailengine.example.com/v1/account/user123/submit" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": [{"address": "original-sender@example.com"}],
"subject": "Re: Original Subject",
"text": "My reply",
"reference": {
"message": "ORIGINAL_MESSAGE_ID",
"action": "reply"
}
}'

Pattern 6: Forward an Email

curl -X POST "https://emailengine.example.com/v1/account/user123/submit" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": [{"address": "forward-to@example.com"}],
"subject": "Fwd: Original Subject",
"text": "Forwarding this email",
"reference": {
"message": "ORIGINAL_MESSAGE_ID",
"action": "forward"
}
}'

Pattern 7: Search Messages

curl -X POST "https://emailengine.example.com/v1/account/user123/search" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"search": {
"from": "sender@example.com",
"subject": "invoice",
"unseen": true,
"since": "2024-01-01"
}
}'

Pattern 8: Configure Webhooks

curl -X POST "https://emailengine.example.com/v1/settings" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"webhooks": "https://your-app.com/webhooks",
"webhooksEnabled": true,
"webhookEvents": ["messageNew", "messageSent", "messageFailed"]
}'

Pattern 9: Handle Webhook (Node.js)

app.post('/webhooks', express.json(), (req, res) => {
const { event, account, data } = req.body;

// Acknowledge immediately
res.status(200).json({ success: true });

// Process asynchronously
switch (event) {
case 'messageNew':
// New email: data.id, data.from, data.to, data.subject
break;
case 'messageSent':
// Email sent: data.messageId
break;
case 'messageFailed':
// Delivery failed: data.error
break;
}
});

Pattern 10: List and Paginate Messages

# First page (20 messages)
curl "https://emailengine.example.com/v1/account/user123/messages?path=INBOX&page=0&pageSize=20" \
-H "Authorization: Bearer YOUR_TOKEN"

# Next page
curl "https://emailengine.example.com/v1/account/user123/messages?path=INBOX&page=1&pageSize=20" \
-H "Authorization: Bearer YOUR_TOKEN"

Pattern 11: Mail Merge (Bulk Personalized Emails)

curl -X POST "https://emailengine.example.com/v1/account/user123/submit" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": "Hello {{name}}",
"html": "<p>Dear {{name}}, your order #{{orderId}} is ready.</p>",
"mailMerge": [
{
"to": [{"address": "alice@example.com"}],
"params": {"name": "Alice", "orderId": "1001"}
},
{
"to": [{"address": "bob@example.com"}],
"params": {"name": "Bob", "orderId": "1002"}
}
]
}'

Pattern 12: Generate Hosted Authentication Form

# Generate form URL
curl -X POST "https://emailengine.example.com/v1/authentication/form" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"account": "new-user",
"name": "New User",
"redirectUrl": "https://your-app.com/settings"
}'

# Response: {"url": "https://emailengine.example.com/accounts/new?data=..."}
# Redirect user to this URL to complete authentication

# Add "expectedEmail" to reject the setup unless the user authenticates as that
# address. Stored on the account, so it also covers later links that omit it.
# Comparison is exact apart from case, so Gmail dot/googlemail/+tag variants
# are rejected - pass the address exactly as the provider reports it.
# A rejected setup is NOT redirected to redirectUrl: EmailEngine shows the user
# both addresses and a button to retry. Only success redirects.
# Clear it with PUT /v1/account/{account} {"expectedEmail": null}

Account Types

TypeValueDescriptionRequirements
IMAP/SMTPimapStandard email protocolHost, port, credentials
Gmail OAuth2gmailGmail via OAuth2 + IMAPOAuth2 app, refresh token
Gmail APIgmailGmail native APIOAuth2 app, Cloud Pub/Sub
Gmail Service AccountgmailServiceGoogle Workspace domain-wideService account key
Outlook OAuth2outlookMicrosoft via OAuth2Azure AD app, refresh token
MS Graph APIoutlookMicrosoft native APIAzure AD app, graph subscription
Outlook Application AccessoutlookServiceMicrosoft 365 via client credentialsAzure AD app, tenant ID
Mail.ru OAuth2mailRuMail.ru via OAuth2 + IMAPOAuth2 app, refresh token
Delegated (Microsoft 365 shared mailbox)delegatedReported type: the account borrows another account's OAuth2 grant (oauth2.auth.delegatedAccount)Parent outlook or outlookService account with a working OAuth2 app

The type field in an account response is derived, not stored. Besides the values above it can be sending (SMTP-only account, no IMAP or OAuth2 configuration), oauth2 (the account references an OAuth2 application that no longer exists) and invalid (a delegated account whose parent is missing or broken). None of these three is something a request can ask for.

Account States

StateDescriptionNext Steps
initBeing initializedWait
connectingEstablishing connectionWait
syncingInitial or periodic sync in progressWait
connectedActive and operationalReady for API calls
disconnectedConnection lostWill auto-reconnect
authenticationErrorCredentials rejectedUpdate credentials or re-authorize
connectErrorNetwork/server errorCheck connectivity
pausedSyncing paused through the APIResume syncing
unsetNot syncing: no IMAP or OAuth2 configuration is set, or syncing was switched off, by the operator (imap.disabled) or automatically after repeated authentication failures (authFailureDisabledAt is set)Finish setup, or supply working credentials to lift an automatic switch-off

Account Object

GET /v1/account/{account} returns these fields (GET /v1/accounts returns the same shape per entry, without imap, smtp and oauth2 credentials):

FieldTypeDescription
accountstringAccount ID
name, emailstringDisplay name and default address
statestringOne of the states above
typestringimap, gmail, gmailService, outlook, outlookService, mailRu, oauth2, delegated, sending or invalid
appstringOAuth2 application ID, for OAuth2 accounts
imapobjectStored IMAP settings with the password masked. imap.disabled: true means syncing is switched off
smtpobjectStored SMTP settings with the password masked
oauth2objectOAuth2 grant details (provider, user, scopes, token expiry), no secrets
authFailureDisabledAtstring or nullRead-only. When the authentication-failure safety net switched syncing off, or null. imap.disabled is also the operator's own send-only switch, so this is what tells an automatic disable from a deliberate one. Supplying working credentials (re-authorize an OAuth2 account, or save new IMAP settings) lifts it
sendOnlybooleanThe account sends mail but does not sync a mailbox
lastErrorobjectMost recent error (response, serverResponseCode)
syncTimestringLast sync time (IMAP accounts)
connectionsintegerOpen IMAP connections (IMAP accounts)
countersobjectEvent counters
quotaobjectMailbox quota, when the server reports one
webhooksstringAccount-specific webhook URL
notifyFromstring or nullOnly send webhooks for messages received after this date
subconnections, patharrayExtra folders watched in real time, and the folders synced at all

Since 2.79.4 both re-authorization through the hosted form and PUT /v1/account/{account} with working credentials clear authFailureDisabledAt and reconnect the account.

Error Handling

HTTP Status Codes

CodeMeaningAction
200Success-
400Bad RequestCheck request parameters
401UnauthorizedVerify API token
403ForbiddenCheck token permissions
404Not FoundVerify account/message ID
413Payload Too LargeReduce the message size
422Unprocessable EntityThe account's backend cannot do this (for example a label filter on a non-Gmail IMAP account). Do not retry
429Rate LimitedRetry after ttl seconds from the body
500Server ErrorRetry after delay
503UnavailableThe account is not connected; the body carries state and a code
504Gateway TimeoutA worker thread did not answer within EENGINE_TIMEOUT

Error Response Format

{
"statusCode": 400,
"error": "Bad Request",
"message": "Human-readable message",
"code": "ErrorCode"
}

error carries the HTTP status phrase, not the explanation. Read message.

Common Error Codes

CodeDescription
MessageNotFound404, message does not exist
FolderNotFound404, mailbox path does not exist
NotFound404, template, webhook route, OAuth2 app or gateway does not exist
SMTPUnavailable404, the account has no SMTP or OAuth2 configuration to send with
AccountAlreadyExists400, the OAuth2 user is already bound to another account under the same OAuth2 application (re-registering an account ID is an update, not an error)
MissingServerExtension422, the IMAP server lacks an extension the request needs
NotYetConnected503, the account has not connected yet
AuthenticationFails503, the account's credentials are rejected
ConnectionError503, the mail server cannot be reached
NotSyncing503, syncing is switched off for the account (state unset)
IMAPUnavailable503, the account's IMAP connection is not up right now
Timeout504, a worker thread did not answer in time

A missing account is a plain 404 with the message Account record was not found for requested ID and no code. Validation failures are a plain 400 with message: "Invalid input" and a fields array. 401 and 403 responses carry no code.

Decision Trees

Choosing Account Type

Gmail API vs Gmail IMAP

MS Graph vs Outlook IMAP

Key Settings (via POST /v1/settings)

SettingTypeDescription
webhooksstringWebhook URL
webhooksEnabledbooleanEnable webhook delivery
webhookEventsarrayEvent types to trigger
inboxNewOnlybooleanOnly trigger messageNew for Inbox folder
serviceUrlstringPublic URL of EmailEngine instance
serviceSecretstringHMAC secret for webhook signature verification
resolveGmailCategoriesbooleanDetect Gmail tabs (Primary, Social, etc.) for IMAP
smtpEhloNamestringCustom EHLO hostname for SMTP connections
ignoreMailCertErrorsbooleanAccept invalid TLS certificates
trackOpensbooleanEnable email open tracking
trackClicksbooleanEnable click tracking
imapIndexerstringIndexing strategy: full or fast
scriptEnvstringJSON environment variables for pre-processing scripts
httpProxyEnabledbooleanRoute outbound HTTP/HTTPS requests through proxy
httpProxyUrlstringHTTP/SOCKS proxy URL for outbound requests
pageBrandNamestringCustom brand name displayed in page titles
notifyTextbooleanInclude plain text content in webhook payloads
notifyTextSizenumberMax text size in webhook payloads (bytes)
notifyAttachmentsbooleanInclude attachments in webhook payloads
notifyAttachmentSizenumberMax attachment size in webhook payloads (bytes)
notifyCalendarEventsbooleanInclude calendar events in webhook payloads
notifyWebSafeHtmlbooleanReplace the HTML body in webhook payloads with a web-safe version (sanitized, inline images embedded, quoted thread history folded into <details class="ee-collapsed-thread">)
localestringUI language/locale
timezonestringDefault timezone (IANA identifier)
templateHeaderstringCustom HTML header for hosted pages
templateHtmlHeadstringCustom HTML for page head section
imapClientNamestringIMAP ID extension client name
imapClientVersionstringIMAP ID extension version
imapClientVendorstringIMAP ID extension vendor
imapClientSupportUrlstringIMAP ID extension support URL

Per-Account IMAP Settings

SettingTypeDefaultDescription
disabledbooleanfalseDisable IMAP (send-only mode). Also set automatically by the authentication-failure safety net; authFailureDisabledAt tells the two apart
resyncDelaynumber900Seconds between full mailbox resyncs
sentMailPathstringautoCustom Sent folder path
draftsMailPathstringautoCustom Drafts folder path
junkMailPathstringautoCustom Junk folder path
trashMailPathstringautoCustom Trash folder path
archiveMailPathstringautoCustom Archive folder path
useAuthServerbooleanfalseFetch credentials from external auth server

Environment Variables

VariableRequiredDescription
EENGINE_REDISNoRedis URL (default: redis://127.0.0.1:6379/8)
EENGINE_SECRETProdEncryption key for credentials (32+ hex chars)
EENGINE_PORTNoAPI port (default: 3000)
EENGINE_HOSTNoBind address (default: 127.0.0.1)
EENGINE_WORKERSNoAccount worker count - IMAP, Gmail API, Outlook/Graph (default: 4)
EENGINE_WORKERS_APINoAPI/HTTP worker count (default: 1); values >1 need SO_REUSEPORT (Linux, Node.js 23.1+)
EENGINE_WORKERS_WEBHOOKSNoWebhook worker count (default: 1)
EENGINE_WORKERS_SUBMITNoSubmit worker count (default: 1)
EENGINE_WORKERS_EXPORTNoExport worker count (default: 1)
EENGINE_LOG_LEVELNoLog level (trace/debug/info/warn/error)
EENGINE_CORS_MAX_AGENoCORS preflight cache duration in seconds (default: 60)
EENGINE_HTTP_PROXY_ENABLEDNoEnable HTTP proxy for outbound requests
EENGINE_HTTP_PROXY_URLNoHTTP/SOCKS proxy URL for outbound requests

Submit API Key Parameters

The POST /v1/account/{account}/submit endpoint accepts these key parameters:

ParameterTypeDescription
toarrayRecipients [{address, name}] (required)
ccarrayCC recipients
bccarrayBCC recipients
subjectstringEmail subject
textstringPlain text body
htmlstringHTML body
fromobjectOverride sender {address, name}
replyToarrayReply-To addresses [{address, name}]
attachmentsarrayAttachments [{filename, content, contentType}]
headersobjectCustom headers
referenceobjectFor replies/forwards {message, action}
templatestringTemplate ID to use
mailMergearrayBulk send with personalization
sendAtstringSchedule sending (ISO 8601)
trackOpensbooleanEnable open tracking
trackClicksbooleanEnable click tracking
copybooleanSave to Sent folder; unset follows the account's copy setting. SMTP deliveries only
dryRunbooleanPreview without sending
gatewaystringUse specific SMTP gateway
deliveryAttemptsnumberMax retry attempts

To send an email that already exists as a draft, use POST /v1/account/{account}/message/{message}/submit with the draft's message ID instead of composing content. The optional body accepts the delivery options above (envelope, copy, sentMailPath, sendAt, deliveryAttempts, gateway, dsn, proxy, localAddress) but no content fields - the draft is sent as stored. Gmail and MS Graph accounts send it with the provider's native draft-send call; the draft is removed after sending on all account types.

Search Parameters

The POST /v1/account/{account}/search endpoint accepts these search criteria:

ParameterTypeDescription
fromstringSender address/name
tostringRecipient address/name
subjectstringSubject contains
bodystringBody contains
unseenbooleanUnread only
flaggedbooleanStarred/flagged only
sincestringAfter date (YYYY-MM-DD)
beforestringBefore date (YYYY-MM-DD)
headerobjectCustom header match
emailIdstringSpecific message ID
threadIdstringSpecific thread ID
labelsobject{ "has": [...], "not": [...] } - filter by Gmail labels or Outlook categories. has matches messages with ALL listed labels, not excludes messages with ANY of them. Gmail and MS Graph accounts only; returns HTTP 422 if the account cannot satisfy the filter

See Also