如何正确构建含内嵌图片的 multipart 邮件以兼容 Apple Mail

13次阅读

如何正确构建含内嵌图片的 multipart 邮件以兼容 Apple Mail

本文详解 php 手动构造 multipart mime 邮件时的常见陷阱,重点解决 apple mail 显示空白、仅显示最后一张图等问题,通过嵌套 multipart/related + multipart/alternative 结构实现跨平台(ios/android/web)稳定渲染。

Apple Mail 对 MIME 结构的解析比大多数客户端更严格——它不支持在 multipart/alternative 中直接混排图像部分与 HTML 部分,也不接受 Content-ID 引用但未被正确包裹在 multipart/related 子边界内的内联图片。你原始代码的问题根源在于:单一层级的 multipart/alternative 无法承载内嵌资源(如 CID 引用的图片),导致 iOS 客户端忽略或错误解析整个 HTML 体,最终呈现为空白或仅最后一张图。

✅ 正确结构:嵌套式 multipart(recommended)

必须采用两层边界嵌套:

  • 外层:multipart/alternative(兼容纯文本客户端,提供降级内容)
  • 内层(HTML 部分中):multipart/related(专为 HTML + 内联资源设计,确保 CID 关联生效)

以下是可直接落地的修正方案(已验证在 Apple Mail、Outlook iOS、Gmail App、Thunderbird 和桌面 浏览器 中一致显示):

$boundary = md5(uniqid(rand())); // 全局唯一边界标识 $outerBoundary = 'b1_' . $boundary; $innerBoundary = 'b2_' . $boundary;  // ✅ 外层 headers:声明 multipart/alternative + 外边界 $headers = "MIME-Version: 1.0rn"; $headers .= "Content-Type: multipart/alternative; boundary="{$outerBoundary}"rn"; $headers .= "From: rn"; $headers .= "Reply-To: no-reply@yourdomain.netrn";  // ✅ 构建完整邮件体(注意顺序与换行!)$message = "";  // ▶ 第一部分:纯文本备选(Apple Mail 会忽略,但规范要求存在)$message .="--{$outerBoundary}rn"; $message .="Content-Type: text/plain; charset="us-ascii"rn"; $message .="Content-Transfer-Encoding: 7bitrnrn"; $message .="This email contains a visitor register with photos. Please view in HTML mode.rnrn";  // ▶ 第二部分:HTML 主体(类型为 multipart/related)$message .="--{$outerBoundary}rn"; $message .="Content-Type: multipart/related; boundary="{$innerBoundary}"; type="text/html"rnrn";  // ▶ 内层 HTML 内容(注意:此处不写 --b2_xxx,由下一行开始)$message .="--{$innerBoundary}rn"; $message .="Content-Type: text/html; charset="UTF-8"rn"; $message .="Content-Transfer-Encoding: 8bitrnrn";  // 插入你的完整 HTML(含 @@##@@)$message .= $mailHeader; $message .="

Visitors on ". date("d/m/Y", strtotime($_POST['date'])) ."

"; $message .= $table; $message .= $mailFooter; $message .="rn"; // ▶ 内层图片资源(每个图片必须在 --b2_xxx 边界内,且 Content-ID 严格匹配 HTML 中的 cid:xxx)foreach ($images as $imgData) {$imageName = $imgData['name']; // e.g.,'Robin0'$imageBase64 = $imgData['base64']; // 原始 base64 字符串(不含 data:……)$message .="--{$innerBoundary}rn"; $message .="Content-Type: image/jpeg; name="{$imageName}.jpg"rn"; // ⚠️ 用 image/jpeg 而非 image/jpg(更标准)$message .="Content-Transfer-Encoding: base64rn"; $message .="Content-ID: <{$imageName}>rn"; $message .="Content-Disposition: inline; filename="{$imageName}.jpg"rnrn"; $message .= chunk_split($imageBase64, 76,"rn"); // ✅ 每行 ≤76 字符,符合 RFC 2045 } // ▶ 结束内层 multipart/related $message .="--{$innerBoundary}--rn"; // ▶ 结束外层 multipart/alternative $message .="--{$outerBoundary}--rn"; // 发送 mail($to, $subject, $message, $headers);

⚠️ 关键注意事项

  • 边界命名不可重复:外层 b1_… 与内层 b2_… 必须不同,且全程统一大小写和引号(推荐双引号包裹 boundary 值);
  • 换行符必须为 rn:Unix n 在某些 SMTP 服务中会导致解析失败;
  • Base64 数据需 chunk_split():RFC 强制要求每行 ≤76 字符,否则 Apple Mail 可能截断;
  • Content-Type: image/jpeg 更可靠:image/jpg 并非标准 MIME 类型,部分 iOS 版本拒绝渲染;
  • 不要省略 text/plain 部分:虽然 Apple Mail 不显示它,但缺失会导致部分邮件网关标记为异常;
  • 避免在 HTML 中使用 data: URI:iOS Mail 不支持 base64 内联图片(src=”data:image/…”),必须用 cid: + multipart/related。

✅ 验证建议

发送测试邮件后,在 Apple Mail 中:

  1. 右键 →“显示原始邮件”(或按 Cmd+Shift+U);
  2. 检查是否存在两层 boundary= 声明;
  3. 确认所有 如何正确构建含内嵌图片的 multipart 邮件以兼容 Apple Mail 都有对应 Content-ID: 且位于同一 multipart/related 边界内;
  4. 查看 Base64 图片块是否以 rnrn 开头、以 rn 结尾,且无多余空行。

通过该结构,你将彻底规避 Apple Mail 的渲染缺陷,同时保持 Android、Web 客户端完美兼容——无需引入 PHPMailer 等依赖,纯原生 PHP 即可稳定交付专业级 HTML 邮件。

如何正确构建含内嵌图片的

text=ZqhQzanResources