You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

找回密码OTP邮件发送报错求助:收件人邮箱未设置或为空

问题描述

开发支持邮箱获取OTP的找回密码表单时,出现报错:Message could not be sent. Mailer Error: Recipient email address is not set or empty。需求为用户提交表单后,填写的邮箱能收到包含OTP及跳转至OTP验证页面链接的邮件。

错误原因分析

  1. 页面逻辑冲突:原代码将PHP邮件发送逻辑与HTML表单放在同一文件,页面加载时PHP代码就会执行,此时未提交表单,$_POST['email']为空,触发收件人不存在的异常。
  2. 表单提交目标混乱:HTML表单action指向otp-confirmation.php,但AJAX请求目标是当前文件,导致流程错位。
  3. 邮件配置缺失:未设置发件人信息,部分SMTP服务器会拒绝发送;邮件仅包含OTP,未添加验证页面跳转链接。
  4. 流程设计不合理:找回密码流程应分“提交邮箱→发送OTP→验证OTP并重置密码”三步,原表单同时包含邮箱和新密码字段,逻辑混乱。

修复方案

1. 拆分页面职责

将流程拆分为三个独立页面,明确各页面功能:

  • forgot-password.php:展示邮箱输入表单,提交后触发AJAX请求发送OTP。
  • send-otp.php:处理AJAX请求,生成OTP并发送邮件,返回JSON格式结果。
  • otp-confirmation.php:展示OTP验证表单,验证通过后允许用户重置密码。

2. 修正PHPMailer配置

  • 添加发件人信息(setFrom),确保SMTP服务器认可。
  • 改为HTML格式邮件,插入验证页面跳转链接。
  • 仅在AJAX请求触发时执行邮件发送逻辑,避免页面加载时误触发。

3. 完善会话与安全机制

  • 存储收件邮箱和OTP到会话,用于后续验证。
  • 给OTP设置5分钟过期时间,提升安全性。

完整修复代码

1. forgot-password.php(邮箱提交页面)

<?php session_start(); ?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>重置密码 - Obaju</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="card mt-5">
                <div class="card-header">重置密码</div>
                <div class="card-body">
                    <form id="forgot-password-form">
                        <div class="form-group">
                            <label for="email">邮箱地址</label>
                            <input type="email" class="form-control" id="email" name="email" required>
                        </div>
                        <button type="submit" class="btn btn-primary">发送验证码</button>
                    </form>
                    <div id="message" class="mt-3"></div>
                </div>
            </div>
        </div>
    </div>
</div>
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<script>
$(document).ready(function(){
    $("#forgot-password-form").submit(function(event){
        event.preventDefault();
        var formData = $(this).serialize();
        $.ajax({
            url: "send-otp.php",
            type: "POST",
            data: formData,
            success: function(response){
                var res = JSON.parse(response);
                if(res.status === "success"){
                    $("#message").html('<div class="alert alert-success">验证码已发送至您的邮箱,请查收</div>');
                    setTimeout(function(){
                        window.location.href = "otp-confirmation.php?email=" + res.email;
                    }, 2000);
                } else {
                    $("#message").html('<div class="alert alert-danger">' + res.message + '</div>');
                }
            },
            error: function(){
                $("#message").html('<div class="alert alert-danger">请求失败,请稍后重试</div>');
            }
        });
    });
});
</script>
</body>
</html>

2. send-otp.php(OTP发送处理)

<?php
session_start();

$phpMailerDir = 'C:\wamp64\www\obaju\distribution\sendEmails\vendor\phpmailer\phpmailer';
require_once $phpMailerDir . '\src\PHPMailer.php';
require_once $phpMailerDir . '\src\SMTP.php';
require_once $phpMailerDir . '\src\Exception.php';

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

header('Content-Type: application/json');

$response = ['status' => 'error', 'message' => '未知错误'];

