Accounts API
The Accounts API allows you to programmatically manage email accounts in EmailEngine. You can register new accounts, update settings, monitor connection status, and handle OAuth2 authentication.
Overview
Email accounts are the core resource in EmailEngine. Each account represents a connection to an email service (Gmail, Outlook, IMAP/SMTP server) and maintains:
- Connection credentials (OAuth2 tokens or passwords)
- Mailbox synchronization state
- Account-specific settings
- Connection status and health
Account Object Structure
{
"account": "user@example.com",
"name": "John Doe",
"email": "user@example.com",
"state": "connected",
"syncTime": 1640995200000,
"notifyFrom": "2025-01-01T00:00:00.000Z",
"lastError": null,
"imap": {
"host": "imap.gmail.com",
"port": 993,
"secure": true,
"disabled": false
},
"smtp": {
"host": "smtp.gmail.com",
"port": 465,
"secure": true,
"disabled": false
},
"oauth2": {
"enabled": true,
"provider": "gmail",
"auth": {
"user": "user@example.com"
}
}
}
Account States
| State | Description |
|---|---|
init | Account registered, connection not yet attempted |
connecting | Attempting to connect to mail server |
syncing | Connected and synchronizing mailboxes |
connected | Successfully connected and fully synced |
authenticationError | Authentication failed (invalid credentials or expired token) |
connectError | Connection failed (network or server issue) |
disconnected | Connection closed or lost |
unset | Initial state before any connection attempt (internal) |
Common Operations
1. Register Account
Register a new email account with EmailEngine.
Endpoint: POST /v1/account
Request Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
account | string | Yes | Unique account identifier (usually email address) |
name | string | Yes | Display name for the account |
email | string | No | Email address (defaults to account) |
imap | object | Yes* | IMAP connection settings |
smtp | object | No | SMTP connection settings |
oauth2 | object | No | OAuth2 settings |
notifyFrom | string | No | ISO date to send webhooks from (default: account creation time) |
*Either imap or oauth2 is required.
IMAP Configuration:
{
"host": "imap.example.com",
"port": 993,
"secure": true,
"auth": {
"user": "username",
"pass": "password"
}
}
SMTP Configuration:
{
"host": "smtp.example.com",
"port": 465,
"secure": true,
"auth": {
"user": "username",
"pass": "password"
}
}
Examples:
- cURL
- Python
curl -X POST http://localhost:3000/v1/account \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"account": "user@example.com",
"name": "John Doe",
"imap": {
"host": "imap.example.com",
"port": 993,
"secure": true,
"auth": {
"user": "user@example.com",
"pass": "password"
}
}
}'
import requests
response = requests.post(
'http://localhost:3000/v1/account',
headers={
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'
},
json={
'account': 'user@example.com',
'name': 'John Doe',
'imap': {
'host': 'imap.example.com',
'port': 993,
'secure': True,
'auth': {
'user': 'user@example.com',
'pass': 'password'
}
}
}
)
result = response.json()
print(f"Account registered: {result['account']}")
Pseudo code:
// Register a new email account
response = HTTP_POST("http://localhost:3000/v1/account", {
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
},
body: {
account: "user@example.com",
name: "John Doe",
imap: {
host: "imap.example.com",
port: 993,
secure: true,
auth: {
user: "user@example.com",
pass: "password"
}
},
smtp: {
host: "smtp.example.com",
port: 465,
secure: true,
auth: {
user: "user@example.com",
pass: "password"
}
}
}
})
result = PARSE_JSON(response.body)
PRINT("Account registered: " + result.account)
Response:
{
"account": "user@example.com",
"state": "init"
}
Use Cases:
- Onboarding new users to your application
- Allowing users to connect multiple email accounts
- Automated account provisioning in bulk
2. List Accounts
Retrieve all registered accounts.
Endpoint: GET /v1/accounts
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
page | number | Page number (0-indexed) |
pageSize | number | Items per page (default 20) |
state | string | Filter by account state |
query | string | Filter accounts by string match |
Examples:
- cURL
- Pseudo code
curl "http://localhost:3000/v1/accounts?pageSize=50" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
// List all accounts with pagination
response = HTTP_GET("http://localhost:3000/v1/accounts?pageSize=50", {
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
})
data = PARSE_JSON(response.body)
PRINT("Total accounts: " + data.total)
for each account in data.accounts {
PRINT(account.account + ": " + account.state)
}
Response:
{
"total": 2,
"page": 0,
"pages": 1,
"accounts": [
{
"account": "user1@example.com",
"name": "John Doe",
"email": "user1@example.com",
"state": "connected"
},
{
"account": "user2@example.com",
"name": "Jane Smith",
"email": "user2@example.com",
"state": "authenticationError"
}
]
}
Use Cases:
- Dashboard displaying all connected accounts
- Health monitoring across accounts
- Bulk operations on multiple accounts
3. Get Account Details
Retrieve detailed information about a specific account.
Endpoint: GET /v1/account/:account
Path Parameters:
| Parameter | Description |
|---|---|
account | Account identifier |
Examples:
- cURL
- Pseudo code
curl "http://localhost:3000/v1/account/user@example.com" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
// Get detailed information about a specific account
account = "user@example.com"
response = HTTP_GET(
"http://localhost:3000/v1/account/" + URL_ENCODE(account),
{
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
}
)
details = PARSE_JSON(response.body)
PRINT("Connection state: " + details.state)
PRINT("Last sync: " + details.syncTime)
Response:
{
"account": "user@example.com",
"name": "John Doe",
"email": "user@example.com",
"state": "connected",
"syncTime": 1640995200000,
"lastError": null,
"counters": {
"sent": 42,
"received": 128
}
}
Use Cases:
- Displaying account status in user interface
- Checking connection health
- Retrieving account statistics
4. Update Account
Update account settings or credentials.
Endpoint: PUT /v1/account/:account
Request Body:
{
"name": "New Display Name",
"imap": {
"partial": true,
"port": 993
},
"smtp": {
"partial": true,
"port": 465
}
}
Use "partial": true inside imap, smtp, or oauth2 objects to update only the specified fields instead of replacing the entire configuration. Without this flag, the entire object will be replaced, potentially losing existing settings.
Note: The partial flag only works for main-level objects (imap, smtp, oauth2), not for nested objects like imap.auth.
Examples:
- cURL
- Pseudo code
curl -X PUT "http://localhost:3000/v1/account/user@example.com" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Name",
"imap": {
"partial": true,
"port": 993
}
}'
// Update account settings or credentials
account = "user@example.com"
response = HTTP_PUT(
"http://localhost:3000/v1/account/" + URL_ENCODE(account),
{
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
},
body: {
name: "Updated Name",
imap: {
partial: true,
port: 993
}
}
}
)
result = PARSE_JSON(response.body)
PRINT("Account updated: " + result.success)
Use Cases:
- Updating account credentials after password change
- Changing display names
- Modifying connection settings
5. Delete Account
Remove an account and stop synchronization.
Endpoint: DELETE /v1/account/:account
Examples:
- cURL
- Pseudo code
curl -X DELETE "http://localhost:3000/v1/account/user@example.com" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
// Delete an account
account = "user@example.com"
response = HTTP_DELETE(
"http://localhost:3000/v1/account/" + URL_ENCODE(account),
{
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
}
)
result = PARSE_JSON(response.body)
PRINT("Account deleted: " + result.success)
Response:
{
"success": true,
"account": "user@example.com"
}
Use Cases:
- User disconnecting their email account
- Removing inactive accounts
- Cleanup during offboarding
6. Reconnect Account
Force reconnection to mail server (useful after credential updates).
Endpoint: PUT /v1/account/:account/reconnect
Examples:
- cURL
- Pseudo code
curl -X PUT "http://localhost:3000/v1/account/user@example.com/reconnect" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
// Force account reconnection
account = "user@example.com"
response = HTTP_PUT(
"http://localhost:3000/v1/account/" + URL_ENCODE(account) + "/reconnect",
{
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
}
)
result = PARSE_JSON(response.body)
PRINT("Reconnection initiated: " + result.success)
Use Cases:
- Testing connection after credential update
- Recovering from connection errors
- Manual reconnection trigger
Account Object Reference
Complete Field Reference
| Field | Type | Description |
|---|---|---|
account | string | Unique account identifier |
name | string | Display name |
email | string | Email address |
state | string | Connection state (see Account States) |
syncTime | number | Unix timestamp of last sync |
notifyFrom | string | ISO date to send webhooks from |
lastError | object | Last error details (if any) |
imap | object | IMAP connection settings |
smtp | object | SMTP connection settings |
oauth2 | object | OAuth2 configuration |
counters | object | Message statistics |
Account States
Detailed state descriptions:
init
- Account just registered
- No connection attempt made yet
- Waiting for initial connection
connecting
- Attempting to establish connection
- Authenticating credentials
- Retrieving mailbox list
connected
- Successfully connected
- Actively syncing messages
- Healthy state
authenticationError
- Invalid credentials
- OAuth2 token expired
- Action required: update credentials
connectError
- Network connectivity issues
- Mail server unavailable
- Temporary state, will auto-retry
disconnected
- Manually disconnected via API
- Not syncing messages
- Can be reconnected
Common Patterns
Bulk Account Registration
Register multiple accounts efficiently:
// Pseudo code: Register multiple accounts in parallel
function registerAccounts(accounts) {
results = []
// Process accounts in parallel
for each acc in accounts {
response = HTTP_POST("http://localhost:3000/v1/account", {
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
},
body: acc
})
result = PARSE_JSON(response.body)
results = results + [result]
}
return results
}
// Example usage
accounts = [
{ account: "user1@example.com", name: "User 1", imap: { /* ... */ } },
{ account: "user2@example.com", name: "User 2", imap: { /* ... */ } }
]
results = registerAccounts(accounts)
PRINT("Registered " + LENGTH(results) + " accounts")
Health Monitoring
Monitor account connection health:
// Pseudo code: Monitor account health
function checkAccountHealth() {
// Get all accounts
response = HTTP_GET("http://localhost:3000/v1/accounts", {
headers: { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
})
accounts = PARSE_JSON(response.body).accounts
// Find unhealthy accounts
unhealthy = []
for each acc in accounts {
if (acc.state != "connected" AND acc.state != "connecting") {
unhealthy = unhealthy + [acc]
}
}
// Alert if issues found
if (LENGTH(unhealthy) > 0) {
PRINT("WARNING: Unhealthy accounts found")
for each acc in unhealthy {
PRINT(" - " + acc.account + ": " + acc.state)
}
// Send alerts, attempt reconnection, etc.
}
// Return summary
connected = FILTER(accounts, state == "connected")
return {
total: LENGTH(accounts),
connected: LENGTH(connected),
unhealthy: LENGTH(unhealthy)
}
}
// Run periodically (every 5 minutes)
SCHEDULE(checkAccountHealth, interval: 5 * 60 * 1000)
Credential Rotation
Update passwords programmatically:
// Pseudo code: Rotate account credentials
function rotateCredentials(account, newPassword) {
// Step 1: Update credentials
HTTP_PUT(
"http://localhost:3000/v1/account/" + URL_ENCODE(account),
{
headers: {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
},
body: {
imap: { auth: { pass: newPassword } },
smtp: { auth: { pass: newPassword } }
}
}
)
// Step 2: Force reconnection to apply new credentials
HTTP_PUT(
"http://localhost:3000/v1/account/" + URL_ENCODE(account) + "/reconnect",
{
headers: { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
}
)
PRINT("Credentials rotated and reconnected")
}
Account Synchronization Status
Track sync progress:
// Pseudo code: Get account sync status
function getSyncStatus(account) {
// Get account details
response = HTTP_GET(
"http://localhost:3000/v1/account/" + URL_ENCODE(account),
{
headers: { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
}
)
details = PARSE_JSON(response.body)
// Calculate status
currentTime = CURRENT_TIMESTAMP()
timeSinceSync = currentTime - details.syncTime
isHealthy = (details.state == "connected" AND details.lastError == null)
return {
state: details.state,
lastSync: details.syncTime,
timeSinceSync: timeSinceSync,
isHealthy: isHealthy
}
}
Error Handling
Common Errors
Account Already Exists:
{
"error": "Another account for the same OAuth2 user already exists",
"code": "AccountAlreadyExists",
"statusCode": 400
}
Solution: Use PUT to update existing account or choose different account ID.
Authentication Failed:
{
"error": "Authentication failed",
"code": "AuthenticationError",
"statusCode": 400
}
Solution: Verify credentials, check if 2FA/app passwords are required.
Account Not Found:
{
"error": "Account record was not found for requested ID",
"statusCode": 404
}
Solution: Verify account ID is correct and account exists.
Troubleshooting
For accounts stuck in error states:
- Check
lastErrorfield for details - Verify credentials are current
- Test connection with manual reconnect
- Check mail server accessibility
- Review OAuth2 token expiration