mirror of
https://github.com/root-fr/jmap-webmail.git
synced 2026-09-24 16:01:18 +00:00
9.7 KiB
9.7 KiB
JMAP Webmail - Architecture Reference
Implementation details, file locations, and feature documentation. Last verified: 2026-03-16
Settings Integration Status
All settings are properly wired to their functionality:
| Setting | Store Location | UI Control | Integration |
|---|---|---|---|
| deleteAction | settings-store.ts:26 | email-settings.tsx | Moves to trash or permanently deletes |
| showPreview | settings-store.ts:27 | email-settings.tsx | Conditionally renders preview in email list |
| externalContentPolicy | settings-store.ts:29 | email-settings.tsx | Controls external content blocking (ask/block/allow) |
| debugMode | settings-store.ts:40 | advanced-settings.tsx | Conditional logging via lib/debug.ts |
| animationsEnabled | settings-store.ts:17 | appearance-settings.tsx | Works via CSS variable |
| markAsReadDelay | settings-store.ts:25 | email-settings.tsx | Fully integrated |
Email Features
Drag-and-Drop
- Native HTML5 DnD API — drag emails to mailbox folders in sidebar
- Files:
contexts/drag-drop-context.tsx,hooks/use-email-drag.ts,hooks/use-mailbox-drop.ts - Multi-select support, permission validation, visual feedback
Context Menus
- Right-click on email list items
- Files:
components/ui/context-menu.tsx,components/email/email-context-menu.tsx,hooks/use-context-menu.ts - Reply, Forward, Move to, Color tags, Delete — supports batch operations
Mobile Responsive
- Adaptive single/multi-pane layout with CSS-first breakpoints (no JS layout lag)
- Files:
stores/ui-store.ts,hooks/use-media-query.ts,components/layout/mobile-header.tsx - Mobile bottom action bar:
components/email/mobile-action-bar.tsx(reply, archive, delete, more) - Long-press context menu:
hooks/use-long-press.ts(300ms, vibration, scale feedback) - Touch-friendly submenu: tap-to-expand on
pointer: coarsedevices - Hamburger menu navigation, view switching, safe area support
Keyboard Shortcuts
- Hook:
hooks/use-keyboard-shortcuts.ts - Modal:
components/keyboard-shortcuts-modal.tsx - Navigation: j/k or arrows (next/prev email), Enter/o (open), Esc (close)
- Actions: r (reply), R/a (reply all), f (forward), s (star), e (archive), #/Del (delete), u (unread)
- Global: c (compose), / (search), ? (help), Shift+G (refresh), Ctrl+A (select all)
- Threads: x (expand/collapse thread)
- Disabled when typing in inputs or when composer is open
Email Threading
- Gmail-style inline expansion (desktop), full-screen conversation view (mobile)
- Files:
lib/thread-utils.ts— Thread grouping utilitieslib/jmap/types.ts— ThreadGroup interfacelib/jmap/client.ts— getThread(), getThreadEmails() methodsstores/email-store.ts— Thread expansion statecomponents/email/thread-list-item.tsx— Collapsed/expanded thread viewcomponents/email/thread-email-item.tsx— Compact email within threadcomponents/email/thread-conversation-view.tsx— Full-screen mobile conversation viewcomponents/email/email-list.tsx— Groups emails by threadId
Sandboxed Email Rendering
- Rich HTML emails (tables, stylesheets) rendered in sandboxed iframe for CSS isolation
- Simple HTML/plain text rendered inline via DOMPurify (faster, no iframe overhead)
- Decision function:
lib/email-sanitization.ts(needsIframeRendering()) - Iframe component:
components/email/sandboxed-email-frame.tsx(auto-height, link interception) - Applied in both
email-viewer.tsxandthread-conversation-view.tsx - DOMPurify remains the security boundary; iframe provides CSS containment only
Dark Mode Email Readability
- Intelligent color transformation during HTML sanitization
- Files:
lib/color-transform.ts,components/email/email-viewer.tsx - Iframe path: uses
prefers-color-schememedia query viagenerateIframeStylesheet() - Luminance < 0.4 (very dark): Inverted and brightened
- Luminance 0.4-0.6 (medium): Lightened by 40-50%
- Luminance > 0.6 (light): Preserved as-is
Newsletter Unsubscribe (RFC 2369)
- Files:
lib/validation.ts,lib/email-headers.ts,components/email/unsubscribe-banner.tsx - URL validation blocks XSS vectors, two-step confirmation, localStorage persistence
- Supports both HTTP (one-click) and mailto methods
Email Layout & Blocked Content Fix
- Removed
width: max-content/display: inline-blockfrom email content wrappers - Files:
app/globals.css,lib/email-sanitization.ts,components/email/email-viewer.tsx - Blocked images: walks up DOM to collapse empty containers
Identity Management & Sub-Addressing
- Full CRUD:
stores/identity-store.ts,lib/jmap/client.ts(Identity/get, Identity/set) - Components:
components/identity/identity-manager-modal.tsx,components/identity/identity-form.tsx - Sub-addressing:
lib/sub-addressing.ts(parse, generate, suggest) - Visual badges:
components/email/email-identity-badge.tsx
Calendar Integration
Core
- JMAP Calendars: Full CalendarEvent CRUD with RFC 8984 types
- Files:
lib/jmap/types.ts,lib/jmap/client.ts,stores/calendar-store.ts - Capability detection:
urn:ietf:params:jmap:calendarsin auth-store.ts - UI:
components/calendar/(month-view, week-view, day-view, agenda-view, toolbar, event-modal, event-detail-popover, event-card, mini-calendar, calendar-sidebar-panel) - Settings:
components/settings/calendar-settings.tsx - Keyboard: m (month), w (week), d (day), a (agenda), t (today), n (new event), arrows (navigate)
Drag-and-Drop Rescheduling
- Week/day views: 15-min snap with visual indicator
- Month view: date move with blue ring highlight
- HTML5 DnD API with
application/x-calendar-eventpayload
Click-Drag to Create
- Pointer events, 5px movement threshold
- Shared hook:
hooks/use-time-grid-interactions.ts
Event Resize
- Drag bottom edge, 15-min snap, optimistic JMAP update
role="separator"with aria-label
Recurring Event Edit Scope
- "This event only" / "This and following" / "All events" dialog
- Files:
components/calendar/recurrence-scope-dialog.tsx
Event Detail Popover (Read-Only View)
- Click event → read-only popover (instead of edit form)
- Component:
components/calendar/event-detail-popover.tsx - Displays: title, calendar, date/time, location (URL-aware with
target="_blank" rel="noreferrer"), virtual meeting link, participants with status badges, recurrence, reminder, description - Actions: Edit (opens modal), Delete (with confirmation), Duplicate
- Quick note: inline input appends timestamped note to description
- RSVP bar for attendees (Accept/Tentative/Decline)
- Smart positioning: right → left → below → above, stays in viewport
- Portal-rendered, CSS transition entrance, dismisses on Escape/click-outside/scroll
Double-Click Quick Create
- Inline title input, PT1H default, timer-based click disambiguation
- Component:
components/calendar/quick-event-input.tsx
iCalendar Import
- Files:
lib/jmap/client.ts(parseCalendarEvents),components/calendar/ical-import-modal.tsx - Multi-step flow: file select → preview list → calendar selector → import (5MB max)
Email Filters & Sieve Rules (RFC 9661)
- Types:
lib/jmap/sieve-types.ts - Client:
lib/jmap/client.ts(12 Sieve methods) - Generator/Parser:
lib/sieve/generator.ts,lib/sieve/parser.ts - Store:
stores/filter-store.ts - UI:
components/settings/filter-settings.tsx,components/filters/filter-rule-modal.tsx,components/filters/sieve-editor-modal.tsx - Conditions: From, To, Cc, Subject, Custom Header, Size, Body
- Actions: Move, Copy, Forward, Mark read, Star, Label, Discard, Reject, Keep, Stop
Email Templates
- Local storage via Zustand persist middleware
- Files:
lib/template-types.ts,stores/template-store.ts,lib/template-utils.ts - Components:
components/templates/(template-manager-modal, template-form, template-picker, placeholder-fill-modal) - Placeholder variables:
{{variable}}syntax with auto-fill from composer context - Composer shortcut: Ctrl+Shift+T
Accessibility (WCAG 2.0 AA)
- Color contrast rules documented in CLAUDE.md
- All color via CSS variables or Tailwind classes
- ARIA roles on calendar grids, event cards, modals
- Focus trap in all modals, 44px mobile touch targets
- Reduced-motion media query, sr-only live region
Dependency Versions (2026-02-16)
- next 16.1.6, react 19.2.4, next-intl 4.8.3, zustand 5.0.11, vitest 4.0.18
- @types/node 25, jsdom 28, lucide-react 0.564
Feature Completeness Summary
- Authentication: Complete (Basic Auth + TOTP 2FA + OAuth2/OIDC with PKCE)
- Email Operations: Complete (threading, unsubscribe, templates)
- Real-time Updates: Complete (EventSource push)
- UI: Settings integrated, DnD, context menus, mobile, keyboard, WCAG AA
- Identity Management: Complete (CRUD, sub-addressing, signatures)
- Contacts/Address Book: Complete (groups, vCard, bulk ops)
- Advanced Search: Complete (JMAP filters, search chips)
- Vacation Responder: Complete (JMAP VacationResponse)
- Calendar: Phase 5 complete (event detail popover, quick notes, drag-create, resize, recurring scope, quick create, duplication, import, notifications)
- Email Filters: Complete (Sieve RFC 9661, visual + raw editor)
- Security: CSP Report-Only + all P0 headers, sandboxed iframe for HTML emails
- API Robustness: Exponential backoff retry (
lib/jmap/retry.ts) for transient JMAP failures - Sidebar: Tag counts section, empty folder (junk/trash), resizable width (
hooks/use-resize-handle.ts) - Density: Extra-compact option (28px desktop, 44px touch), persisted in settings
- Sender Info: Expandable panel in email viewer (
components/email/sender-info-panel.tsx) - Security Tooltips: Plain-language SPF/DKIM/DMARC explanations on hover
- Testing: 704 tests passing