if(isset($_POST['email']) && !empty($_POST['email'])){
    $recipient_email = trim($_POST['email']);
    $_SESSION['reset_email'] = $recipient_email;

    try {
        $mail = new PHPMailer(true);

        // SMTP服务器配置
        $mail->isSMTP();
        $mail->Host = 'smtp-mail.outlook.com';
        $mail->SMTPAuth = true;
        $mail->Username = "gcira2023@outlook.com";
        $mail->Password = "***"; // 替换为实际SMTP密码
        $mail->SMTPSecure = 'tls';
        $mail->Port = 587;

        // 发件人设置
        $mail->setFrom('gcira2023@outlook.com', 'Obaju商城');
        $mail->addAddress($recipient_email);

        // 生成OTP并存储会话
        $otp = rand(100000, 999999);
        $_SESSION['otp'] = $otp;
        $_SESSION['otp_expire'] = time() + 300; // 5分钟过期

        // 构建验证链接
        $verify_link = "http://" . $_SERVER['HTTP_HOST'] . "/obaju/distribution/otp-confirmation.php?email=" . urlencode($recipient_email);
        
        // HTML格式邮件内容
        $mail->isHTML(true);
        $mail->Subject = 'Obaju商城密码重置验证码';
        $mail->Body = <<<HTML
<p>您好,您正在申请重置Obaju商城账号密码,请使用以下验证码完成验证:</p>
<p><strong>$otp</strong></p>
<p>或者点击下方链接直接跳转至验证页面:</p>
<p><a href="$verify_link">点击验证</a></p>
<p>验证码5分钟内有效,如非本人操作请忽略此邮件。</p>
HTML;

        $mail->send();
        $response = ['status' => 'success', 'message' => '邮件发送成功', 'email' => $recipient_email];
    } catch (Exception $e) {
        $response['message'] = '邮件发送失败:' . $e->getMessage();
    }
} else {
    $response['message'] = '请填写有效的邮箱地址';
}

echo json_encode($response);
?>

3. otp-confirmation.php(OTP验证及密码重置页面)

<?php
session_start();

// 检查会话有效性
if(!isset($_SESSION['reset_email']) || !isset($_SESSION['otp']) || $_SESSION['otp_expire'] < time()){
    header('Location: forgot-password.php');
    exit;
}

$email = $_SESSION['reset_email'];
$error = '';

if($_SERVER['REQUEST_METHOD'] === 'POST'){
    $user_otp = trim($_POST['otp']);
    $new_password = trim($_POST['new-password']);
    $confirm_password = trim($_POST['confirm-password']);

    if($user_otp == $_SESSION['otp']){
        if($new_password === $confirm_password && strlen($new_password) >= 6){
            // 此处添加更新数据库密码的逻辑
            // 示例:update users set password = password_hash($new_password, PASSWORD_DEFAULT) where email = '$email'

            // 重置会话
            unset($_SESSION['otp'], $_SESSION['otp_expire'], $_SESSION['reset_email']);
            header('Location: dashboard.php');
            exit;
        } else {
            $error = '两次输入的密码不一致或长度不足6位';
        }
    } else {
        $error = '验证码错误';
    }
}
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>验证验证码 - Obaju</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="card mt-5">
                <div class="card-header">验证验证码</div>
                <div class="card-body">
                    <?php if($error): ?>
                        <div class="alert alert-danger"><?php echo $error; ?></div>
                    <?php endif; ?>
                    <form method="post">
                        <div class="form-group">
                            <label for="otp">验证码</label>
                            <input type="text" class="form-control" id="otp" name="otp" required maxlength="6">
                        </div>
                        <div class="form-group">
                            <label for="new-password">新密码</label>
                            <input type="password" class="form-control" id="new-password" name="new-password" required minlength="6">
                        </div>
                        <div class="form-group">
                            <label for="confirm-password">确认密码</label>
                            <input type="password" class="form-control" id="confirm-password" name="confirm-password" required minlength="6">
                        </div>
                        <button type="submit" class="btn btn-primary">重置密码</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
</body>
</html>

内容的提问来源于stack exchange,提问作者The01800

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 16:37:00