Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
7.7 KiB
7.7 KiB
IMAP Inbound Email Service Plan
Status: Draft Owner: Email Platform Last updated: 2025-12-26
Goals
- Add an IMAP inbound email provider that feeds the same
INBOUND_EMAIL_RECEIVEDevent flow as Gmail and Microsoft. - Provide a resilient, long-running IMAP service that uses IDLE, reconnects automatically, and handles multiple folders per mailbox.
- Expose IMAP as a first-class inbound email provider in the settings UI alongside Google and Microsoft.
Current State (Research Summary)
- Gmail inbound flow:
server/src/app/api/email/webhooks/google/route.tsdecodes Pub/Sub, loads provider config, fetches full message details viaGmailAdapter, and publishesINBOUND_EMAIL_RECEIVEDviashared/events/publisher.ts. - Microsoft inbound flow:
server/src/app/api/email/webhooks/microsoft/route.tsvalidates Graph notifications, fetches message details viaMicrosoftGraphAdapter, then publishesINBOUND_EMAIL_RECEIVED(with fallback minimal payload on fetch failure). - Test flow:
server/src/services/email/MailHogPollingService.tsemitsINBOUND_EMAIL_RECEIVEDdirectly via the server EventBus. - Workflow trigger:
services/workflow-worker/src/WorkflowWorker.tsconsumes workflow events (Redis stream) and startsshared/workflow/workflows/system-email-processing-workflow.ts, which waits for theINBOUND_EMAIL_RECEIVEDpayload defined inshared/workflow/streams/eventBusSchema.ts.
Proposed Architecture
High-level flow
- IMAP service connects to configured mailboxes and folders.
- IDLE receives new mail notifications (or polling fallback if IDLE unsupported).
- IMAP service fetches the full RFC822/body + headers for new messages.
- Parse MIME into
EmailMessageDetailsand publishINBOUND_EMAIL_RECEIVEDusingshared/events/publisher.ts. - Workflow worker consumes and runs the existing system email processing workflow (no change).
Service placement
- New service in
services/email-service(Node + TS, similar toservices/workflow-worker). - Uses shared DB access and shared event publisher to avoid duplicating queue/event logic.
- Deploy as a long-running worker alongside existing services (server, workflow-worker, temporal-worker).
Data Model & Configuration
Provider types
- Extend all inbound email unions to include
imap:shared/interfaces/inbound-email.interfaces.tsserver/src/interfaces/email.interfaces.tsserver/src/components/EmailProviderConfiguration.tsx(providerTypeunion)- Any API/action payloads that validate provider type
New vendor config table
Create imap_email_provider_config with fields (initial draft):
email_provider_id,tenant- Connection:
host,port,secure(TLS),allow_starttls,auth_type(password | oauth2) - Auth:
username,password(store encrypted or via tenant secret provider),oauth_access_token,oauth_refresh_token,oauth_expires_at - Processing:
auto_process_emails,max_emails_per_sync,folder_filters(jsonb array) - State:
last_uid,uid_validity,last_seen_at,last_error,last_sync_at
Provider CRUD + validation
- Update
server/src/services/email/EmailProviderService.tsandserver/src/lib/actions/email-actions/emailProviderActions.tsto support IMAP configs. - Add validation in
server/src/services/email/EmailProviderValidator.tsfor IMAP host/port/auth requirements. - Add secret storage integration via
getSecretProviderInstance()for IMAP passwords (and optional OAuth tokens) instead of plain DB storage.
IMAP Service Design
Connection lifecycle
- Maintain one IMAP connection per provider + folder (or multiplex folders on a single connection if library allows).
- On startup, load active IMAP providers and connect to all configured folders.
- Use IDLE to listen for
EXISTS/RECENTevents; on disconnect or IDLE timeout, re-enter IDLE. - Implement exponential backoff with jitter on reconnect.
Message tracking + dedupe
- Track
uidvalidityandlast_uidper provider/folder; on mismatch, resync (search unseen from scratch). - Persist state to
imap_email_provider_configto survive restarts. - Use
Message-IDheader plus providerId as a secondary dedupe key (insert intoemail_processed_messagesor a newimap_processed_messagestable) to avoid double-publishing.
MIME parsing
- Fetch full RFC822 or
BODY.PEEK[]and parse with a MIME parser (e.g.,mailparser). - Map into the existing
EmailMessageDetailsstructure:subject,from,to,cc,receivedAtbody.textandbody.htmlattachmentsmetadata (id, name, contentType, size)threadId,references,inReplyTo, andheaders
Event publishing
- Publish
INBOUND_EMAIL_RECEIVEDusingshared/events/publisher.tswith payload:tenantId,tenant,providerId, and the fullemailDataobject
- Reuse existing workflow pipeline and ticket creation logic without changes.
UI/UX Updates (Inbound Email Settings)
- Add an IMAP card to
server/src/components/EmailProviderSelector.tsxandee/server/src/components/EmailProviderSelector.tsx. - Add an IMAP provider form in both OSS and EE components:
- Fields: mailbox, host, port, TLS/starttls, username, password/app-password, folder filters, auto-process, max emails per sync, inbound ticket defaults.
- Update provider list cards to show IMAP status and connection errors.
API + Service Integration
- New IMAP service reads configs via DB (not via server API) to avoid API coupling.
- Optional admin endpoints (future): manual reconnect, force resync, or pause provider.
- Add Docker Compose entry for
email-service(dev + prod) with required env vars.
Observability
- Log structured events per provider: connect, disconnect, idle start, new message count, publish success/failure.
- Update
email_providers.status,error_message,last_sync_atfrom the IMAP service on state changes. - Add a lightweight health check endpoint or readiness log for monitoring.
Testing Strategy
- Unit tests for IMAP MIME parsing into
EmailMessageDetails. - Integration tests with a local IMAP server (e.g., dockerized test server) validating:
- IDLE + reconnect
- Folder filters
- Deduplication by UID + Message-ID
- Published
INBOUND_EMAIL_RECEIVEDpayload
- E2E: simulate incoming email and verify ticket creation via workflow.
Implementation Plan (Tasks)
- Add
imapprovider type across shared/server interfaces and validation. - Create
imap_email_provider_configmigration + indices + Citus distribution. - Extend provider CRUD/actions to read/write IMAP config and secrets.
- Build IMAP adapter/parser (message fetch + MIME parsing) and map to
EmailMessageDetails. - Build
services/email-servicewith connection manager, IDLE loop, reconnect strategy, and publisher. - Add UI forms and selector card for IMAP in both OSS and EE bundles.
- Wire Docker Compose for the new service (dev + prod) and document env vars.
- Add tests (unit + integration) and update inbound email docs to include IMAP.
Risks & Mitigations
- IMAP server variance: IDLE support and folder semantics differ. Mitigate with polling fallback and robust folder selection logic.
- Duplicate events: IMAP can replay on reconnect. Mitigate with UID + Message-ID dedupe and persisted state.
- Credential handling: Storing passwords requires secure storage; use tenant secret provider and avoid logging secrets.
- Large attachments: IMAP fetch size can be heavy; fetch metadata first and defer content where possible.
Open Questions
- Do we want OAuth2 for IMAP (XOAUTH2) in v1 or password-only?
- Should IMAP providers share the same inbound defaults schema as Google/Microsoft (yes), or add IMAP-specific defaults?
- Preferred IMAP test server for CI (e.g., Dovecot, GreenMail, or MailHog alternative)?