Files
sharedinbox/README.md
T
Thomas GüttlerandClaude Sonnet 4.6 7c000dcee5 Add IMAP search: server-side OR SUBJECT/TEXT, inline results in email list
- EmailRepository: add searchEmails(accountId, mailboxPath, query)
- EmailRepositoryImpl: UID SEARCH with OR SUBJECT/TEXT criteria,
  fetch ENVELOPE+FLAGS for matching UIDs
- EmailListScreen: toggle search bar in AppBar; submit triggers server
  search; results replace the stream list; ESC/back closes search
- Refactored list into _buildList() shared by stream and search views
- README/PLAN.md updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 11:13:33 +02:00

5.5 KiB

SharedInbox License: MIT

IMAP/SMTP email client written in Flutter.

Targets Android, iOS, and Desktop (Linux done; macOS, Windows, Android, iOS scaffolded).
Supports multiple accounts — each synced independently via IMAP IDLE.

Design philosophy: offline-first

IMAP/SMTP server
       ↓
  AccountSyncManager  ←→  Drift (SQLite, local DB)
  (IMAP IDLE per account)         ↓
                            UI (reads only from DB)

The UI never touches the network. The sync engine runs in the background and writes to a local Drift database. Screens observe reactive streams from that DB.

Platform support

Platform Status
Linux desktop Working (task run)
Android APK builds (task build-android)
macOS desktop Scaffolded
Windows desktop Scaffolded
iOS Scaffolded

Key packages

Package Role
enough_mail IMAP / SMTP / MIME
drift Local SQLite ORM (offline-first store)
flutter_riverpod State management / DI
go_router Navigation
flutter_secure_storage Password storage

For users

Download the latest release from the Releases page (not yet published).

Run the app, tap +, and enter your IMAP/SMTP server details. The app syncs your INBOX in the background using IMAP IDLE and works offline — the network is only needed during initial sync and when sending mail.


For developers

Prerequisites

Nix with flakes enabled, and direnv.

# One-time: allow direnv in this directory
direnv allow

direnv loads the Nix flake automatically — no manual nix develop needed after that. The flake pins Flutter 3.41.6, Android SDK, Stalwart mail server (for integration tests), and all Linux desktop build tools (GTK3, clang, cmake).

First-time setup

# Generate the Drift database layer (required before first build)
task codegen

# Verify everything compiles and tests pass
task check

Daily workflow

task analyze          # flutter analyze (uses analysis_options.yaml)
task test             # pure-Dart unit tests — fast, no device
task test-flutter     # Flutter widget tests
task integration      # IMAP/SMTP integration tests via local Stalwart server
task run              # flutter run -d linux
task analyze-fix      # dart fix --apply

task check runs analyze + test in parallel — use it before every commit.

After changing the DB schema

Edit lib/data/db/database.dart, then:

task codegen   # regenerates lib/data/db/database.g.dart

database.g.dart is git-ignored; every developer must regenerate it after cloning or pulling schema changes.

Integration tests

task integration

Starts a local Stalwart mail server on random ports, runs the tests in test/integration/, then stops it. No manual setup needed — Stalwart is provided by the Nix flake.

Adding a screen

  1. Create lib/ui/screens/my_screen.dart — extend ConsumerWidget.
  2. Add a GoRoute in lib/ui/router.dart.
  3. Read from Riverpod providers in lib/di.dart; never call the network directly from UI.

Project layout

lib/
  core/
    models/          — plain Dart data classes (Account, Email, Mailbox, …)
    repositories/    — abstract interfaces
    sync/            — AccountSyncManager (IMAP IDLE + backoff)
    utils/           — htmlToPlain, fmtSize (pure functions, unit-tested)
  data/
    db/              — Drift schema + generated code
    imap/            — connectImap / connectSmtp helpers
    repositories/    — concrete implementations
  ui/
    screens/         — one file per screen
    router.dart      — go_router route tree
  di.dart            — Riverpod providers
  main.dart          — entry point

packages/
  enough_mail/       — vendored IMAP/SMTP library (editable)

stalwart-dev/        — local mail server config + start/test scripts
test/
  unit/              — pure-Dart unit tests (no device)
  integration/       — IMAP/SMTP tests against local Stalwart

Working features

  • Multiple accounts — add any number of IMAP/SMTP accounts; each syncs independently
  • IMAP IDLE — background sync with push-like latency; exponential backoff (5 s → 5 min) on error
  • Mailbox list — shows all folders with unread / total counts
  • Email list — sender, subject, date; bold for unread; manual sync button
  • Email detail — renders plain text; falls back to HTML→plain conversion; marks as read on open; shows attachment names and sizes
  • Reply / Reply all — pre-fills To, Subject (Re:), Cc from original
  • Compose — To, Cc, Subject, Body fields; sends via SMTP
  • Flag / unflag — star button in detail view; amber star indicator in list; synced to server
  • Move to folder — bottom-sheet folder picker; moves on server via IMAP MOVE
  • Attachment indicators — paperclip icon in email list; filename + size in detail
  • Delete email — removes from server (IMAP expunge) and local DB
  • Settings — list and remove accounts
  • Search — IMAP server-side search (subject + body); results shown inline, no navigation change
  • Offline-first — all reads come from local Drift/SQLite DB; network only for sync and send