diff --git a/lib/data/repositories/email_repository_impl.dart b/lib/data/repositories/email_repository_impl.dart index 74463c2..5179e15 100644 --- a/lib/data/repositories/email_repository_impl.dart +++ b/lib/data/repositories/email_repository_impl.dart @@ -2963,6 +2963,20 @@ class EmailRepositoryImpl implements EmailRepository { }) async { if (query.length < 2) return []; final pattern = '%${query.toLowerCase()}%'; + + // Addresses we deliberately wrote to (sent folder) should appear before + // addresses that happened to email us (inbox/other folders). + final sentMailboxes = await (_db.select(_db.mailboxes) + ..where((t) { + Expression cond = t.role.equals('sent'); + if (accountId != null) { + cond = t.accountId.equals(accountId) & cond; + } + return cond; + })) + .get(); + final sentPaths = {for (final m in sentMailboxes) m.path}; + final rows = await (_db.select(_db.emails) ..where((t) { Expression cond = const Constant(true); @@ -2977,11 +2991,22 @@ class EmailRepositoryImpl implements EmailRepository { ..limit(100)) .get(); + // Two passes: sent-folder rows first (prioritise recipients we chose), + // then other rows (senders who contacted us). + final sortedRows = [ + ...rows.where((r) => sentPaths.contains(r.mailboxPath)), + ...rows.where((r) => !sentPaths.contains(r.mailboxPath)), + ]; + final seen = {}; final results = []; final lowerQuery = query.toLowerCase(); - for (final row in rows) { - for (final jsonStr in [row.fromJson, row.toAddresses, row.ccJson]) { + for (final row in sortedRows) { + final isSent = sentPaths.contains(row.mailboxPath); + final fields = isSent + ? [row.toAddresses, row.ccJson, row.fromJson] + : [row.fromJson, row.toAddresses, row.ccJson]; + for (final jsonStr in fields) { final list = jsonDecode(jsonStr) as List; for (final e in list) { final map = e as Map; diff --git a/test/unit/email_repository_impl_test.dart b/test/unit/email_repository_impl_test.dart index 256ea0b..d2edc48 100644 --- a/test/unit/email_repository_impl_test.dart +++ b/test/unit/email_repository_impl_test.dart @@ -497,6 +497,60 @@ void main() { }, ); + test( + 'searchAddresses prioritises sent-folder addresses over newer received', + () async { + final r = _makeRepos(); + await r.accounts.addAccount(_account, 'pw'); + + // Register the Sent mailbox so searchAddresses knows its role. + await r.db.into(r.db.mailboxes).insert( + MailboxesCompanion.insert( + id: 'acc-1:Sent', + accountId: 'acc-1', + path: 'Sent', + name: 'Sent', + role: const Value('sent'), + ), + ); + + // Older sent email: user deliberately wrote to info@foo.de. + await r.db.into(r.db.emails).insert( + EmailsCompanion.insert( + id: 'acc-1:sent-1', + accountId: 'acc-1', + mailboxPath: 'Sent', + uid: 1, + receivedAt: DateTime(2025), + toAddresses: const Value( + '[{"name":"Foo","email":"info@foo.de"}]', + ), + ), + ); + + // Newer received email: spam arrived today from info@spam.de. + await r.db.into(r.db.emails).insert( + EmailsCompanion.insert( + id: 'acc-1:inbox-1', + accountId: 'acc-1', + mailboxPath: 'INBOX', + uid: 2, + receivedAt: DateTime(2026), + fromJson: const Value( + '[{"name":"Spam","email":"info@spam.de"}]', + ), + ), + ); + + // Even though spam is newer, the sent-folder address should win. + final results = await r.emails.searchAddresses(null, 'info'); + expect(results.map((a) => a.email).toList(), [ + 'info@foo.de', + 'info@spam.de', + ]); + }, + ); + // ── IMAP method tests ──────────────────────────────────────────────────── test(