Notes can now be added and deleted on any email. Each note is stored as a message in a dedicated Notes folder on the IMAP or JMAP server, so:
Multi-user safe — all clients connected to the same account see the same notes
Move-stable — notes are keyed by the RFC 2822 Message-ID header (via X-SharedInbox-Note-For custom header), not the IMAP UID, so they survive folder moves
No local-only storage — the server is the source of truth; the local Drift cache is only a read-through cache
NoteRepository + NoteRepositoryImpl: IMAP uses APPEND to Notes folder with X-SharedInbox-Note-For/X-SharedInbox-Note-Id custom headers, SEARCH HEADER to sync, UID STORE \Deleted + EXPUNGE to delete. JMAP uses Email/set create/destroy in a Notes mailbox, Email/get with header:...:asText to sync.
di.dart: noteRepositoryProvider + notesProvider stream family
email_detail_screen.dart: Notes section below the email body — list with delete buttons, "Add" dialog. Notes synced from server once when the screen opens.
migration_test.dart: updated for schema v39
Verification
flutter analyze lib/ → no issues
flutter test test/unit/ → 335 tests, all pass
Closes #436
## What changed
Notes can now be added and deleted on any email. Each note is stored as a message in a dedicated **Notes** folder on the IMAP or JMAP server, so:
- **Multi-user safe** — all clients connected to the same account see the same notes
- **Move-stable** — notes are keyed by the RFC 2822 `Message-ID` header (via `X-SharedInbox-Note-For` custom header), not the IMAP UID, so they survive folder moves
- **No local-only storage** — the server is the source of truth; the local Drift cache is only a read-through cache
## Implementation
- **Schema v39**: new `EmailNotes` table (`id`, `accountId`, `messageId`, `noteText`, `serverId`, `createdAt`)
- **`NoteRepository`** + **`NoteRepositoryImpl`**: IMAP uses `APPEND` to `Notes` folder with `X-SharedInbox-Note-For`/`X-SharedInbox-Note-Id` custom headers, `SEARCH HEADER` to sync, `UID STORE \Deleted` + `EXPUNGE` to delete. JMAP uses `Email/set` create/destroy in a `Notes` mailbox, `Email/get` with `header:...:asText` to sync.
- **`di.dart`**: `noteRepositoryProvider` + `notesProvider` stream family
- **`email_detail_screen.dart`**: Notes section below the email body — list with delete buttons, "Add" dialog. Notes synced from server once when the screen opens.
- **`migration_test.dart`**: updated for schema v39
## Verification
- `flutter analyze lib/` → no issues
- `flutter test test/unit/` → 335 tests, all pass
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #436
What changed
Notes can now be added and deleted on any email. Each note is stored as a message in a dedicated Notes folder on the IMAP or JMAP server, so:
Message-IDheader (viaX-SharedInbox-Note-Forcustom header), not the IMAP UID, so they survive folder movesImplementation
EmailNotestable (id,accountId,messageId,noteText,serverId,createdAt)NoteRepository+NoteRepositoryImpl: IMAP usesAPPENDtoNotesfolder withX-SharedInbox-Note-For/X-SharedInbox-Note-Idcustom headers,SEARCH HEADERto sync,UID STORE \Deleted+EXPUNGEto delete. JMAP usesEmail/setcreate/destroy in aNotesmailbox,Email/getwithheader:...:asTextto sync.di.dart:noteRepositoryProvider+notesProviderstream familyemail_detail_screen.dart: Notes section below the email body — list with delete buttons, "Add" dialog. Notes synced from server once when the screen opens.migration_test.dart: updated for schema v39Verification
flutter analyze lib/→ no issuesflutter test test/unit/→ 335 tests, all pass