PHP联系表单仅支持部分邮箱提交,请求故障排查
由于我的标准表单无法在客户网站运行,因此改用了客户的联系表单邮箱。目前客户仅能收到部分提交(比如我的测试提交和一条随机提交),但使用个人邮箱或客户自身邮箱提交时,完全收不到表单邮件。我曾尝试修改From头信息,但直接导致所有提交失败。请问这段代码存在什么问题?
PHP脚本(mail.php)
function stripFormSlashes($arr) { if(!is_array($arr)) { return stripslashes($arr); } else { return array_map('stripFormSlashes', $arr); } } if(get_magic_quotes_gpc()) { $_POST = stripFormSlashes($_POST); } $message = ""; $message .= "First Name: " . htmlspecialchars($_POST['first_name'], ENT_QUOTES) . "<br />\n"; $message .= "Last Name: " . htmlspecialchars($_POST['last_name'], ENT_QUOTES) . "<br />\n"; $message .= "Email: " . htmlspecialchars($_POST['email'], ENT_QUOTES) . "<br />\n"; $message .= "Phone: " . htmlspecialchars($_POST['telephone'], ENT_QUOTES) . "<br />\n"; $message .= "Company: " . htmlspecialchars($_POST['company'], ENT_QUOTES) . "<br />\n"; $message .= "Comments: " . htmlspecialchars($_POST['message'], ENT_QUOTES) . "<br />\n"; $lowmsg = strtolower($message); $injection_strings = array ("content-type:","charset=","mime-version:","multipart/mixed","bcc:","cc:"); foreach($injection_strings as $suspect) { if((stristr($lowmsg, $suspect)) || (stristr(strtolower($_POST['first_name']), $suspect)) || (stristr(strtolower($_POST['email']), $suspect))) { die ( 'Illegal Input. Go back and try again. Your message has not been sent.' ); } } $headers = "MIME-Version: 1.0\r\nContent-type: text/html; charset=utf-8\r\n"; $headers .= "Content-Transfer-Encoding: 8bit\r\n"; $headers .= "From: \"" . $_POST['first_name'] . " " . $_POST['last_name'] . "\" <" . $_POST['email'] . ">\r\n"; $headers .= "Reply-To: " . $_POST['email'] . "\r\n"; mail("emailtosendto@customdomain.com", "Contact Form Submission", $message, $headers); header("Location: ../thank_you.html"); ?>
表单模态框代码
<div class="modal fade" id="contactForm" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="contactFormLabel" aria-hidden="true" > <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header border-0" style="background-color: var(--tp-theme-main-bg)" > <h2 class="modal-title fs-5" id="ContactFormLabel" style="font-size: 36px !important" > Contact Me! </h2> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" ></button> </div> <div class="modal-body form-group col-12 px-5"> <p> contact text </p> <form action="./assets/mail.php" method="POST" id="contactForm" > <div class="row g-3"> <div class="col-md-6"> <div class="input-item"> <input type="text" name="first_name" placeholder="First Name" required /> </div> </div> <div class="col-md-6"> <div class="input-item"> <input type="text" name="last_name" placeholder="Last Name" required /> </div> </div> <div class="col-lg-12"> <div class="input-item"> <input type="text" name="company" placeholder="Company Name" /> </div> </div> <div class="col-md-6"> <div class="input-item"> <input type="text" name="email" placeholder="Email Address" required /> </div> </div> <div class="col-md-6"> <div class="input-item"> <input type="tel" name="telephone" placeholder="(555) 123-4567" /> </div> </div> <div class="col-12"> <div class="input-item-textarea"> <textarea name="message" placeholder="Let us know what you're looking for" required ></textarea> </div> </div> </div> <div class="modal-footer border-0 me-auto flex-row-reverse flex-md-row"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal" > Close </button> <button type="submit" name="submit" class="btn btn-primary" style="position: relative" > Submit </button> </div> </form> </div> </div> </div> </div>
核心问题分析
发件人身份验证失败(SPF/DKIM拦截)
当前代码直接将用户提交的邮箱作为From头发件人地址:$headers .= "From: \"" . $_POST['first_name'] . " " . $_POST['last_name'] . "\" <" . $_POST['email'] . ">\r\n";主流邮件服务商都会通过SPF/DKIM验证发件人身份,如果服务器未被授权发送用户提交域名的邮件,邮件会被判定为伪造,直接被拦截或扔进垃圾箱。测试提交可能用了服务器允许的域名(比如客户自身域名),所以能正常送达,外部邮箱则会被拦截。
头信息拼接存在安全风险与格式错误
直接拼接用户输入的姓名、邮箱到邮件头,未过滤换行符、引号等特殊字符,可能导致邮件头格式混乱,甚至触发邮件注入攻击。当前的注入检测仅覆盖特定字符串,防护不全面。无错误处理与日志记录
调用mail()后未检查返回值,也没有错误日志,无法定位发送失败的具体原因(比如服务器配置问题、DNS解析失败等)。原生mail()函数局限性
PHP原生mail()依赖服务器sendmail/SMTP配置,配置不当易被垃圾邮件系统标记,且对现代邮件验证机制支持不足。
修复方案
1. 修正发件人头信息
用服务器授权的邮箱(比如客户域名下的noreply邮箱)作为From头,保留Reply-To为用户邮箱,既符合验证规则,又不影响回复:
// 过滤姓名中的特殊字符,防止头注入 $safe_first_name = preg_replace('/[\r\n\t"]/', '', $_POST['first_name']); $safe_last_name = preg_replace('/[\r\n\t"]/', '', $_POST['last_name']); $safe_name = $safe_first_name . " " . $safe_last_name; // 验证邮箱格式 $safe_email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL); if (!$safe_email) { die('请输入有效的邮箱地址。'); } $headers .= "From: \"Contact Form\" <noreply@customdomain.com>\r\n"; $headers .= "Reply-To: \"" . $safe_name . "\" <" . $safe_email . ">\r\n";
2. 加强输入验证
替换现有注入检测,全面过滤换行符,同时验证邮箱格式:
// 检查所有输入是否包含换行符,防止头注入 foreach ($_POST as $value) { if (preg_match('/[\r\n]/', $value)) { die('非法输入,请返回重试。'); } } // 验证邮箱格式 if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) { die('请输入有效的邮箱地址。'); }
3. 添加错误处理与日志
检查mail()返回值,记录错误日志:
$mail_sent = mail("emailtosendto@customdomain.com", "Contact Form Submission", $message, $headers); if (!$mail_sent) { error_log("表单邮件发送失败: " . date('Y-m-d H:i:s') . " | 提交邮箱: " . $_POST['email']); die('邮件发送失败,请稍后重试或联系管理员。'); } header("Location: ../thank_you.html"); exit;
4. 改用专业邮件库(推荐)
放弃原生mail(),使用PHPMailer/SwiftMailer支持SMTP协议,提升送达率:
require 'PHPMailer/PHPMailer.php'; require 'PHPMailer/SMTP.php'; $mail = new PHPMailer\PHPMailer\PHPMailer(); $mail->isSMTP(); $mail->Host = 'smtp.customdomain.com'; $mail->SMTPAuth = true; $mail->Username = 'noreply@customdomain.com'; $mail->Password = 'your_auth_password'; $mail->SMTPSecure = 'tls'; $mail->Port = 587; $mail->setFrom('noreply@customdomain.com', 'Contact Form'); $mail->addAddress('emailtosendto@customdomain.com'); $mail->addReplyTo($_POST['email'], $_POST['first_name'] . " " . $_POST['last_name']); $mail->isHTML(true); $mail->Subject = 'Contact Form Submission'; $mail->Body = $message; if (!$mail->send()) { error_log("PHPMailer发送失败: " . $mail->ErrorInfo); die('邮件发送失败,请稍后重试。'); } else { header("Location: ../thank_you.html"); exit; }
内容的提问来源于stack exchange,提问作者Randy Christenhusz

