# DashMail — Architecture Overview

DashMail

Technical Architecture & System Overview

# How DashMail Works

Version 1.2 · May 2026 · Little Creek Door Co. · Confidential

DashMail is a native Windows email client built on WinUI 3. It uses a local-first architecture — all email is stored in a SQLite database on the Windows host. The SMB network share is used only as a handoff zone: Mutt deposits incoming messages and DashMail queues outgoing ones.

## Table of Contents

## 1. Application Screenshots

Current state of the DashMail prototype — built in React/JSX as a visual specification for the WinUI 3 native build.

### Login Screen

Login screen — 50/50 split layout. Paper airplane logo + DashMail wordmark on dark left panel, mountain background photo on rounded right panel. Password-only authentication auto-matches account profile.

### Main Application

Main email client — three-pane layout: account/folder sidebar (left), email list with search (centre), reading pane with full email + attachments (right). Resizable panels, sign out button, connection status bar.

## 2. End-to-End System Architecture

DashMail follows the local-first (Option B) architecture. The SMB share acts only as a message handoff point — not a working mailstore.

### Receiving Mail

Mail ServerIMAP/POP3
→
Mutt Daemonon server
→
SMB Shareinbox\
→
DashMail Poller60s / watcher
→
SQLite DBmail.db
→
DashMail UIWinUI 3

### Sending Mail

DashMail UICompose
→
SQLite DBdrafts/sent
→
SMB Shareout\
→
Mutt Daemonsends via SMTP
→
Mail ServerSMTP
Core Principle
The SMB share is a handoff zone only. DashMail reads and writes exclusively to local SQLite during normal operation. A network outage never interrupts access to existing mail.

## 3. Email File Format

Each email on the SMB share is a folder containing these files. The parsing rules are deliberately simple:

.Mails\devon@littlecreekdoor.com\inbox\[message-folder]\ _headers_ <-- RFC 2822 headers (From, To, Subject, Date, Message-ID...) textfile0 <-- Plain text email body (only file rendered as message body) invoice.pdf <-- Any other files in the folder = attachments

File | Role | Action
--- | --- | ---
`_headers_` | RFC 2822 email headers | Parse: From, To, Subject, Date, Message-ID, Spam-Score
`textfile0` | Email body — plain text | Store as body_text in SQLite, render in reading pane
Everything else | Attachment | Copy to local attachments cache, register in DB

Header Field | Example Value | UI Usage
--- | --- | ---
`From:` | Charleen Roland <charroland@zoominternet.net> | Sender name + avatar initials
`Delivered-To:` | sales@littlecreekdoor.com | Account routing
`Subject:` | Charleen and Rich Roland | Email list + reading pane title
`Date:` | Sat, 23 May 2026 10:33:48 -0400 | Timestamp display
`Message-ID:` | <1076592763...@zoominternet.net> | Unique key / deduplication
`X-Spam-Status:` | No, score=1.7 | Spam indicator in UI
`Thread-Topic:` | Charleen and Rich Roland | Thread grouping

## 4. Receiving Email — Step by Step

