PHP发送带附件邮件异常:附件显示为Base64格式的解决方法
问题原因分析
你遇到的问题核心是邮件的MIME结构没有正确配置——你的代码只对附件做了Base64编码,但没有告诉邮件客户端这是一个独立的附件,也没有将邮件声明为「多部分混合内容」(multipart/mixed),导致客户端把Base64编码后的内容当成了邮件文本的一部分直接显示。
修正方案
要解决这个问题,你需要完善邮件的MIME头结构,明确区分邮件正文和附件部分,具体步骤如下:
- 生成随机边界字符串:用来分隔邮件中的不同内容块(正文、附件),避免内容冲突。
- 更新邮件头:添加
Content-Type: multipart/mixed声明,并指定边界字符串。 - 构建完整的邮件内容:包含邮件正文(如果需要)和附件部分,每个部分都要用边界包裹,同时为附件设置正确的MIME属性。
修正后的完整代码
<?php $from = 'sender@example.com'; // 替换为你的发件人邮箱 $to = 'recipient@example.com'; // 替换为收件人邮箱 $subject = '带附件的测试邮件'; // 1. 生成随机边界字符串(用于分隔邮件内容块) $boundary = md5(uniqid(time())); // 2. 构建完整的邮件头 $headers = "From: $from\r\n"; $headers .= "Reply-To: $from\r\n"; $headers .= "MIME-Version: 1.0\r\n"; $headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n"; $headers .= "X-Mailer: PHP/" . phpversion() . "\r\n"; // 3. 读取附件内容(保留你原有的文件读取逻辑) $arquivo = $_FILES['your_file_input']; // 替换为你的文件上传字段名 $file = $arquivo['tmp_name']; $originalFile = $arquivo['name']; $file_size = filesize($file); $handle = fopen($file, "rb"); $anexo = fread($handle, $file_size); fclose($handle); $anexo = chunk_split(base64_encode($anexo)); // 4. 构建邮件内容主体 $message = "--$boundary\r\n"; // 邮件正文部分(不需要的话可以直接删除这段) $message .= "Content-Type: text/plain; charset=UTF-8\r\n"; $message .= "Content-Transfer-Encoding: 7bit\r\n\r\n"; $message .= "这是邮件的正文内容,请查收附件。\r\n\r\n"; // 附件核心部分(关键配置) $message .= "--$boundary\r\n"; $message .= "Content-Type: application/octet-stream; name=\"$originalFile\"\r\n"; $message .= "Content-Transfer-Encoding: base64\r\n"; $message .= "Content-Disposition: attachment; filename=\"$originalFile\"\r\n\r\n"; $message .= $anexo . "\r\n"; // 结束边界(注意末尾的两个连字符) $message .= "--$boundary--\r\n"; // 发送邮件 if (mail($to, $subject, $message, $headers)) { echo "邮件发送成功!"; } else { echo "邮件发送失败!"; } ?>
关键修改点说明
- MIME结构声明:新增的
MIME-Version: 1.0和Content-Type: multipart/mixed; boundary="...",是告诉邮件客户端「这是一个包含多种内容的邮件,用指定边界区分不同部分」。 - 附件的MIME属性:
Content-Type: application/octet-stream:表示这是二进制文件(如果知道具体文件类型,比如图片用image/jpeg、PDF用application/pdf,通用场景用octet-stream即可)。Content-Disposition: attachment; filename="...":明确告诉客户端这是一个附件,并指定显示的文件名。Content-Transfer-Encoding: base64:说明附件内容是Base64编码的,客户端会自动解码还原成正常文件。
- 边界字符串的正确使用:每个内容块前后都要用
--$boundary包裹,最后用--$boundary--结束整个邮件内容,这是MIME多部分邮件的规范要求。
额外注意事项
- 如果邮件主题包含中文,建议用
mb_encode_mimeheader()处理避免乱码:$subject = mb_encode_mimeheader('带附件的测试邮件', 'UTF-8', 'B'); - 部分服务器的
mail()函数可能依赖本地MTA配置,如果发送不稳定,推荐使用PHPMailer等第三方邮件库,配置更灵活且兼容性更好。
内容的提问来源于stack exchange,提问作者Débora Gonçalves
相关产品推荐
相关产品推荐

