PHP管道邮件转发故障:含MIME头、原正文转为HTML附件求助
管道邮件转发PHP脚本问题修复
存在的问题
- 转发后的邮件正文中包含原邮件的MIME头信息
- 原邮件的正文文本被转为HTML附件,未显示在转发邮件的正文中
问题原因
- 直接将完整的原邮件内容(包含MIME头和编码后的正文/附件)拼接到转发邮件的正文里,导致MIME头被当成普通文本显示
- 未正确提取原邮件的正文内容,仅处理了附件部分,原正文未被单独提取并整合到转发邮件的正文区域
修复后的代码
#!/usr/bin/php -q <?php // 读取STDIN中的邮件内容 $fd = fopen("php://stdin", "r"); $email_content = stream_get_contents($fd); fclose($fd); // 分割邮件头和邮件体(头和体之间是\r\n\r\n) list($email_headers, $email_body) = explode("\r\n\r\n", $email_content, 2); // 提取原邮件主题 preg_match('/^Subject: (.+)$/m', $email_headers, $matches); $subject = isset($matches[1]) ? $matches[1] : '转发邮件'; // 目标邮箱 $to_email = "example@example.com"; // 生成新的MIME边界(避免和原邮件边界冲突) $new_boundary = '----ForwardBoundary_' . md5(time()); // 解析原邮件的正文内容 $original_body = ''; // 匹配text/plain类型的正文 if (preg_match('/Content-Type: text\/plain;.*?\r\n\r\n(.+?)\r\n--/sm', $email_body, $text_matches)) { // 检查编码并解码 if (preg_match('/Content-Transfer-Encoding: (base64|quoted-printable)/i', $email_body, $encoding_match)) { switch(strtolower($encoding_match[1])) { case 'base64': $original_body = base64_decode($text_matches[1]); break; case 'quoted-printable': $original_body = quoted_printable_decode($text_matches[1]); break; default: $original_body = $text_matches[1]; } } else { $original_body = $text_matches[1]; } } // 如果没有纯文本正文,尝试提取HTML正文 elseif (preg_match('/Content-Type: text\/html;.*?\r\n\r\n(.+?)\r\n--/sm', $email_body, $html_matches)) { if (preg_match('/Content-Transfer-Encoding: (base64|quoted-printable)/i', $email_body, $encoding_match)) { switch(strtolower($encoding_match[1])) { case 'base64': $original_body = base64_decode($html_matches[1]); break; case 'quoted-printable': $original_body = quoted_printable_decode($html_matches[1]); break; default: $original_body = $html_matches[1]; } } else { $original_body = $html_matches[1]; } } // 构建转发邮件的正文内容 $forward_message = "此邮件由PHP脚本转发。\n\n原邮件内容:\n\n{$original_body}"; // 解析原邮件的附件 $attachments = []; // 匹配附件部分 preg_match_all('/Content-Disposition: attachment; filename="(.+)"\s*Content-Type: (.+);\s*name=".+"\s*Content-Transfer-Encoding: (base64|quoted-printable|7bit|8bit|binary)\s*\r\n\r\n(.+?)\r\n--/sm', $email_body, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $attachment_data = $match[4]; switch(strtolower($match[3])) { case 'base64': $attachment_data = base64_decode($attachment_data); break; case 'quoted-printable': $attachment_data = quoted_printable_decode($attachment_data); break; } $attachments[] = [ 'name' => $match[1], 'type' => $match[2], 'data' => $attachment_data ]; } // 构建带附件的多部分邮件内容 $multipart_content = ''; // 添加转发邮件的正文部分 $multipart_content .= "--{$new_boundary}\r\n"; $multipart_content .= "Content-Type: text/plain; charset=UTF-8\r\n"; $multipart_content .= "Content-Transfer-Encoding: 8bit\r\n\r\n"; $multipart_content .= "{$forward_message}\r\n"; // 添加附件部分 foreach ($attachments as $attachment) { $multipart_content .= "--{$new_boundary}\r\n"; $multipart_content .= "Content-Type: {$attachment['type']}; name=\"{$attachment['name']}\"\r\n"; $multipart_content .= "Content-Disposition: attachment; filename=\"{$attachment['name']}\"\r\n"; $multipart_content .= "Content-Transfer-Encoding: base64\r\n\r\n"; $multipart_content .= chunk_split(base64_encode($attachment['data'])); } // 结束边界 $multipart_content .= "--{$new_boundary}--\r\n"; // 设置邮件头 $headers = "From: example@example.com\r\n"; $headers .= "Reply-To: example@example.com\r\n"; $headers .= "X-Mailer: PHP/" . phpversion() . "\r\n"; $headers .= "MIME-Version: 1.0\r\n"; $headers .= "Content-Type: multipart/mixed; boundary=\"{$new_boundary}\"\r\n"; // 发送邮件 mail($to_email, $subject, $multipart_content, $headers, "-fexample@example.com"); exit; ?>
修复说明
- 分离邮件头和体:通过
\r\n\r\n分割原邮件的头和体,避免将头信息混入正文 - 提取原邮件正文:分别匹配纯文本和HTML类型的正文内容,根据编码格式解码后整合到转发邮件的正文中
- 自定义MIME边界:生成新的边界字符串,避免和原邮件的边界冲突,防止邮件解析混乱
- 重构邮件内容结构:先添加转发提示和原正文,再添加附件,确保正文正常显示,附件也能正确识别
内容的提问来源于stack exchange,提问作者uk_nick
相关产品推荐
相关产品推荐

