使用PHP mail()发送带.docx附件失败,请求代码排查及修改建议
解决PHP mail()发送docx附件失败的问题
从你的代码来看,主要问题出在文件上传验证缺失和MIME邮件结构错误上,以下是具体的修正方案:
第一步:修正mail.php的核心问题
修正后的完整mail.php代码
<?php if (isset($_POST['submit'])) { $mailto = "to@gmail.com"; $from_mail = $_POST["fromEmail"]; $replyto = $_POST["fromEmail"]; $from_name = $_POST["fromName"]; $message = "This is message part"; $subject = "this is subject part"; // 1. 首先处理文件上传验证 $fileError = $_FILES["fileAttach"]["error"]; if ($fileError !== UPLOAD_ERR_OK) { $errorMsg = match($fileError) { UPLOAD_ERR_INI_SIZE => "上传文件超过php.ini限制", UPLOAD_ERR_FORM_SIZE => "上传文件超过表单限制", UPLOAD_ERR_PARTIAL => "文件仅部分上传", UPLOAD_ERR_NO_FILE => "未选择上传文件", UPLOAD_ERR_NO_TMP_DIR => "服务器缺少临时目录", UPLOAD_ERR_CANT_WRITE => "文件写入失败", UPLOAD_ERR_EXTENSION => "PHP扩展阻止了文件上传", default => "未知上传错误" }; echo "<script>alert('上传失败:{$errorMsg}');</script>"; exit; } // 2. 验证文件类型为docx $allowedMime = ["application/vnd.openxmlformats-officedocument.wordprocessingml.document"]; $fileMime = mime_content_type($_FILES["fileAttach"]["tmp_name"]); if (!in_array($fileMime, $allowedMime)) { echo "<script>alert('仅允许上传docx格式文件');</script>"; exit; } // 3. 处理文件信息 $filename = basename($_FILES["fileAttach"]["name"]); $content = chunk_split(base64_encode(file_get_contents($_FILES["fileAttach"]["tmp_name"]))); $uid = md5(uniqid(time())); // 4. 构建邮件头(仅包含基础头信息) $header = "From: " . $from_name . " <" . $from_mail . ">\r\n"; $header .= "Reply-To: " . $replyto . "\r\n"; $header .= "MIME-Version: 1.0\r\n"; $header .= "Content-Type: multipart/mixed; boundary=\"" . $uid . "\"\r\n"; // 5. 构建邮件主体内容(包含正文和附件) $body = "This is a multi-part message in MIME format.\r\n"; $body .= "--" . $uid . "\r\n"; $body .= "Content-type:text/html; charset=utf-8\r\n"; $body .= "Content-Transfer-Encoding: 7bit\r\n\r\n"; $body .= "<div style='color: red'>" . $message . "</div>\r\n\r\n"; $body .= "--" . $uid . "\r\n"; $body .= "Content-Type: {$fileMime}; name=\"" . $filename . "\"\r\n"; $body .= "Content-Transfer-Encoding: base64\r\n"; $body .= "Content-Disposition: attachment; filename=\"" . $filename . "\"\r\n\r\n"; $body .= $content . "\r\n\r\n"; $body .= "--" . $uid . "--"; // 6. 发送邮件:第三个参数是完整的邮件主体,第四个是头信息 if (mail($mailto, $subject, $body, $header)) { echo "<script>alert('Success');</script>"; } else { echo "<script>alert('Failed');</script>"; // 调试时可以开启错误提示:error_reporting(E_ALL); ini_set('display_errors', 1); } } ?>
关键修改点说明
增加文件上传完整验证
- 检查
$_FILES["fileAttach"]["error"],确保文件成功上传,避免因上传失败导致后续代码报错 - 验证文件MIME类型为docx的标准类型,防止非目标文件引发问题
- 检查
修复MIME邮件结构
- 原来的代码错误地将所有MIME内容放到了邮件头(
$header)中,现在将正文和附件内容移到邮件主体($body)里,mail()函数的第三个参数传递完整的MIME主体,第四个参数传递基础头信息,这是符合邮件协议的正确写法
- 原来的代码错误地将所有MIME内容放到了邮件头(
移除无效代码
- 删除了未定义变量
$name = basename($file);,避免PHP警告干扰邮件发送
- 删除了未定义变量
规范附件MIME类型
- 使用docx的官方MIME类型
application/vnd.openxmlformats-officedocument.wordprocessingml.document,替代通用的application/octet-stream,提升邮件客户端的兼容性
- 使用docx的官方MIME类型
额外建议
- 在index.html中给表单字段增加
required属性,确保用户填写必要信息:<input type="text" name="fromName" required> <input type="email" name="fromEmail" required> <input type="file" name="fileAttach" required accept=".docx"> - 调试时可以开启PHP错误提示,更容易排查问题:在mail.php开头添加
error_reporting(E_ALL); ini_set('display_errors', 1);
内容的提问来源于stack exchange,提问作者Ramlal S
相关产品推荐
相关产品推荐

