fix(email): resolve cid: inline images in multipart/related messages (#89)

Emails with multipart/related structure reference embedded images via
cid: URIs.  The WebView's CSP only allows data:/blob: sources, so those
images were never shown.  injectInlineImages() now replaces each cid:
reference with a data: URI using the decoded bytes from the MIME tree,
both for double-quoted and single-quoted src attributes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Thomas SharedInbox
2026-05-15 11:02:22 +02:00
co-authored by Claude Sonnet 4.6
parent 69e358204d
commit 653ef92430
3 changed files with 144 additions and 1 deletions
@@ -13,6 +13,7 @@ import 'package:sharedinbox/core/models/account.dart' as account_model;
import 'package:sharedinbox/core/models/email.dart' as model;
import 'package:sharedinbox/core/repositories/account_repository.dart';
import 'package:sharedinbox/core/repositories/email_repository.dart';
import 'package:sharedinbox/core/utils/cid_utils.dart';
import 'package:sharedinbox/core/utils/logger.dart';
import 'package:sharedinbox/data/db/database.dart';
import 'package:sharedinbox/data/imap/imap_client_factory.dart';
@@ -235,7 +236,9 @@ class EmailRepositoryImpl implements EmailRepository {
final fetch = await client.uidFetchMessage(emailRow.uid, '(BODY.PEEK[])');
final msg = fetch.messages.first;
final textBody = msg.decodeTextPlainPart();
final htmlBody = msg.decodeTextHtmlPart();
final rawHtml = msg.decodeTextHtmlPart();
final htmlBody =
rawHtml == null ? null : injectInlineImages(rawHtml, msg);
final contentInfos = msg.findContentInfo();
final attachmentsJson = jsonEncode(