
本文详解如何将 bootstrap 联系表单的用户输入(姓名、邮箱、电话等字段)通过 phpmailer 安全、完整地提交至指定邮箱,并支持发送成功/失败的前端提示,避免常见 `msghtml()` 误用导致内容丢失的问题。
在使用 PHPMailer 处理联系表单时,一个常见误区是多次调用 $mail->MsgHTML()(如分别传入 $_POST['name']、$_POST['message'] 等),这会导致只有最后一次调用的内容生效——因为 MsgHTML() 是整体设置 HTML 邮件正文的方法,而非追加内容。正确做法是先构建完整的邮件正文(文本或 HTML),再一次性赋值给 $mail->Body 或 $mail->msgHTML()。
✅ 正确构建邮件正文(推荐 HTML 模板方式)
为提升可读性与专业性,建议使用结构化 HTML 邮件体。以下是一个安全、清晰的实现方案:
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require "../PHPMailer-master/src/PHPMailer.php";
require "../PHPMailer-master/src/SMTP.php";
require "../PHPMailer-master/src/Exception.php";
// 数据清洗(防止 XSS 和基础注入)
function sanitize($input) {
return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
}
$name = sanitize($_POST['name'] ?? '');
$prenom = sanitize($_POST['prenom'] ?? '');
$email = sanitize($_POST['email'] ?? '');
$phone = sanitize($_POST['subject'] ?? ''); // 注意:HTML 中 name="subject" 对应电话字段
$from = sanitize($_POST['input_from'] ?? '');
$to = sanitize($_POST['input_to'] ?? '');
$message = nl2br(sanitize($_POST['message'] ?? '')); // 保留换行
// 构建 HTML 邮件正文
$htmlBody = <<<EOT
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<body>
<h3>Nouveau message depuis le formulaire de contact</h3>
<table border="1" style="border-collapse: collapse; width: 100%;">
<tr><td><strong>Nom</strong></td><td>$name</td></tr>
<tr><td><strong>Prénom</strong></td><td>$prenom</td></tr>
<tr><td><strong>Email</strong></td><td><a href="mailto:$email">$email</a></td></tr>
<tr><td><strong>Téléphone</strong></td><td>$phone</td></tr>
<tr><td><strong>Période (du)</strong></td><td>$from</td></tr>
<tr><td><strong>au</strong></td><td>$to</td></tr>
<tr><td><strong>Message</strong></td><td>$message</td></tr>
</table>
<p><em>Ce message a été envoyé le : {date('d/m/Y H:i', time())}</em></p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill12720" title="Word文档工具V102(免费版)"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20d3191a227.jpg" alt="Word文档工具V102(免费版)" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill12720" title="Word文档工具V102(免费版)">Word文档工具V102(免费版)</a>
<p>Word文档处理增强版本,支持高级格式化、样式管理、修订追踪与协同编辑。</p>
</div>
<a href="/xiazai/skill12720" title="Word文档工具V102(免费版)" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div>
</body>
</html>
EOT;
$mail = new PHPMailer(true); // 启用异常模式更利于调试
$mail->isSMTP();
$mail->SMTPAuth = true;
$mail->SMTPOptions = [
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
]
];
$mail->Host = "mail.xxxx.com";
$mail->Port = 587;
$mail->Username = "your_username@example.com";
$mail->Password = "your_app_password"; // 强烈建议使用应用专用密码
$mail->setFrom("contact@votresite.com", "Formulaire de contact");
$mail->addAddress("destinataire@exemple.com"); // 收件人
$mail->addReplyTo($email, "$name $prenom"); // 自动设置回复地址
$mail->isHTML(true);
$mail->Subject = "? Nouveau message — $name $prenom";
$mail->Body = $htmlBody;
$mail->AltBody = "Nom: $name\nPrénom: $prenom\nEmail: $email\nTéléphone: $phone\nDu: $from\nAu: $to\nMessage: " . strip_tags($message);
// 发送并返回 JSON 响应(适配前端 AJAX)
try {
$mail->send();
echo json_encode(['status' => 'success', 'message' => 'Votre message a été envoyé. Merci !']);
} catch (Exception $e) {
error_log("PHPMailer Error: " . $e->getMessage());
echo json_encode(['status' => 'error', 'message' => 'Erreur d\'envoi : ' . $mail->ErrorInfo]);
}? 前端反馈集成(AJAX + Bootstrap 表单)
原 HTML 使用了 class="php-email-form" 和预设的 .sent-message / .error-message 元素,建议改用 AJAX 提交,避免页面跳转,同时精准控制提示显示:
立即学习“PHP免费学习笔记(深入)”;
<form id="contactForm" role="form" class="php-email-form">
<!-- 所有 input 和 textarea 保持不变 -->
<div class="my-3">
<div class="loading" style="display:none;">Envoi en cours…</div>
<div class="error-message" style="display:none;"></div>
<div class="sent-message" style="display:none;"></div>
</div>
<div class="text-center"><button type="submit">Envoyer</button></div>
</form>
<script>
document.getElementById('contactForm').addEventListener('submit', async function(e) {
e.preventDefault();
const form = e.target;
const btn = form.querySelector('button[type="submit"]');
const loading = form.querySelector('.loading');
const errorMsg = form.querySelector('.error-message');
const successMsg = form.querySelector('.sent-message');
loading.style.display = 'block';
errorMsg.style.display = 'none';
successMsg.style.display = 'none';
try {
const response = await fetch('contact-2.php', {
method: 'POST',
body: new FormData(form)
});
const result = await response.json();
loading.style.display = 'none';
if (result.status === 'success') {
successMsg.textContent = result.message;
successMsg.style.display = 'block';
form.reset();
} else {
errorMsg.textContent = result.message;
errorMsg.style.display = 'block';
}
} catch (err) {
loading.style.display = 'none';
errorMsg.textContent = 'Une erreur réseau est survenue.';
errorMsg.style.display = 'block';
}
});
</script>⚠️ 关键注意事项
- 字段名一致性:HTML 中 实际代表电话,但语义上易混淆,建议改为 并同步更新 PHP 中的 $_POST['phone']。
- 安全性强化:始终对 $_POST 数据进行 htmlspecialchars() 和 trim() 处理;敏感操作(如发信)建议添加 CSRF Token 验证。
- 错误日志:生产环境务必记录 $mail->ErrorInfo 到服务器日志(如 error_log()),而非直接输出给用户。
- SMTP 凭据保护:切勿在代码中硬编码密码;应使用环境变量或配置文件(.env + vlucas/phpdotenv)管理。
- 响应格式统一:后端返回 JSON,前端统一解析,便于扩展(如国际化、埋点统计)。
通过以上重构,你的联系表单不仅能准确传递全部 7 个字段(name、prenom、email、subject/phone、input_from、input_to、message),还能提供即时、友好、可控的用户反馈,符合现代 Web 表单最佳实践。


















