NAiOSOmni Email
omnichat-emailv0.6.0Add an email channel (IMAP/SMTP) to NAiOSOmni. Your inbox appears as another channel within the unified Inbox, with AI auto-reply, vertical agents, and all the capabilities of NAiOSOmni.
Description
Plugin attached to NAiOSOmni: registers a new driver 'email-imap' in the ChannelRegistry of NAiOSOmni so that any IMAP/SMTP account (Gmail with app-password, IONOS, personal, corporate Outlook) can connect as a channel. Incoming emails appear in the unified Inbox, grouped by sender (peer = email address). Email specifics (subject, message-id, threading, cc/bcc, html body, attachments) are serialized in media_meta JSON without modifying the schema of NAiOSOmni. Responses are sent via SMTP with correct threading (In-Reply-To + Subject: Re:). HTML body is served by 'view original' from the publicRouter of the plugin itself (auth-checked).
Features (3)
Your IMAP inbox appears alongside WhatsApp and Telegram in the unified Inbox.
Compatible with Gmail (app-password), IONOS, personal, corporate Outlook. Google/Microsoft OAuth in phase 2.
Responses maintain In-Reply-To + Subject: Re: so that the recipient's client threads them correctly.
Changelog
- PHASE 10 · HUMAN-IN-THE-LOOP + tool integration RAG
- DRAFT MODE — toggle per-channel in the General tab (only email-imap). When ON, AI auto-replies are NOT sent: they are saved with status='draft' for review. Special bubble with dashed amber border + 3 actions: Send (real SMTP now) / Edit (loads text into composer + discards) / Discard (cleans DB + files). PATCH /channels/:id/draft-mode to activate/deactivate
- Draft endpoints: GET /api/drafts/:msgId (fetch for composer), POST /api/drafts/:msgId/send (promotes to real send), DELETE /api/drafts/:msgId (cleans with attachment deletion on disk)
- Inbox renderer: detects status='draft', shows header 🤖 AI Draft pending + differently styled bubble + action row with 3 buttons. No changes in chat drivers (WA/TG do not emit status='draft')
- TOOL search_inbox for agents — registered in TOOLS of OmniChat via mutation of the exported object (no changes in core). OpenAI tool schema with params {query, top_k}. ctx.invokePlugin delegates to the plugin's searchInbox() which calls the EmbeddingsStore. Agents can now semantically query the inbox when a client requests it
- Public method searchInbox(args) in the plugin: generates embedding of the query, executes cosine search, returns top-K formatted for LLM (no buffers, scores with 2 decimals, truncated snippet)
- PHASE 9 · EMAIL-AI FEATURES — 4 AI features specific to email
- F-1 · AUTOMATIC TRIAGE — each incoming email classified by LLM into {urgent, action, fyi, newsletter, spam} with reason in ≤12 words. Colored badge in the inbox bubble (red/orange/gray/blue/black). Persisted in media_meta.triage
- F-4 · AI ANTI-PHISHING — score 0-1 calculated in the same LLM call as the triage (token-efficient). Severity-coded banner over the message when score ≥ 0.5 (medium/high/critical with pulse animation). Risk factors in Spanish. Persisted in media_meta.phishing
- F-5 · RAG ON THE INBOX — own SQLite with Float32 packed vectors (1536-dim, ~6KB/email). Auto-indexes each incoming non-spam email after analysis. Endpoint POST /api/search with embedding of the query + cosine in JS. Top-K results with peer/subject/snippet/score. Integrated cleanup: deletes embeddings of deleted channels
- F-6 · THREE AUTO-COMPOSE DRAFTS — when opening an email thread, a row of 3 chips above the composer with drafts in formal/casual/brief tones. Click → loads the text into the textarea. 5min cache by (channel+peer+last_inbound_id) to avoid re-spending tokens while navigating tabs. Refresh button to manually regenerate
- ENDPOINTS — POST /plugins/omnichat-email/api/search, POST /plugins/omnichat-email/api/drafts. Both auth-checked, scoped to the user
- UI/CSS — triage badges (5 colors), phishing banner (3 severities with pulse), draft chips with hover lift effect. All driver-conditional (only email-imap, WA/TG intact)
- LLM combination — triage + phishing in a single call with unified prompt → ~50% token savings vs separate calls. Model: gpt-4o-mini for classification/drafts, text-embedding-3-small for vectors
- PHASE 8 · POLISH & ROBUSTNESS — the 7 complete items
- B-7 · Sanitize HTML email body — allowedTags expanded (style, font, center, table-layout, etc.) to preserve the real format of emails. Inline CSS is not filtered (parseStyleAttributes=false). meta charset utf-8 guaranteed via HTTP header + inline meta
- B-2 · IMAP \Seen flag — driver.markAsRead(peerId) now performs IMAP search by-From + STORE +FLAGS \Seen for all unseen UIDs of the peer. Endpoint /api/channels/:id/messages triggers markAsRead fire-and-forget when serving the thread (driver-agnostic, WA/TG are no-op)
- B-6 · Enhanced healthcheck — NOOP latency tracking (rolling window 10 samples), degradation detection (3 NOOPs >5s consecutive → preventive reconnect), inactivity hint (>6h without inbound during working hours → log info)
- B-1 · Quota UI in Anti-spam tab — new card ONLY for email-imap channels with 3 inputs (per_minute/hour/day), pre-filled from driver_config.quotas, PATCH /plugins/omnichat-email/channels/:cid/quotas with reasonable bounds
- B-5 · Cool-down outbound dedup — refuse re-sending the same (peerId + body) within 60s. SHA-1 hash in in-memory map pruned to the window. err.code DEDUP with time since the previous send
- B-3 · Cleanup jobs orphans — daily cron (initial delay 60s) that scans data/bodies/<uid>/<cid>/ and uploads/users/<uid>/email-<cid>/ and deletes dirs whose email-imap channel no longer exists in DB. Scope channel-level (per-message orphans deferred)
- B-4 · Dedicated metrics — endpoint /plugins/omnichat-email/api/metrics (admin/superadmin only) with total/connected channels, volume 24h/7d in/out, filter savings, smtp errors, quota hits, avg attachment size, top senders 7d, NOOP latency p50/p95 + slow streak + last inbound per live channel
- PHASE 7 · HARDENING — hardening the driver for real production
- OUTBOUND QUOTAS — defaults 30/min · 200/hour · 1000/day per channel, in-memory counters with timestamps pruned to 24h. Exceeds → throw with err.code QUOTA_MINUTE/HOUR/DAY. Override per-channel via driver_config.quotas. _recordSend() only counts after successful SMTP (failures do not penalize)
- HEALTHCHECK IMAP NOOP every 5min — detects dead silent IDLE (NAT timeout, LB reset, server-side drop). NOOP fails → close → reconnect via existing backoff. Started after connect, stopped on disconnect
- STRUCTURED LOG BRIDGE — driver emits 'omnichat-email.log' on the event bus, the plugin forwards it to OmniChat.logService.log(). Categories: email-rx, email-tx, email-filter, email-quota, email-health. Detailed events (subject, peer, uid, attachments, smtp_code) visible in real-time in the channel's Log tab
- SANITIZATION from_name — helper sanitizeFromName() strips CR/LF/angle-brackets + caps 80 chars. Applied in initial pairing and edit-connection page. Blocks SMTP header injection
- CAP ATTACHMENT SIZE — total raw bytes ≤ 24MB (typical max SMTP envelope 25MB with base64 overhead +33%). fs.statSync sum before sending, fails cleanly with err.code=ATTACHMENT_TOO_LARGE
- STRUCTURED LOG in all fail-paths — SMTP rejects (with smtp_code if provided), quota exceeded (code), attachments too large (bytes), auto-mail filter (reason), successful reception/sending (full metadata)
- Rename — 'OmniChat Email' → 'NAiOSOmni Email' in manifest (id remains omnichat-email for compatibility)
- PAIRING (Phase 2) — real IMAP+SMTP validation with imapflow + nodemailer.verify(), AES-256-GCM encryption of credentials with secret-vault, sanitization (passwords stripped from driver_config)
- RECEPTION (Phase 3) — persistent IMAP IDLE, initial backfill of 30 emails, tracking UIDVALIDITY + UIDNEXT, mailparser + sanitize-html, attachments to disk, HTML body sanitization. Reconnect with backoff 5/10/30/60/120/300s
- SENDING (Phase 4) — SMTP with pool, correct threading (In-Reply-To + References), 3 subject modes (Subject: explicit / Re: automatic / synthetic 60 chars), header Auto-Submitted: auto-replied (active anti-loop)
- VIEW ORIGINAL (Phase 5) — Route /plugins/omnichat-email/body/:cid/:mid serves sanitized HTML with strict CSP + iframe-friendly headers, ownership check. Attachments reuse /uploads/users/ existing from NAiOSOmni (no new auth code)
- OUTSTANDING ATTACHMENTS (Phase 6) — 1 email = N attachments in a single SMTP envelope (instead of N emails as WA/TG do). Driver accepts content.attachments[] from the composer and maps them to nodemailer
- EMAIL TACTICAL MODE — Automatic inbound email filter (Auto-Submitted, Precedence bulk/list/junk, List-* headers, X-Autoresponse, machine senders); suppression of progress notifies from tools (isProgress flag, no more '📚 Consulting KB…' by email); suffix to system_prompt when driver=email-imap for email-aware tone (a response, formal, without decorative emojis)
- EDIT CONNECTION — Page /plugins/omnichat-email/channels/:cid/edit with pre-filled form (passwords blank for security), validation before saving, unload+load+connect live. 'Re-link' from the ⋮ menu redirects automatically for email-imap channels
- INBOX UI — Renderer now draws media_meta.attachments[] as cards (thumbnails for images, inline players for video/audio, icon+name+size for PDF/Word/Excel/ZIP). Driver-agnostic, any future driver with the same shape will benefit
- Modal 'Add contact' driver-aware — copy + validation change according to driver (email vs phone vs telegram chat_id)
- Tab 'Simulation' hidden for email-imap (incompatible by design: synchronous chat-only state machine)
- BUGS — BigInt coercion for uidValidity/uidNext/uid (imapflow >=1.3 returns BigInt → broke JSON.stringify); _restoreOwnChannels to avoid 'driver not registered' in boot race; polling of pluginLoader (not just setImmediate, there are awaits between loadAll and app.set); CSS padding of the modal 'Add channel' (pre-existing bug)
- TLS — Optional tls_insecure flag per-channel for servers with cert intercept (Norton AV / corporate proxies / expired certs). Strict TLS by default
- Dependencies — imapflow ^1.3.3, mailparser ^3.9.8, sanitize-html ^2.17.3 (nodemailer was already there)
- Initial scaffold — registration of driver 'email-imap' in OmniChat ChannelRegistry
- Form-based pairing with IMAP/SMTP fields (placeholder — Phase 2 implements real validation)
- Driver stub: connect/startPairing/sendMessage launch 'not yet implemented' with the pending phase