EmailEngine CLI
The EmailEngine command line interface manages tokens, licenses, passwords, accounts, and encryption. It talks to Redis directly, so it can run anywhere that can reach the database, whether or not the server is running.
Overview
Remote Administration
The EmailEngine CLI does not need to run on the same server as EmailEngine. You can run CLI commands from any location as long as you can:
- Access the Redis instance used by EmailEngine
- Know the encryption secret (for some operations)
This enables:
- Remote administration
- Automated deployment scripts
- CI/CD pipeline integration
- Backup and migration tools
Installation
The EmailEngine CLI can be installed in several ways:
Option 1: npm (Recommended)
Install globally from npm:
npm install -g emailengine-app
After installation, the emailengine command is available system-wide:
emailengine --version
emailengine help tokens
Option 2: Download Binary
Download a pre-built binary from the installation guide:
Available formats:
- Compiled binaries (Linux, macOS, Windows)
- Docker images
- Source distribution
The binary is the emailengine command and can be run directly:
./emailengine [command] [options]
Option 3: From Source
If running from source code, install globally from the project directory:
# From the EmailEngine directory
npm install -g .
Getting Help
EmailEngine provides a dynamic help system that adapts to your terminal width:
# Show all available commands
emailengine --help
emailengine -h
emailengine help
View command-specific help:
emailengine help tokens
emailengine help license
emailengine help check-bounce
The --help flag is only recognized on its own. emailengine tokens --help runs the tokens command without a subcommand, so use the help <command> form. Help is printed on stderr. An unknown command is refused with Unknown command and exit status 1 rather than starting the server.
One command is not listed by the help output: emailengine webhooks prints the webhook event table that the EmailEngine README carries, and exits with status 1. It is a maintenance helper and needs no Redis connection.
Version Information
emailengine --version
emailengine -v
emailengine version
Output:
EmailEngine v2.82.0 (LICENSE_EMAILENGINE)
Configuration Arguments
Essential Arguments
Redis Connection
Required for most commands:
--dbs.redis="redis://host:port/db"
Examples:
# Local Redis, database 0
--dbs.redis="redis://127.0.0.1:6379/0"
# Remote Redis with password
--dbs.redis="redis://:password@remote.example.com:6379/8"
# Redis with username and password
--dbs.redis="redis://user:password@remote.example.com:6379/8"
# TLS connection (Redis over TLS)
--dbs.redis="rediss://user:password@remote.example.com:6380/8"
Important: Use the same Redis database number as your EmailEngine instance. EmailEngine accepts only redis:// and rediss:// (TLS) connection strings - Redis Sentinel and Redis Cluster connection URLs are not supported.
Encryption Secret
Required for encryption-related operations:
--service.secret="your-encryption-secret"
When needed:
- Account export with encrypted fields
- Encryption migration (
encryptcommand)
Not needed for:
- Token operations (tokens are stored as hashes, not encrypted)
- License operations
- Password operations
Commands
Run EmailEngine Server
Start the EmailEngine application:
emailengine
With custom configuration:
emailengine \
--dbs.redis="redis://127.0.0.1:6379/8" \
--api.port=3000 \
--api.host="0.0.0.0" \
--workers.imap=8 \
--log.level="info"
Common options:
| Option | Environment Variable | Description | Default |
|---|---|---|---|
--dbs.redis | EENGINE_REDIS | Redis connection URL | redis://127.0.0.1:6379/8 |
--api.host | EENGINE_HOST | API server host | 127.0.0.1 |
--api.port | EENGINE_PORT | API server port | 3000 |
--workers.imap | EENGINE_WORKERS | Account worker count | 4 |
--workers.webhooks | EENGINE_WORKERS_WEBHOOKS | Webhook worker count | 1 |
--log.level | EENGINE_LOG_LEVEL | Log level | trace |
--service.secret | EENGINE_SECRET | Encryption secret | None |
All Server Arguments
emailengine --help lists the options below, in the groups the help output uses. The worker, queue, API body and TLS options joined the listing in v2.79.8; before that --help showed a subset of what the code reads.
General
| Option | Description | Default |
|---|---|---|
--dbs.redis | Redis connection URL | redis://127.0.0.1:6379/8 |
--workers.imap | Account worker threads. cpus uses one per CPU core | 4 |
--settings | Pre-configured settings as a JSON string | None |
--service.secret | Key for encrypting stored credentials | None |
--service.commandTimeout | Maximum time for an IMAP command | 10s |
--service.setupDelay | Delay between assigning connections to workers | 0ms |
--log.level | Logging level | trace |
--log.raw | Log raw IMAP traffic. Includes unmasked credentials | false |
--workers.webhooks | Webhook worker threads | 1 |
--workers.submit | Submission worker threads | 1 |
--workers.export | Export worker threads. The one worker count with no environment variable | 1 |
--workers.api | API worker threads. Anything above 1 needs SO_REUSEPORT, so it falls back to 1 off Linux. cpus is accepted | 1 |
API server
| Option | Description | Default |
|---|---|---|
--api.host | Bind address | 127.0.0.1 |
--api.port | Port | 3000 |
--api.maxSize | Maximum attachment size when submitting or uploading | 5M |
--api.maxBodySize | Maximum request body for message uploads | 50M |
--api.maxPayloadTimeout | Time allowed to receive a request body | 10s |
--api.proxy | Trust X-Forwarded-For from the reverse proxy in front of the API. Seeds the Behind Reverse Proxy setting on first start; when the argument, the config key and EENGINE_API_PROXY are all absent, the setting starts out enabled | Unset |
--api.tls.certPath | Path to the TLS certificate. Setting it serves the API and admin interface over HTTPS | None |
--api.tls.keyPath | Path to the TLS private key | None |
Background tasks
| Option | Description | Default |
|---|---|---|
--queues.notify | Concurrent webhook deliveries | 1 |
--queues.submit | Concurrent email submissions | 1 |
--queues.export | Concurrent exports per export worker | 1 |
SMTP server
| Option | Description | Default |
|---|---|---|
--smtp.enabled | Enable the SMTP submission server | false |
--smtp.secret | Shared SMTP password accepted for all accounts | None |
--smtp.host | Bind address | 127.0.0.1 |
--smtp.port | Port | 2525 |
--smtp.proxy | Accept the HAProxy PROXY protocol | false |
--smtp.maxMessageSize | Maximum accepted email size | 25M |
MCP
| Option | Description | Default |
|---|---|---|
--mcp.enabled | Register the MCP endpoint routes. A deployment gate, not the on switch: the mcpEnabled setting still has to be turned on | true |
Every configuration key follows the same --section.key=value form, including keys that --help does not list. The ones EmailEngine reads that are not shown above:
| Option | Environment Variable | Description | Default |
|---|---|---|---|
--submitDelay | EENGINE_SUBMIT_DELAY | Pause between submissions | None |
--service.fetchBatchSize | EENGINE_FETCH_BATCH_SIZE | Messages per fetch batch during sync | 1000 |
--licensePath | none | Path to a license key file to load and verify at startup. A file that fails verification stops EmailEngine with exit status 13 | None |
--preparedLicense, --preparedToken, --preparedPassword | EENGINE_PREPARED_LICENSE, EENGINE_PREPARED_TOKEN, EENGINE_PREPARED_PASSWORD | The prepared settings in argument form | None |
--api.cspMode | EENGINE_CSP_MODE | How the Content-Security-Policy is delivered: enforce, report-only or off. Since v2.79.9 | enforce |
--cors.origin | EENGINE_CORS_ORIGIN | Allowed CORS origins | None |
--cors.maxAge | EENGINE_CORS_MAX_AGE | CORS preflight cache time | 60s |
--smtp.maxClients | EENGINE_SMTP_MAX_CLIENTS | Concurrent connections the SMTP server accepts. Since v2.79.9 | 100 |
--imap.maxClients | EENGINE_IMAPPROXY_MAX_CLIENTS | Concurrent connections the IMAP proxy accepts. The section is imap, not imap-proxy. Since v2.79.9 | 1000 |
--imap-proxy.enabled, --imap-proxy.host, --imap-proxy.port, --imap-proxy.secret, --imap-proxy.proxy | EENGINE_IMAP_PROXY_ENABLED, EENGINE_IMAP_PROXY_HOST, EENGINE_IMAP_PROXY_PORT, EENGINE_IMAP_PROXY_SECRET, EENGINE_IMAP_PROXY_PROXY | The IMAP proxy listener, with the same meaning as the SMTP server options | false, 127.0.0.1, 2993, none, false |
The IMAP proxy runs as a single worker started by the imapProxyServerEnabled setting; there is no worker count for it.
The Environment Variables reference lists every variable with its default and the config-file equivalent, including the ones that have no CLI form.
Configuration Files
EmailEngine supports TOML configuration files for persistent settings.
Using Configuration Files
Create a TOML file:
# /etc/emailengine/config.toml
[dbs]
redis = "redis://localhost:6379/8"
[api]
host = "0.0.0.0"
port = 3000
[log]
level = "info"
[service]
secret = "your-encryption-secret"
[workers]
imap = 8
webhooks = 2
submit = 2
Load the configuration:
emailengine --config=/etc/emailengine/config.toml
Complete Configuration Example
# /etc/emailengine/production.toml
# Database configuration
[dbs]
redis = "redis://redis.example.com:6379"
# API server configuration
[api]
host = "0.0.0.0"
port = 3000
proxy = true
maxSize = "20M"
# Worker configuration
[workers]
imap = 8
webhooks = 4
submit = 2
# Logging
[log]
level = "info"
# Service settings
[service]
secret = "your-encryption-secret-32-chars-min"
commandTimeout = "30s"
# IMAP Proxy (optional)
[imap-proxy]
enabled = true
host = "0.0.0.0"
port = 2993
secret = "imap-proxy-secret"
# SMTP Server (optional)
[smtp]
enabled = true
host = "0.0.0.0"
port = 2525
secret = "smtp-server-secret"
Run with config file:
emailengine --config=/etc/emailengine/production.toml
Configuration Precedence
A CLI argument loses to the matching EENGINE_* environment variable and wins over everything else, so a flag has no effect when the variable is set as well. Configuration Precedence lists all five layers in order.
Example:
# Configuration file has: port = 3000
# CLI argument: --api.port=4000
# Environment variable: EENGINE_PORT=5000
emailengine --config=config.toml --api.port=4000
# Result: Port 5000 (environment variable wins)
Token Management
Manage API access tokens for authentication.
Issue Token
Create a new access token:
emailengine tokens issue [options]
Options:
| Option | Short | Description | Default |
|---|---|---|---|
--description | -d | Token description | Generated at <timestamp> |
--scope | -s | One of *, api, metrics, smtp, imap-proxy, mcp-manage:<level>, mcp:<level>. Repeat the flag for several | * |
--account | -a | Bind the token to one account | None |
--dbs.redis | Redis connection | redis://127.0.0.1:6379/8 |
An unknown scope is refused with the allowed list, rather than issuing a token that cannot be used.
Examples:
# System-wide token with full access
emailengine tokens issue \
-d "Admin token" \
-s "*" \
--dbs.redis="redis://127.0.0.1:6379/8"
# API-only token
emailengine tokens issue \
-d "API token" \
-s "api" \
--dbs.redis="redis://127.0.0.1:6379/8"
# Account-specific token
emailengine tokens issue \
-d "User token for john@example.com" \
-s "api" \
-a "user123" \
--dbs.redis="redis://127.0.0.1:6379/8"
# Metrics-only token
emailengine tokens issue \
-d "Prometheus metrics" \
-s "metrics" \
--dbs.redis="redis://127.0.0.1:6379/8"
# MCP token that can observe the instance and read mail
emailengine tokens issue \
-d "MCP client" \
-s "mcp-manage:observe" \
-s "mcp:read" \
--dbs.redis="redis://127.0.0.1:6379/8"
Available scopes:
"*"- Full access (all operations)"api"- API calls only"metrics"- Prometheus metrics endpoint only"smtp"- SMTP gateway access"imap-proxy"- IMAP proxy access"mcp-manage:<level>"- MCP instance management tools, at the levelobserve,operate, oradminister"mcp:<level>"- MCP email access tools, at the levelread,mail, orfull
The two MCP scopes give no access to the REST API. Each one requires an access level after a colon, and the token carries the explicit list of grants that level stands for, the same list the admin interface and the MCP consent page mint, so it does not widen when a later release adds tools. Both MCP scopes can be issued in one token, but neither can be combined with a non-MCP scope, because one permissions record covers the whole token; issue separate tokens, or use POST /v1/tokens with an explicit permissions record. Pair an mcp token with -a to bind it to one account. See MCP Access Control for what each level allows.
Before v2.82.1, mcp-manage could not be issued here, and -s mcp issued a token with no permissions record that reached every tool the scope allowed. Since v2.82.1, a scope given without a level, such as -s mcp, is refused, so scripts that issued mcp tokens need a level added.
Output:
The token value, on stdout, with no trailing newline:
f05d76644ea39c4a2ee33e7bffe55808b716a34b51d67b388c7d60498b0f89bc
Export Token
Export token data for backup or transfer:
emailengine tokens export [options]
Options:
| Option | Short | Description |
|---|---|---|
--token | -t | Access token to export |
--dbs.redis | Redis connection |
Example:
emailengine tokens export \
-t "f05d76644ea39c4a2ee33e7bffe55808b716a34b51d67b388c7d60498b0f89bc" \
--dbs.redis="redis://127.0.0.1:6379/8"
Output:
The token record, msgpack-encoded and base64url-encoded, on stdout:
hKJpZNlAMzAxZThjNTFhZjgxM2Q3MzUxNTYzYTFlM2I1NjVkYmEzZWJjMzk4ZjI4OWZjNjgzN
Use cases:
- Backup tokens before migration
- Transfer tokens between instances
- Pre-configure tokens via environment variables
Import Token
Import previously exported token data:
emailengine tokens import [options]
Options:
| Option | Short | Description |
|---|---|---|
--token | -t | Exported token data (base64url) |
--dbs.redis | Redis connection |
Example:
emailengine tokens import \
-t "hKJpZNlAMzAxZThjNTFhZjgxM2Q3MzUxNTYzYTFlM2I1NjVkYmEzZWJjMzk4ZjI4OWZjNjgzN" \
--dbs.redis="redis://127.0.0.1:6379/8"
Output:
Token was imported
Important: Use the exported data, not the original token. The same exported value is what EENGINE_PREPARED_TOKEN accepts.
License Management
Manage EmailEngine licenses.
Show the License Text
emailengine license
This prints the version on stdout and the EmailEngine license agreement on stderr, so emailengine license 2>/dev/null leaves you with just the version string. It reports the terms EmailEngine is distributed under, not the license key installed on an instance.
For the installed key, read GET /v1/license, which returns whether the license is active, its type, and the details of the key, or open the License page in the admin interface.
Export License
Export the installed license key for backup or transfer:
emailengine license export --dbs.redis="redis://127.0.0.1:6379/8"
Output:
The key as one base64url string on stdout. When no license is installed the command reports Failed to load license information on stderr and exits with status 1.
eyJsaWNlbnNlIjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5
Import License
Import license key:
emailengine license import [options]
Options:
| Option | Short | Description |
|---|---|---|
--license | -l | The license key, either the BEGIN LICENSE block or the string from license export |
--dbs.redis | Redis connection |
Example:
emailengine license import \
-l "eyJsaWNlbnNlIjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5" \
--dbs.redis="redis://127.0.0.1:6379/8"
Output:
License key was imported
A key that fails verification is reported as Failed to import license information and the command exits with status 1. Both success and failure messages go to stderr.
Use cases:
- Automated license deployment
- License updates
- Migration to new instance
See Prepared License for automated setup.
Password Management
Manage the admin password for the web interface.
Set Password
Set or reset the admin password:
emailengine password [options]
Options:
| Option | Short | Description |
|---|---|---|
--password | -p | Password to set (auto-generated if omitted) |
--hash | -r | Print the password hash instead of the password |
--dbs.redis | Redis connection |
Examples:
# Set specific password
emailengine password \
-p "MySecurePassword123" \
--dbs.redis="redis://127.0.0.1:6379/8"
# Auto-generate password
emailengine password \
--dbs.redis="redis://127.0.0.1:6379/8"
# Get password hash for prepared settings
emailengine password \
-p "MySecurePassword123" \
-r \
--dbs.redis="redis://127.0.0.1:6379/8"
Auto-generated output:
5b0c9b3e5f0d4a7c8e1f2a3b4c5d6e7f
Hash output (with -r):
JHBia2RmMi1zaGEyNTYkaT02MDAwMDAkMEwwRUVtSkZPNC8vSmtDWlZDTTRTUSRiNCt3QURwWVhOL0ZDUndtMW1QcDdqRkhqR2tjdndxaDBKWFFpS1ZxQTRr
Notes:
- Minimum 8 characters
- Auto-generated passwords are 32 hex characters
- The hash is a PBKDF2-SHA256 string, base64url-encoded, and is what
EENGINE_PREPARED_PASSWORDaccepts - Resetting the password also disables TOTP two-factor authentication and removes every registered passkey
See Reset Password for details.
Account Management
Export Account
Export account data including credentials:
emailengine export [options]
Options:
| Option | Short | Description |
|---|---|---|
--account | -a | Account identifier |
--dbs.redis | Redis connection | |
--service.secret | Encryption secret (if encryption enabled) |
Example:
emailengine export \
-a "user123" \
--dbs.redis="redis://127.0.0.1:6379/8" \
--service.secret="my-encryption-secret"
Output: the account record as JSON, on stdout.
Use cases:
- Backup specific accounts
- Migrate accounts between instances
- Disaster recovery
- Account auditing
Passing --service.secret is what lets the command read the stored values, and what it writes is the decrypted result: the IMAP password or the OAuth2 refresh token in cleartext. Redirect it to a file only where that file is protected the way a credential store would be, and delete it when the migration is done.
Encryption Management
Manage field-level encryption for stored secrets. One run rewrites every encrypted value the instance holds: the encrypted settings values, account credentials, SMTP gateway passwords, OAuth2 application secrets, the target URL and custom headers of webhook routes, the Let's Encrypt account and domain keys, and the private keys of an uploaded or self-signed TLS certificate.
Encrypt Command
Migrate encryption settings. This command can be run from any machine with network access to the Redis database - it does not need to run on the EmailEngine server itself.
emailengine encrypt [options]
Options:
| Option | Description |
|---|---|
--service.secret | New encryption secret. Leave out to remove encryption |
--decrypt | Old secret for decrypting. Repeat the flag if values were encrypted with different secrets |
--dbs.redis | Redis connection (required) |
Running it with neither option prints the usage text and changes nothing.
Use cases:
- Enable encryption (no encryption to encrypted)
- Disable encryption (encrypted to plain text)
- Re-encrypt (change encryption key)
- Migrate from multiple old keys
- Rewrite values under the current key derivation (same key, values written by an earlier release)
Examples:
Enable encryption:
emailengine encrypt \
--service.secret="new-encryption-key" \
--dbs.redis="redis://127.0.0.1:6379/8"
Change encryption key:
emailengine encrypt \
--service.secret="new-key" \
--decrypt="old-key" \
--dbs.redis="redis://127.0.0.1:6379/8"
Migrate from multiple old keys:
emailengine encrypt \
--service.secret="new-key" \
--decrypt="old-key-1" \
--decrypt="old-key-2" \
--decrypt="old-key-3" \
--dbs.redis="redis://127.0.0.1:6379/8"
Disable encryption:
emailengine encrypt \
--decrypt="current-key" \
--dbs.redis="redis://127.0.0.1:6379/8"
Rewrite values under the current key derivation:
emailengine encrypt \
--service.secret="current-key" \
--dbs.redis="redis://127.0.0.1:6379/8"
A value whose key was derived with scrypt by an earlier release is rewritten with PBKDF2 even though the key is unchanged; a value already under the current derivation and key is left as it is. This is required before moving an instance to a host in FIPS mode.
The command reports each updated record as it goes (<account>: updated, Gateway <id>: updated, and so on) and finishes each pass with a count, such as Updated 2/3 accounts, Updated 0/1 SMTP gateways, Updated 1/1 OAuth2 apps and Updated 0/0 webhook routes. A value it cannot decrypt with any of the given secrets is reported as Could not process ... Check decryption secrets. on stderr and left as it is.
Important:
- Back up your data before encryption changes
- All EmailEngine instances must use the same secret
- Changing keys requires access to the old key or keys
See Field Encryption for details.
Redis Keyspace Scan
Scan Command
Scan Redis and count keys by pattern:
emailengine scan --dbs.redis="redis://127.0.0.1:6379/8"
Output: CSV on stdout with a KEY,COUNT header. Account IDs, hashes, numbers, email addresses, and dates in key names are replaced with placeholders so that keys of the same kind are counted together; progress and the final Checked N keys line go to stderr.
Example output:
KEY,COUNT
"iad:hash(16)",150
"ia:accounts",1
"settings",1
"bull:submit:*",42
Use cases:
- Audit keyspace structure
- Capacity planning
- Debugging
Bounce Email Analysis
Check Bounce Command
Analyze an EML file to detect bounce information:
emailengine check-bounce [options]
Options:
| Option | Short | Description |
|---|---|---|
--file | -f | Path to EML file to analyze |
Examples:
# Analyze a bounce email
emailengine check-bounce /path/to/bounce.eml
# Using the --file option
emailengine check-bounce --file /path/to/bounce.eml
emailengine check-bounce -f /path/to/bounce.eml
Output: a JSON object with the fields the bounce detector could extract:
recipient- The email address that bouncedaction- The delivery action from the report, for examplefailedordelayedresponse.message- The error message from the remote serverresponse.status- Enhanced status code, for example5.1.1response.source- Where the diagnostic code came fromresponse.category- Classifier label, for exampleuser_unknownormailbox_fullresponse.recommendedAction- One ofremove,retry,retry_different_ip,fix_configuration,review,remove_contentresponse.blocklistandresponse.retryAfter- Set when the classifier recognized a blocklist listing or a retry hintmta- The mail server that reported the failurequeueId- Queue ID from the sending MTA, when presentmessageId- Message-ID of the original message
Fields that could not be determined are left out. A file that is not a bounce produces {}.
Example output:
{
"recipient": "user@example.com",
"action": "failed",
"response": {
"message": "550 5.1.1 User unknown",
"status": "5.1.1",
"source": "smtp",
"category": "user_unknown",
"recommendedAction": "remove"
},
"mta": "mx.example.com",
"messageId": "<original@example.com>"
}
Use cases:
- Debug delivery issues
- Classify bounce types
- Test bounce detection against a saved message
This command uses the same bounce detection and classification as EmailEngine's automatic bounce handling, so its output matches what a messageBounce webhook would carry for the same message.
Remote Administration Examples
Scenario 1: Automated Deployment
Deploy EmailEngine with a pre-configured token:
#!/bin/bash
# Generate token on admin workstation
TOKEN=$(emailengine tokens issue \
-d "Production API token" \
-s "api" \
--dbs.redis="redis://prod-redis.example.com:6379/0")
# Export for prepared settings
PREPARED=$(emailengine tokens export \
-t "$TOKEN" \
--dbs.redis="redis://prod-redis.example.com:6379/0")
# Deploy to production server
ssh prod-server "export EENGINE_PREPARED_TOKEN='$PREPARED' && emailengine"
Scenario 2: CI/CD Pipeline
# .github/workflows/deploy.yml
steps:
- name: Create deployment token
id: create-token
run: |
TOKEN=$(emailengine tokens issue \
-d "CI deployment token" \
-s "api" \
--dbs.redis="${REDIS_URL}")
echo "token=$TOKEN" >> "$GITHUB_OUTPUT"
- name: Check the account list
env:
EMAILENGINE_TOKEN: ${{ steps.create-token.outputs.token }}
run: |
curl -fsS -H "Authorization: Bearer $EMAILENGINE_TOKEN" \
https://emailengine.example.com/v1/accounts
Scenario 3: Backup Automation
The CLI has no command that lists tokens or accounts, so the script needs the token values and account IDs as input. Account IDs can come from GET /v1/accounts.
#!/bin/bash
# backup-emailengine.sh
REDIS_URL="redis://backup-source.example.com:6379/0"
BACKUP_DIR="/backups/emailengine/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# Export the license
emailengine license export \
--dbs.redis="$REDIS_URL" \
> "$BACKUP_DIR/license.txt"
# Export tokens, one per line in tokens.txt
while read -r TOKEN; do
emailengine tokens export \
-t "$TOKEN" \
--dbs.redis="$REDIS_URL" \
>> "$BACKUP_DIR/tokens.txt"
echo >> "$BACKUP_DIR/tokens.txt"
done < tokens.txt
# Export accounts, one ID per line in accounts.txt
while read -r ACCOUNT; do
emailengine export \
-a "$ACCOUNT" \
--dbs.redis="$REDIS_URL" \
--service.secret="$ENCRYPTION_SECRET" \
> "$BACKUP_DIR/account-$ACCOUNT.json"
done < accounts.txt
Scenario 4: Multi-Instance Management
Issue a token on several EmailEngine instances:
#!/bin/bash
INSTANCES=(
"redis://instance1.example.com:6379/0"
"redis://instance2.example.com:6379/0"
"redis://instance3.example.com:6379/0"
)
# Each instance gets its own token value
for REDIS_URL in "${INSTANCES[@]}"; do
echo "Creating token on $REDIS_URL"
emailengine tokens issue \
-d "Monitoring token" \
-s "metrics" \
--dbs.redis="$REDIS_URL"
echo
done
Common Patterns
Pattern 1: Environment-Based Configuration
# dev.env
REDIS_URL=redis://localhost:6379/8
ENCRYPTION_SECRET=dev-secret
# prod.env
REDIS_URL=redis://prod-redis:6379/0
ENCRYPTION_SECRET=prod-secret-key
# Usage
source dev.env
emailengine tokens issue -d "Dev token" --dbs.redis="$REDIS_URL"
source prod.env
emailengine tokens issue -d "Prod token" --dbs.redis="$REDIS_URL"
Pattern 2: Token Rotation Script
The CLI can issue tokens but not delete them, so revoke the old one with DELETE /v1/tokens/{token} once the new one is in place.
#!/bin/bash
# rotate-tokens.sh
OLD_TOKEN="$1"
REDIS_URL="$2"
# Create the replacement
NEW_TOKEN=$(emailengine tokens issue \
-d "Rotated token $(date +%Y%m%d)" \
-s "api" \
--dbs.redis="$REDIS_URL")
echo "New token: $NEW_TOKEN"
# Revoke the old one through the API, using the new token
curl -fsS -X DELETE \
-H "Authorization: Bearer $NEW_TOKEN" \
"https://emailengine.example.com/v1/tokens/$OLD_TOKEN"
Pattern 3: Health Check
/health needs no token, and it checks the things a token would not: that every IMAP worker is up and that Redis answers a write and a read.
#!/bin/bash
# check-emailengine.sh
if curl -fsS https://emailengine.example.com/health > /dev/null; then
echo "EmailEngine is healthy"
exit 0
else
echo "EmailEngine is unhealthy"
exit 1
fi
Minting a token per check would work too, and would leave one behind on every run.
See Also
- Environment Variables - The same settings as environment variables, plus those with no CLI equivalent
- Configuration Overview - How config files, environment variables, and CLI arguments combine
- Prepared Settings - Provisioning license, token, and password without manual setup
- Reset Password - The
passwordcommand in detail - Access Tokens - What
tokens issueproduces and how scopes work