You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TIdMessage处理含内联图片的MIME格式并还原HTML?

提取MIME内联图片Base64并还原HTML渲染的解决方案

问题描述

使用TIdMessage库加载本地MIME文本文件时,已能识别内联附件的Content-Disposition和Content-Type,但无法提取内联图片的原始Base64内容。尝试用OpenLoadStream访问TIdAttachment时,得到的是二进制图片数据而非Base64字符串,需要将Base64转换为data URI插入HTML以还原图片渲染。

提供的MIME内容

Content-Type: multipart/alternative; boundary="qawqKLHOZYgscUPhZKw5hacv=_UlERjiEj"
MIME-Version: 1.0
Date: Mon, 25 Mar 2024 10:17:34 +0800

This is a multi-part message in MIME format

--qawqKLHOZYgscUPhZKw5hacv=_UlERjiEj
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Sample HTML

--qawqKLHOZYgscUPhZKw5hacv=_UlERjiEj
Content-Type: multipart/related; type="text/html";
    boundary="5SZQJxkhHuQyExC8cj=_sPNysz4gQuoIGj"

--5SZQJxkhHuQyExC8cj=_sPNysz4gQuoIGj
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

<P><STRONG>Sample HTML</STRONG></P>
<P><STRONG><IMG style=3D"HEIGHT: 184px; WIDTH: 194px" border=3D0 hspac=
e=3D0 alt=3D"" src=3D"cid:/Desktop/potato.gif" width=3D495 align=3Dbas=
eline height=3D497></STRONG></P>

--5SZQJxkhHuQyExC8cj=_sPNysz4gQuoIGj
Content-Type: image/gif;
    name="/Desktop/potato.gif"
Content-Transfer-Encoding: base64
Content-Disposition: inline;
    filename="/Desktop/potato.gif"
Content-ID: </Desktop/potato.gif>

<base 64 data>

--5SZQJxkhHuQyExC8cj=_sPNysz4gQuoIGj--

--qawqKLHOZYgscUPhZKw5hacv=_UlERjiEj--

.

初始代码

var vMsg := TIdMessage.Create(nil);
try
  vMsg.LoadFromFile('D:\Desktop\Complete MIME 2.txt');
  for var i := 0 to vMsg.MessageParts.Count - 1 do begin
    var o := vMsg.MessageParts.Items[i];

    if (o.PartType = TIdMessagePartType.mptAttachment) then begin
      if o.ContentDisposition.Equals('inline') then begin
        var sContentID := o.ContentID.Substring(1, o.ContentID.Length - 2);

        // how to retrieve inline image base 64?
      end;
    end;
  end;
finally
  vMsg.Free;
end;

更新尝试代码

var vAttachment := TIdAttachment(o);
var vAttachmentStream := vAttachment.OpenLoadStream;
var vStringStream := TStringStream.Create;
try
  vStringStream.LoadFromStream(vAttachmentStream);
  vStringStream.Position := 0;
  OutputDebugString(PChar(vStringStream.DataString));
finally
  vAttachment.CloseLoadStream;
  vStringStream.Free;
end;

解决方案

核心原理

TIdMessage默认会自动解码Content-Transfer-Encoding指定的编码(如Base64),所以直接通过OpenLoadStream获取的是解码后的二进制图片数据。要获取原始Base64字符串,需禁止自动解码,保留MIME部分的原始内容。

完整实现代码

var vMsg := TIdMessage.Create(nil);
try
  // 关键:禁止自动解码,保留原始Base64内容
  vMsg.NoDecode := True;
  vMsg.LoadFromFile('D:\Desktop\Complete MIME 2.txt');

  var htmlContent := '';
  // 第一步:提取并解码HTML内容(HTML使用quoted-printable编码)
  for var i := 0 to vMsg.MessageParts.Count - 1 do begin
    var o := vMsg.MessageParts.Items[i];
    if o is TIdText then begin
      var txt := TIdText(o);
      if txt.ContentType.StartsWith('text/html') then begin
        // 解码quoted-printable编码的HTML
        htmlContent := TIdDecoderQuotedPrintable.DecodeString(txt.Body.Text, IndyTextEncoding_UTF8);
        Break;
      end;
    end;
  end;

  // 第二步:提取内联图片的Base64并替换HTML中的CID引用
  for var i := 0 to vMsg.MessageParts.Count - 1 do begin
    var o := vMsg.MessageParts.Items[i];
    if (o.PartType = TIdMessagePartType.mptAttachment) then begin
      var att := TIdAttachment(o);
      if att.ContentDisposition.Equals('inline') then begin
        // 清理ContentID的<>包裹符
        var sContentID := att.ContentID.Substring(1, att.ContentID.Length - 2);
        // 获取原始Base64内容(因NoDecode=True,Body即为Base64字符串)
        var base64Data := att.Body.Text;
        // 移除Base64中的换行符(MIME标准会插入换行,需清理)
        base64Data := StringReplace(base64Data, #13#10, '', [rfReplaceAll]);
        base64Data := StringReplace(base64Data, #10, '', [rfReplaceAll]);

        // 构造data URI格式,替换HTML中的CID
        var dataUri := 'data:' + att.ContentType + ';base64,' + base64Data;
        htmlContent := StringReplace(htmlContent, 'cid:' + sContentID, dataUri, [rfReplaceAll]);
      end;
    end;
  end;

  // 此时htmlContent已可直接用于渲染,包含内嵌的图片data URI
  // 示例:输出到调试窗口
  OutputDebugString(PChar(htmlContent));
finally
  vMsg.Free;
end;

关键步骤说明

  1. 禁止自动解码:设置vMsg.NoDecode := True,确保TIdMessage不处理Content-Transfer-Encoding,保留附件的原始Base64字符串。
  2. 解码HTML内容:HTML部分使用quoted-printable编码,需用TIdDecoderQuotedPrintable.DecodeString还原正常HTML文本。
  3. 清理Base64格式:MIME中的Base64会包含换行符,需移除才能生成有效的data URI。
  4. 替换CID引用:将HTML中cid:开头的图片引用替换为data:image/xxx;base64,xxx格式,使浏览器无需外部资源即可渲染图片。

内容的提问来源于stack exchange,提问作者Lyn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 07:05:00