From 4ba18370a4d38f8817f9a4a58e446a6d633e51e3 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 11 Aug 2026 01:26:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(mail):=20Blob/get=20=E5=85=BC=E5=AE=B9=20St?= =?UTF-8?q?alwart=20=E7=9A=84=20data:asText=20=E7=BA=AF=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stalwart v0.11 对 text/* 直接返回 data:asText(非标准 base64 的 data),fetchEmailBody 优先读 data:asText,缺失时回退 atob(data) --- src/utils/jmap.ts | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/utils/jmap.ts b/src/utils/jmap.ts index 5841306..df13edd 100644 --- a/src/utils/jmap.ts +++ b/src/utils/jmap.ts @@ -109,25 +109,30 @@ export class JmapClient { } /** 拉取邮件正文内容——Stalwart v0.11 的 Email/get 不返回 bodyValues, - * 正文通过 Blob/get 按 blobId 获取(base64 编码),HTML 正文提取纯文本 */ + * 正文通过 Blob/get 按 blobId 获取。注意 Stalwart 对 text/* 直接返回 + * data:asText(纯文本),标准 base64 则走 data 字段 */ async fetchEmailBody(email: JmapEmail): Promise { const parts = [...(email.textBody || []), ...(email.htmlBody || [])] for (const p of parts) { if (!p.blobId) continue try { - const payload = await this.call<{ list?: Array<{ id: string; data?: string }> }>( + const payload = await this.call<{ list?: Array<{ id: string; data?: string; 'data:asText'?: string }> }>( 'Blob/get', { accountId: this.accountId, ids: [p.blobId] }, ['urn:ietf:params:jmap:core', 'urn:ietf:params:jmap:blob'], ) - const data = payload.list?.[0]?.data - if (data) { - const text = atob(data) - if ((p.type || '').toLowerCase() === 'text/html') { - return text.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim() - } - return text + const item = payload.list?.[0] + if (!item) continue + // Stalwart v0.11 文本正文直接给 data:asText;标准实现用 base64 的 data + let text = item['data:asText'] + if (text == null) { + if (!item.data) continue + text = atob(item.data) } + if ((p.type || '').toLowerCase() === 'text/html') { + return text.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim() + } + return text } catch { /* 尝试下一个 part */ }