如何用PHP原生mail()函数发送带纯文本、HTML及附件的邮件?
原生PHP mail()函数实现纯文本+HTML+附件的邮件发送
问题诊断
你的代码核心问题有两个:
- 纯文本的
Content-Type字符集参数错误:写成了charset="charset=UTF-8",多余的charset=会导致邮件客户端无法正确识别纯文本类型,进而错误显示HTML内容 - 换行符不统一:MIME协议要求所有头信息和内容分隔使用
\r\n,你代码中混用了\n和\r\n,破坏了MIME结构的解析规则
修正后的完整代码
$to = 'xyz@xyz.com'; $subject = 'my test subject'; $htmlMessage = 'this <i>is</i> html'; $plaintextMessage = 'this is plain text'; $attachments = [ [ 'path' => 'download/', 'file' => 'test1.pdf' ], [ 'path' => 'download/', 'file' => 'test2.pdf' ], ]; // 生成唯一的MIME边界符 $mimeBoundary = md5((string) time()); $mimeBoundaryMixed = $mimeBoundary . '_mixed'; $mimeBoundaryAlternative = $mimeBoundary . '_alternative'; // 构建邮件头,统一使用\r\n换行 $headers = "MIME-Version: 1.0\r\n"; $headers .= "Content-Type: multipart/mixed; boundary=\"$mimeBoundaryMixed\"\r\n"; $headers .= "Content-Transfer-Encoding: 7bit\r\n"; // 构建邮件主体 $body = "This is a multi-part message in MIME format.\r\n\r\n"; // 第一部分:替代内容(纯文本+HTML) $body .= "--$mimeBoundaryMixed\r\n"; $body .= "Content-Type: multipart/alternative; boundary=\"$mimeBoundaryAlternative\"\r\n\r\n"; // 纯文本版本 $body .= "--$mimeBoundaryAlternative\r\n"; $body .= "Content-Type: text/plain; charset=\"UTF-8\"\r\n"; $body .= "Content-Transfer-Encoding: 7bit\r\n\r\n"; $body .= $plaintextMessage . "\r\n\r\n"; // HTML版本 if (!empty($htmlMessage)) { $body .= "--$mimeBoundaryAlternative\r\n"; $body .= "Content-Type: text/html; charset=\"UTF-8\"\r\n"; $body .= "Content-Transfer-Encoding: 7bit\r\n\r\n"; $body .= $htmlMessage . "\r\n\r\n"; } // 结束替代内容边界 $body .= "--$mimeBoundaryAlternative--\r\n\r\n"; // 处理附件 if (!empty($attachments)) { foreach ($attachments as $attachment) { $filePath = $attachment['path'] . $attachment['file']; if (file_exists($filePath)) { $fileSize = filesize($filePath); $fileHandle = fopen($filePath, "rb"); $fileContent = fread($fileHandle, $fileSize); fclose($fileHandle); $fileContent = chunk_split(base64_encode($fileContent)); $body .= "--$mimeBoundaryMixed\r\n"; $body .= "Content-Type: application/octet-stream; name=\"{$attachment['file']}\"\r\n"; $body .= "Content-Transfer-Encoding: base64\r\n"; $body .= "Content-Disposition: attachment; filename=\"{$attachment['file']}\"\r\n\r\n"; $body .= $fileContent . "\r\n\r\n"; } } } // 结束外层MIME边界 $body .= "--$mimeBoundaryMixed--\r\n"; // 发送邮件 mail($to, $subject, $body, $headers);
核心原理说明
MIME层级结构
- 最外层使用
multipart/mixed:用于同时包含"替代内容"和"附件"两种不同用途的内容 - 内层嵌套
multipart/alternative:专门用于存放同一内容的不同格式版本(纯文本和HTML),邮件客户端会根据自身支持能力自动选择显示哪一个(支持HTML的客户端优先显示HTML,纯文本客户端显示纯文本)
- 最外层使用
边界符规则
- 每个MIME部分用唯一的边界符分隔,边界符前必须加
--,结束边界符需要在末尾再加-- - 边界符必须唯一,避免和邮件内容冲突,这里用
md5(time())生成唯一值
- 每个MIME部分用唯一的边界符分隔,边界符前必须加
编码与格式规范
- 所有头信息和内容之间必须用
\r\n\r\n分隔(空行) - 附件使用
base64编码,确保二进制文件能被正确传输 - 字符集统一设置为
UTF-8,避免中文等非ASCII字符乱码
- 所有头信息和内容之间必须用
内容的提问来源于stack exchange,提问作者Huberto
相关产品推荐
相关产品推荐