1. Mutt daemon polls the mail server (IMAP/POP3) on a schedule (~2 minutes).
2. New messages are written as individual folders into `\\mailserver\mail\.Mails\[account]\inbox\` containing `_headers_`, `textfile0`, and any attachments.
3. DashMail Poller (background thread) detects new folders via `FileSystemWatcher` or 60-second timer.
4. `_headers_` is parsed with MimeKit HeaderList — From, To, Subject, Date, Message-ID, Spam-Score extracted.
5. `textfile0` is read as the email body. All other files in the folder are copied to the local attachment cache at `%LOCALAPPDATA%\DashMail\attachments\[guid]\`.
6. A row is inserted into local `mail.db`. FTS5 full-text search index is updated automatically.
7. The message folder is deleted from the SMB share — now fully owned by the local database.
8. DashMail UI receives a live notification (ObservableCollection update) — new email appears instantly.

Offline Behaviour
If the SMB share is unreachable, steps 1–7 are skipped silently. The user has full access to all previously downloaded mail without a network connection.

## 5. Sending Email — Step by Step

1. User composes in the Compose window. Draft is auto-saved to local SQLite continuously.
2. User clicks Send. DashMail creates: `\\mailserver\mail\.Mails\[account]\out\[timestamp]-[guid]\`
3. Writes `_headers_`: From, To, Subject, Date, Message-ID, `X-Mailer: DashMail 1.0`.
4. Writes `textfile0`: the plain text message body.
5. Copies any user attachments into the same folder.
6. Email immediately moves to Sent folder in local SQLite — visible in Sent instantly.
7. Mutt daemon detects the folder in `out\`, transmits via SMTP, removes the folder.

## 6. Local Storage — SQLite Schema

CREATE TABLE emails ( id TEXT PRIMARY KEY, -- from Message-ID header account TEXT, -- devon@littlecreekdoor.com folder TEXT, -- inbox | sent | drafts | archive | trash from_addr TEXT, -- "Charleen Roland <charroland@...>" to_addr TEXT, subject TEXT, body_text TEXT, -- contents of textfile0 date DATETIME, is_read INTEGER DEFAULT 0, is_starred INTEGER DEFAULT 0, spam_score REAL, -- parsed from X-Spam-Status score= has_attachments INTEGER DEFAULT 0, modified_at DATETIME DEFAULT (datetime('now')) -- updated by trigger on any change ); CREATE TRIGGER emails_update_modified AFTER UPDATE ON emails BEGIN UPDATE emails SET modified_at = datetime('now') WHERE id = NEW.id; END; CREATE INDEX idx_emails_modified ON emails(modified_at); -- Backup chain tracking CREATE TABLE backup_log ( id TEXT PRIMARY KEY, -- GUID type TEXT, -- 'full' | 'incremental' base_id TEXT, -- parent full backup GUID (incrementals only) created_at DATETIME, zip_path TEXT, -- absolute path to backup ZIP email_count INTEGER, size_bytes INTEGER, checksum TEXT -- SHA-256 of ZIP file ); CREATE TABLE attachments ( id TEXT PRIMARY KEY, email_id TEXT, filename TEXT, -- "invoice.pdf", "photo.jpg", etc. local_path TEXT, size_bytes INTEGER ); CREATE VIRTUAL TABLE email_fts USING fts5(subject, body_text, from_addr);

## 7. SMB Share — Folder Structure

⚠ Critical constraint — Read-only share policy:
DashMail never deletes, moves, renames, or modifies any file or folder on the SMB share. The share is accessed concurrently by multiple users and Mutt is solely responsible for managing the inbox and sent folders. DashMail uses Message-ID deduplication in SQLite to avoid re-importing messages it has already seen — no folder is cleared or touched after reading.

Folder | Managed by | DashMail action
--- | --- | ---
`inbox\` | Mutt (writes incoming message folders) | Reads `_headers_` + `textfile0`, checks Message-ID against SQLite, imports unseen — never deletes
`out\` | DashMail (writes outgoing message folders) | Writes new `_headers_` + `textfile0` folder; Mutt picks up and sends
`sent\` | Mutt (optional mirror) | Not modified by DashMail
`drafts\` | — | Not used on SMB; drafts live in local SQLite only
`archive\` | — | Not used on SMB; archive lives in local SQLite only
`trash\` | — | Not used on SMB; deleted emails are flagged locally only

\\mailserver\mail\.Mails\ devon@littlecreekdoor.com\ inbox\ <-- Mutt writes here; DashMail reads & never deletes out\ <-- DashMail writes here; Mutt sends & clears sent\ <-- Mutt mirror after sending (read-only for DashMail) drafts\ <-- Not used (drafts are local SQLite only) archive\ <-- Not used (archive is local SQLite only) trash\ <-- Not used (trash is local SQLite only) sales@littlecreekdoor.com\ inbox\ out\ sent\ ... dmbont23@mailbox.org\ inbox\ out\ sent\ ... default\ inbox\ out\ sent\ ...

## 8. Technology Stack

Layer | Technology | Purpose
--- | --- | ---
UI Framework | WinUI 3 / Windows App SDK 1.6+ | Native Windows controls, Fluent Design, Mica material
Language | C# 12 | All app logic, services, ViewModels
UI Pattern | MVVM (CommunityToolkit.Mvvm) | Data binding, commands, ObservableCollection
Header Parsing | MimeKit / MailKit | Parse RFC 2822 `_headers_` files, write outgoing headers
Email Body | Plain text (`textfile0`) | Read as-is; write plain text for outgoing mail
Local Database | SQLite + FTS5 (Microsoft.Data.Sqlite) | All email storage + instant full-text search
SMB Access | Native Windows UNC paths | Read `inbox\`, write `out\` — no extra library needed
File Watching | FileSystemWatcher (.NET) | Real-time detection of new message folders on SMB
Reading Pane | RichTextBlock / WebView2 | Render `textfile0` body
Notifications | AppNotificationBuilder | Windows Action Center toasts for new mail
Packaging | MSIX | Installer, auto-update, Windows Store compatible
IDE | Visual Studio 2022 | Build, XAML designer, debugger

### Key NuGet Packages

Microsoft.WindowsAppSDK // WinUI 3 framework CommunityToolkit.Mvvm // ObservableObject, RelayCommand CommunityToolkit.WinUI.UI // Additional WinUI controls MimeKit // RFC 2822 _headers_ parsing and writing Microsoft.Data.Sqlite // SQLite + FTS5 full-text search WinUIEx // Extended window management

## 9. Build Phases & Timeline

1
Project Shell — VS 2022, custom title bar, Mica, login page (logo, password-only auth, mountain photo) · 2 days
2
Main Email Shell — sidebar, email ListView, reading pane, GridSplitter resize, status bar, sign out · 3 days
3
SMB + Data Layer — SmbService, MailService, SQLite schema, FileSystemWatcher, `_headers_` parser, `textfile0` reader, attachment cache · 2 days
4
Compose & Send — Compose window, reply/forward, attachments, write `_headers_` + `textfile0` to SMB `out\` · 2 days
5
Settings — General, Appearance, Notifications, Accounts, Filters, Privacy, Encryption, Spam, Backup, Advanced · 3 days
6
Polish & Features — context menus, attachment viewer/download/print, notifications, dark/light theme, keyboard shortcuts · 2 days
7
Packaging — MSIX installer, app icon, version info, auto-update manifest · 1 day
Total estimated build time: 2 – 3 weeks

## 10. Backup & Restore

### Overview

DashMail stores all email, settings, and metadata in a local SQLite database (`mail.db`). The SMB share is never modified during backup or restore. Users can schedule automatic backups, choose between Smart / Always Full / Always Incremental modes, configure multiple backup destinations, and restore from any point in the backup chain.

### Backup Format

Each backup is a timestamped ZIP archive containing:

dashmail-backup-20260524-220001-full.zip manifest.json // type, created_at, base_id, email_count, checksum mail.db // complete SQLite database (via online backup API) settings.json // profile + app settings snapshot attachments\ // all cached attachment files (full backup only) dashmail-backup-20260525-220001-inc.zip manifest.json // type:"incremental", base_id:"<full GUID>" email_changes.sql // UPSERT statements for rows where modified_at > last backup deleted_ids.json // locally-deleted email IDs (SMB share is unchanged) attachments\ // only attachments added since last backup

### Backup Modes

Mode | Behaviour | Storage impact
--- | --- | ---
Smart (recommended) | Daily incrementals; auto-resets to full every 30 days or 10 incrementals | Low — incremental ZIPs are typically < 2 MB
Always full | Every scheduled run produces a complete backup | High — each run copies entire database
Always incremental | Only changes since last backup are captured | Very low — requires a full backup to exist first

### Incremental Change Detection

The `emails.modified_at` column is updated automatically by a SQLite trigger on every `UPDATE` (read/unread, starred, moved, label changes). At backup time, DashMail queries `SELECT * FROM emails WHERE modified_at > :last_backup_ts` and serialises the results as `INSERT OR REPLACE` statements into `email_changes.sql`.

-- Trigger that keeps modified_at current on any row change CREATE TRIGGER emails_update_modified AFTER UPDATE ON emails BEGIN UPDATE emails SET modified_at = datetime('now') WHERE id = NEW.id; END;

### Backup Chain Management

①
A new full backup starts a chain. Its GUID becomes the `base_id` for all subsequent incrementals.
②
Each incremental records `base_id = <full GUID>` in its manifest so restore knows the required base.
③
After 30 days or 10 incrementals, Smart mode automatically triggers a fresh full backup, starting a new chain.
④
When the retention limit is reached (default: 5 sets), the oldest complete chain (full + all its incrementals) is deleted from the backup folder.
⑤
Scheduled backups are registered with Windows Task Scheduler at setup time. DashMail registers a task that runs even when the app is closed.

### Restore Procedure

❶
Safety backup — DashMail automatically creates a full backup of the current state before any restore begins.
❷
Select point — User picks a full or incremental backup from the history list (or browses to a ZIP file).
❸
Base restore — The full backup in the chain is applied first: `mail.db` replaces the live database via SQLite online backup API.
❹
Incremental replay — Each `email_changes.sql` in the chain is executed in date order up to the selected restore point.
❺
Attachment merge — Cached attachment files are restored to the local cache folder. The SMB share is never touched.
❻
Restart required — DashMail prompts the user to restart so all services reload from the restored database.
Key guarantee: The SMB share is never read, written to, or modified during backup or restore. Backup operates entirely on the local SQLite database and attachment cache. Multiple users can continue accessing the share without interruption.