Administering Keen
IMAP mail
Chapter 18 of 30
IMAP mail
IMAP collects new messages from a mailbox as evidence: one named connection per account and folder, headers only unless you choose to keep part of the body. Existing mail is never imported, and nothing in the mailbox is marked, moved or deleted. IMAP is unavailable in demo environments.
- Set
KEEN_IMAP_ENABLED=truefor API, worker and beat, keepKEEN_INTEGRATION_SECRET_KEYconsistent on the workers, and start the dedicated worker withdocker compose --profile imap up -d(for local builds,docker compose -f docker-compose.yml -f docker-compose.build.yml --profile imap up -d --build). - Open Admin → Sources & evidence mapping → Define a source, choose IMAP mail, name the connection, and enter its hostname, port (normally 993), username, password or app password, and folder (normally INBOX). The account needs permission to read that folder.
- Set the Collection interval: the default and minimum are 5 minutes, in five-minute increments up to 1,440 minutes (24 hours).
- Leave Fetch message body off for headers only, or enable it and choose a character limit (default 4,000 characters; range 1-65,536). Plain text is preferred, attachments are excluded, and HTML is kept as raw text inside JSON and never rendered.
- Choose Collect now to establish the current mailbox position. From then on each connection polls when its interval has elapsed.
- Inspect Events for source
imapand your connection, then write connection-specific mapping rules using structured fields such asmail.headers.subjectormail.body.
What an event looks like. The summary is the subject, the actor comes from From (up to 128 display characters), the action is mail.received, the event timestamp is the collection time, and the message's own Date header stays in mail.headers.date.
Body collection can retain personal or confidential prose. Choose the folder, character limit and retention policy accordingly. Keen applies configured sensitive-key redaction and privacy masking before storage.
Going deeper: polling, manual runs and timing
The scheduler checks every five minutes and each connection polls when its configured interval has elapsed. Another Collect now queues a poll for that connection; manual actions and scheduled runs both respect the interval from the last attempt, including failed attempts, and a request made too early is skipped. Changing the interval retains the mailbox checkpoint. Actual collection can occur on a later scheduler tick or after a queue delay, and busy queues can delay polling beyond five minutes; connection order rotates to share worker capacity.
Admin → Ingest runners → Run IMAP polls all enabled IMAP connections. It queues background work, so the confirmation means the work was queued; inspect each connection's collection health for results. The button is hidden when IMAP is disabled, and paused ingestion must be resumed first. Providers requiring OAuth-only authentication need another supported collection route.
Going deeper: TLS, networking, credentials and file-managed connections
Only verified implicit TLS is supported; fix an invalid or expired certificate at the server, because verification cannot be disabled. Private destinations require explicit entries in KEEN_INGESTION_ALLOWED_CIDRS, and loopback and link-local addresses remain prohibited. Passwords are encrypted; blank password fields preserve an existing credential, and changing the host, port or username requires re-entering it.
File-managed connections use type imap, configuration fields host, port, username, folder, fetch_body, body_max_chars and poll_interval_minutes, an empty inputs object, and a password secret reference. Store configuration values as strings, including "true" or "false".
Going deeper: what one poll fetches and how bodies are bounded
Each poll handles at most ten messages within a 100-UID window, up to 4 MiB of responses, and a 45-second collection alarm that also stops slow-drip responses; the parent terminates a stalled collector subprocess after 55 seconds. Headers and MIME metadata have separate bounds. The collector may return fewer messages to keep its serialised JSON output within 5 MiB, and remaining messages are picked up by a later poll; Unicode escaping can use more output bytes than the original text. Unsolicited literals and additional literals within one fetch are rejected before their payload is read, and contradictory mailbox UID metadata stops the poll.
Only a bounded partial body is fetched; mail.body_truncated records truncation and mail.body_omitted_reason explains omissions. Related MIME resources are excluded, and a related body whose root cannot be identified is omitted. Supported body charsets are UTF-8, ASCII, Latin-1 and Windows-1252; unsupported charsets or invalid transfer encodings omit the body with reason invalid_or_unsupported_body_encoding while headers are retained. Headers-only polling avoids MIME body structure entirely. The JSON artifact contains selected headers and the optional body; the actor and system display labels are limited to 128 characters after redaction and masking, and fuller bounded header values remain in the payload and artifact.
Going deeper: failures, backoff and a changed mailbox
Failed polls keep their checkpoint and use exponential backoff from two minutes to one hour; the next attempt waits for both that backoff and the configured interval. Inspect the worker result and logs, verify credentials and TLS, and investigate oversized headers or malformed MIME structure in the mailbox. Disabling body collection avoids BODYSTRUCTURE failures while continuing to collect headers; protocol identity or size failures still stop the poll. The dedicated worker must be running to consume the imap queue; the ordinary worker does not.
If the server changes UIDVALIDITY, collection pauses: review the mailbox, disable the old connection and create a replacement to establish a new baseline. Replacing or changing the account or folder can leave earlier uncollected mail outside that baseline, and there is no automatic historical backfill.