PHPMailer发送邮件重复问题及批量发件安全浏览器咨询
邮件重复发送排查与批量发送方案建议
问题描述
我用PHPMailer编写的邮件脚本偶尔会出现重复发送的情况(并非每次都发生)。试过在无扩展的Chrome中运行,问题依旧。邮件主题包含随机数,可以确认是同一封邮件被多次送达。另外想咨询:有没有适合通过PHPMailer进行批量邮件发送的安全浏览器?
以下是我的脚本代码:
if(!isset($_SESSION[$reciever])) { $_SESSION[$reciever] = 1; require "mail_inhoud.php"; // <== IMPORTANT INCLUDE $maand = date('Ym'); // 202103 $datum = date('Ymd'); // '20210406' $datum_tijd = date('Ymd H:i'); // '20210406' $maand_ENG = 'March'; $teller = 1; $raw_results = mysql_query("SELECT EMAIL FROM EMAILS_TESTBANK") or die(mysql_error()); //Create a new PHPMailer instance $mail = new PHPMailer(); $mail->SMTPKeepAlive = true; // SMTP connection will not close after each email sent, reduces SMTP overhead $mail->CharSet = 'UTF-8'; //$mail->isSMTP(); $mail->Mailer = 'sendmail'; $mail->SMTPAuth = true; $mail->Host = 'xxxxxx'; $mail->Port = 587; $mail->Username = "xxxxx" ; $mail->Password = "xxxxxx"; $mail->SMTPSecure = "tls"; $mail->setFrom('lucas.tessens@mers.be', 'MERS Antique Books Antwerp'); $mail->Sender = 'bounced@mers.be'; $mail->addReplyTo('lucas.tessens@mers.be', 'MERS Antique Books Antwerp'); $mail->Subject = 'Test Mail ' . rand(); $ONDERWERP = "Catalogue for $maand_ENG"; $mail->Encoding = 'base64'; $today = date('Ymd'); if(mysql_num_rows($raw_results) > 0){ while($row = mysql_fetch_array($raw_results)){ $email = $row['EMAIL']; $email_user = $row['EMAIL']; /* We stellen de INHOUD OP */ $message = ""; $message .= "<html>"; $message .= "<body>"; $message .= "<table width='100%' border='0' cellspacing='0' cellpadding='0'>"; $message .= "<tr><td align='center' style='width:600px'>"; $htmlContent = file_get_contents("$maand/INTERNATIONAAL.html"); $message .= $htmlContent; $message .= "<br><br>"; $message .= "<div style='text-align:center'>"; $message .= "<span>This email was sent to $email</span> | <a href='https://www.mers.be/unsubscribe.php?EMAIL=$email' target='new' style='color:#666; text-decoration:none'>Unsubscribe</a>"; $message .= "<br><br>"; $message .= "<div style='visibility:hidden !important; opacity:0 !important; display:none !important' >"; $message .= "<img style='visibility:hidden !important' src='https://www.mers.be/backend/MAILING_NEW/mailcheck.php?user=$email&subject=$ONDERWERP'>"; $message .= "</div>"; $message .= "</div>"; $message .= "</td></tr>"; $message .= "</table>"; //$message .= $teller; $message .= "</body>"; $message .= "</html>"; $body = $message; $mail->msgHTML($body); $mail->AltBody = 'To view the message, please use an HTML compatible email viewer!'; $raw_check = mysql_query("SELECT EMAIL FROM EMA_CONTROLE WHERE EMAIL = '$email_user' AND DATE = '$today'") or die(mysql_error()); if(mysql_num_rows($raw_check) > 0){ // DO NOTHING, EMAIL WAS ALREADY SENT echo 'EMAIL ALREADY SENT<br>'; }else{ echo 'NOT YET SEND<br>'; $mail->addAddress($email, 'Receiver name'); $mail->send(); // SEND EMAIL $mail->clearAddresses(); $mail->clearAttachments(); echo 'Message sent to : (' . htmlspecialchars($row['EMAIL']) . ')<br>'; //Mark it as sent in the DB $OND = "NEW ARRIVALS MARCH DEEL 1"; mysql_query('SET NAMES UTF8'); mysql_query("INSERT INTO `MAILING_VERZONDEN` (`DATUM`, `EMAIL`, WELKE_MAILING, `TAAL`, `RECEIVER`) VALUES ('$datum_tijd', '$email','$OND', 'INTERNATIONAAL', 'KLANT' )") or die(mysql_error()); mysql_query("INSERT INTO `EMA_CONTROLE` ( `EMAIL`, `DATE`) VALUES ('$email','$today')") or die(mysql_error()); } echo $teller; echo '<br>'; $teller++; } } } else{ echo "doing it more than once"; } $conn = null; $con = null; exit;
问题排查与修复方案
1. 会话控制逻辑漏洞
你当前的会话判断$_SESSION[$reciever]存在问题:如果$reciever变量未定义,会变成$_SESSION[''],等于没有做有效拦截。用户刷新页面或重复请求时,这个判断会失效,导致脚本重复执行。
- 修复:给
$reciever设置固定唯一标识,确保会话变量有效:$reciever = 'mail_batch_send_lock'; if(!isset($_SESSION[$reciever])) { $_SESSION[$reciever] = 1; // 后续执行代码 } else { echo "脚本正在执行,请勿重复触发"; exit; }
2. 数据库操作的原子性问题
当前逻辑是先查询EMA_CONTROLE表,再发送邮件,最后插入记录——这个过程不是原子操作。如果脚本被重复触发,第二次请求可能在第一次插入记录前就通过了查询判断,导致重复发送。
- 修复:
- 给
EMA_CONTROLE表的EMAIL和DATE字段添加联合唯一索引,这样插入重复记录时会直接报错,从数据库层面阻止重复发送。 - 把发送邮件和插入数据库的操作放在事务中,确保要么全部成功,要么全部回滚。
- 给
3. PHPMailer配置冲突
你同时设置了$mail->Mailer = 'sendmail';和SMTP相关参数(SMTPAuth、Host等),这会导致配置混乱:sendmail模式不需要SMTP参数,SMTP模式需要启用$mail->isSMTP();。
- 修复:二选一调整配置:
- 用SMTP模式:注释掉
$mail->Mailer = 'sendmail';,打开$mail->isSMTP(); - 用sendmail模式:删除所有SMTP相关配置(
SMTPAuth、Host、Port、Username、Password、SMTPSecure)
- 用SMTP模式:注释掉
4. 脚本超时与重复触发
批量发送邮件耗时较长,容易触发浏览器超时,用户可能会刷新页面;或者PHP执行时间限制不足,导致脚本中断后被重新触发。
- 修复:
- 在脚本开头添加
set_time_limit(0);,取消执行时间限制(或设置足够大的数值) - 不要通过浏览器运行批量发送脚本,改用命令行执行(
php your_script.php),或者服务器定时任务(如Crontab),这是更稳定的方式
- 在脚本开头添加
关于批量发送的安全浏览器建议
批量发送邮件不建议通过浏览器运行,因为浏览器容易出现超时、重复请求的问题。如果一定要用,Chrome、Firefox、Edge等主流安全浏览器都可以,但要注意:
- 关闭浏览器的自动刷新、重试功能
- 脚本执行期间不要操作页面
- 优先选择命令行或服务器定时任务的方式,这才是批量发送邮件的安全稳定方案
内容的提问来源于stack exchange,提问作者Zaphod
相关产品推荐
相关产品推荐

