
PHP 8.1 升级后,使用 mail() 发送 multipart/alternative 邮件时,正文头部意外显示边界标记(如 --PHP-alt-xxx),根本原因是换行符不规范(误用 \n\n 而非 \r\n),导致 MIME 结构解析异常,被收件客户端误作明文内容渲染。
php 8.1 升级后,使用 `mail()` 发送 multipart/alternative 邮件时,正文头部意外显示边界标记(如 `--php-alt-xxx`),根本原因是换行符不规范(误用 `\n\n` 而非 `\r\n`),导致 mime 结构解析异常,被收件客户端误作明文内容渲染。
在 PHP 8.1(尤其是 8.1.31 及后续维护版本)中,mail() 函数对邮件协议规范的校验更加严格。RFC 2822 明确规定:邮件头与正文之间、各 MIME 部分之间必须使用 \r\n(CRLF)作为行终止符,而不能仅用 \n(LF)。你提供的代码中,虽然 $headers 和 $body 数组拼接时使用了 implode("\r\n", ...),但关键隐患隐藏在 MIME 部分之间的空行构造逻辑中:
// ❌ 错误示例:此处使用了 "\n"(LF),违反 RFC 标准 $body[] = ""; // ← 这个空行实际是 "\n",不是 "\r\n"
当 implode("\r\n", $body) 执行时,数组元素间插入 \r\n,但每个 $body[] = "" 本身仅贡献一个 \n —— 最终生成类似 --boundary\r\nContent-Type: ...\r\nContent-Transfer-Encoding: 8bit\r\n\nYour message 的结构。中间的 \n\n(即两个 LF)被部分 MTA 或客户端识别为“头尾分隔符”,但因不符合 \r\n\r\n 规范,导致后续内容(包括边界标记)未被正确解析为 MIME 控制指令,而是原样落入邮件正文。
✅ 正确做法是:所有空行必须显式写为 "\r\n",而非 ""。同时确保整个 MIME 结构严格遵循 RFC 标准:
<?php $random_hash = md5(uniqid(time(), true));
$from = 'From: "Site Name" <webmaster@example.com>';
$fromemail = 'webmaster@example.com';
$email = 'user@example.com';
$subject = 'HTML 邮件测试';
$message = '这是纯文本内容';
$html_message = '<p>这是<strong>HTML</strong>内容</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill2138" title="PHP"><img
src="https://img.php.cn/upload/skill/000/000/081/178884013267959.jpg" alt="PHP" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill2138" title="PHP" class="overflowclass">PHP</a>
<p class="overflowclass">编写健壮的PHP代码,规避类型转换陷阱、数组怪癖及常见安全漏洞。</p>
</div>
<a rel="nofollow" href="/xiazai/skill2138" title="PHP" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>';
// ✅ 正确构造 headers(全部使用 \r\n 换行)
$headers = [
$from,
"Reply-To: $fromemail",
"Content-Type: multipart/alternative; boundary=\"PHP-alt-$random_hash\"",
"MIME-Version: 1.0",
"X-PHP-Script: " . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']
];
// ✅ 正确构造 body:空行必须为 "\r\n",不可为 ""
$body = [];
// Plain text part
$body[] = "--PHP-alt-$random_hash";
$body[] = "Content-Type: text/plain; charset=\"utf-8\"";
$body[] = "Content-Transfer-Encoding: 8bit";
$body[] = "\r\n"; // ← 关键!显式使用 \r\n 表示空行
$body[] = $message;
// HTML part
$body[] = "--PHP-alt-$random_hash";
$body[] = "Content-Type: text/html; charset=\"utf-8\"";
$body[] = "Content-Transfer-Encoding: 8bit";
$body[] = "\r\n"; // ← 同样必须是 \r\n
$body[] = "<meta http-equiv='\"Content-Type\"' content='\"text/html;' charset='utf-8\"'><title>$subject</title>$html_message";
// Final boundary
$body[] = "--PHP-alt-$random_hash--";
// ✅ 安全拼接(注意:结尾不能有多余 \r\n)
$full_body = implode("\r\n", $body);
$full_headers = implode("\r\n", $headers);
// 发送并检查结果
if (mail($email, $subject, $full_body, $full_headers)) {
echo "✅ 邮件发送成功(MIME 结构已合规)";
} else {
error_log("❌ mail() 返回 false,请检查服务器 MTA 状态及日志");
}
?>
⚠️ 重要注意事项:
-
不要依赖
PHP_EOL:PHP_EOL在 Linux 是\n,Windows 是\r\n,而邮件协议要求统一为\r\n,必须硬编码; -
避免多余空白:
$headers或$body数组末尾不应有空字符串或空格,否则可能引入非法\r\n(带空格); -
字符编码需显式声明:
Content-Type中charset="utf-8"必须存在,中文内容建议对$message和$html_message使用mb_encode_mimeheader()处理主题,或对正文启用mb_internal_encoding('UTF-8'); -
生产环境强烈建议迁移到 SMTP 库:
mail()仅适合开发测试;真实项目请使用 PHPMailer 或 Symfony Mailer,它们自动处理 MIME、编码、认证与错误反馈,规避底层协议陷阱。
综上,--PHP-alt-... 出现在正文,不是 PHP 8.1 的 Bug,而是 MIME 构造不合规的必然表现。修正换行符、严守 RFC 2822,即可彻底解决。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










