Kanmail is a desktop email client that functions like a kanban board, built with Wails v3 (Go backend + React frontend). It supports Mac, Windows, and Linux.
Entry Point: main.go creates the Kanmail app and starts the Wails app.
Core Structure (internal/kanmail.go):
Kanmailstruct holds the Wails app and all services- Services are registered with Wails as bound Go methods callable from frontend
- Circular dependencies are resolved via
Bootstrap()pattern
Services (internal/services/):
AppService: Application lifecycle, window management, license checking, analyticsSettingsService: User settings and configuration persistenceAccountsService: Manages email accounts (creates/deletes Account instances)EmailsService: High-level email operations (send, fetch, etc.)ContactsService: Contact management and avatars
Email Implementation (internal/emails/):
Account: Represents a single email account with IMAP/SMTP connection poolsFolder: Represents an IMAP mailbox with UID tracking and pagination- Tracks UIDs from the last 90 days for pagination
- Uses sparse UID → email cache populated during pagination
lastSentUIDandlastSentDatetrack what frontend knows about
ConnectionPool: Manages pooled IMAP/SMTP connections (regular, priority, background)imapinterface/: Abstraction layer allowing fake IMAP for testing/screenshots
Key Patterns:
- Connection pooling for IMAP/SMTP with priority levels
- UID-based pagination for email folders (folders >1000 emails paginate)
- Sparse caching with cache invalidation on UID validity changes
- OAuth2 support with token refresh (see
emails/oauth/) - Context-based logging with
zerolog
Caches (internal/caches/):
- SQLite-based caching (avatars, contacts, email metadata, folder UIDs, licenses)
- Single shared
caches.dbfile managed byCachesstruct
Types (internal/types/):
AccountSettings,FolderName,AccountName,Emailand other domain typesAccountErrorfor wrapping account-specific errors- Event types for frontend communication
Build System: Vite with React plugin, TypeScript checking, Babel decorators support
Structure:
src/components/: React components organized by featureemails/: Email list, thread, message componentssettings/: Settings UI componentscontacts/,send/,license/, etc.
src/stores/: State management using custom store patternbase.tsx: BaseStore class with subscription systememails/,settings.ts,contacts.ts, etc.- Uses decorator pattern with
@subscribefor component subscriptions
src/util/: Utility functionssrc/styles/: LESS stylesheetssrc/wails/: Auto-generated Wails runtime (DO NOT EDIT MANUALLY)src/bindings/: Auto-generated Go service bindings (DO NOT EDIT MANUALLY)
State Management:
- Custom store pattern with
BaseStoreclass - Components subscribe to stores via
subscribe()decorator - Stores notify subscribed components on state changes
- NEVER edit files in
frontend/wails/orfrontend/bindings/- they are auto-generated - The project uses a custom fork of go-imap (
github.com/oxygem/go-imap/v2) - see replace directive ingo.mod - Email threading logic in
frontend/src/threading.js - Connection pools maintain 2 regular + 2 priority + 1 background IMAP connections per account