Credential Security FAQ
Common questions about how EmailEngine stores, secures, and encrypts email account credentials, and about the other secrets an instance holds.
Where are email credentials stored?
EmailEngine stores every credential it holds in Redis:
- IMAP and SMTP passwords
- OAuth2 access tokens and refresh tokens
- OAuth2 application client secrets, service account keys, and external account configurations
- SMTP gateway passwords
- The SMTP server and IMAP proxy passwords, the OpenAI API key, the TOTP seed, and the admin session cookie key
Is email content stored?
Not as a copy of the mailbox. EmailEngine reads messages from the mail server on demand and keeps only sync state (message IDs, flags, folder listings) in Redis.
Content does pass through Redis in two cases:
- A submitted message is stored in Redis, in full, from submission until it is delivered, so that the queue can retry it. It is removed once delivery succeeds or the attempts run out
- Webhook payloads waiting in the notify queue carry whatever the payload includes; with
notifyTextornotifyAttachmentsenabled, that is message content
Neither is encrypted by EENGINE_SECRET, which covers credentials only. The Document Store, which indexed message content in Elasticsearch, was removed in EmailEngine v2.82.0.
Are credentials encrypted?
It depends on your configuration:
| Configuration | Storage Method | Security Level |
|---|---|---|
Without EENGINE_SECRET | Cleartext | Development only |
With EENGINE_SECRET | AES-256-GCM encrypted | Production ready |
For production deployments, always configure EENGINE_SECRET.
How do I enable encryption?
Set EENGINE_SECRET before the first start and keep the same value on every start afterwards; a different or missing secret leaves the stored credentials undecryptable. An instance that already holds cleartext credentials encrypts them with emailengine encrypt. Secret Encryption has the generation, storage and migration steps.
What encryption algorithm is used?
AES-256-GCM, with a key derived from EENGINE_SECRET by PBKDF2-HMAC-SHA256 and a per-value IV and authentication tag, so a tampered value is detected on decryption rather than silently accepted. Values written by earlier releases derived the key with scrypt and are still read; Secret Encryption describes how to move them.
Does EmailEngine run on a FIPS-enabled host?
Yes, when it runs on a Node.js that uses the host's OpenSSL with its FIPS provider, which is the case for npm and source installations on RHEL and its derivatives. EmailEngine uses only algorithms a FIPS provider allows (PBKDF2, AES-256-GCM, SHA-256, ES256 and RS256 passkeys) and has no FIPS mode of its own. The standalone binary and the Docker image bundle their own OpenSSL without a FIPS provider. An existing instance needs its stored values rewritten before the switch. See FIPS Mode.
What happens if Redis is compromised?
| Scenario | Impact |
|---|---|
| Without encryption | Attacker gains all passwords and OAuth tokens in cleartext |
| With encryption | Attacker sees encrypted data; credentials remain secure unless EENGINE_SECRET is also compromised |
Three things follow from that:
- Enable encryption in production
- Store
EENGINE_SECRETseparately from Redis, so one backup cannot yield both - Use Redis authentication and network isolation
What happens if I lose EENGINE_SECRET?
Every encrypted value is unrecoverable. Password accounts have to be given their credentials again and OAuth2 accounts have to be re-authorized, one by one; there is no bulk recovery, because EmailEngine holds no second copy of the key.
Guard against it by backing the secret up somewhere other than the Redis backups, and by keeping it in a secrets manager rather than only in a deployment file.