PHPMailer 和 Google SMTP 中继。收件人收到其他客户电子邮件的过多重复电子邮件
PHPMailer and Google SMTP-Relay. Excess duplicate email with receiver receiving other customer email
我创建了一个脚本,可以将一些跟踪详细信息通过电子邮件发送给每个已发货的客户订单。
该脚本是用 PHPMailer 构建的,并通过 Google SMTP 中继服务发送电子邮件。
在测试期间,一切都按预期工作。使用 100 封电子邮件进行负载测试,尽管发送到相同的电子邮件地址,但均按预期执行。没有重复或丢失的电子邮件。
然而在上线后不久,我被告知有几个客户收到了数十封电子邮件,其中包含其他客户的跟踪详细信息。
对于 gmail 用户,他们会收到其他客户的跟踪电子邮件,并将其电子邮件地址作为收件人。
使用 outlook 用户,他们会收到其他客户的电子邮件,并且在发送区域中有很多电子邮件。
我查看了代码,测试并检查了每个函数的输出,完全迷失在可能出错的地方。
下面是脚本的sudo过程。想看看是否有人可以提供一些关于如何解决此问题的提示。
- 将电子邮件列表检索到一维数组中。
- 创建 PHPMailer 实例
- 对于数组中的每封邮件,发送邮件,等待TRUE响应,如果为FALSE,等待5s,重试共3次,如果超过CONTINUE。
- 完成后,脚本结束。
其他说明
该脚本由 windows 任务调度程序触发。
脚本将花费大约 2-10 分钟到 运行,具体取决于重试次数,尽管调度程序设置为每 5 分钟 运行,但调度程序中的任务未设置为运行 任务的多个实例,如果存在 运行ning。
任何建议都很好。
干杯
代码片段。希望能提供足够的思路。
一般过程是脚本从 Dispatcher_cl.php 调用 sendTrackingEmails(),然后使用 MyCustomerMailer.php 的不同函数。 MyCustomerMailer.php 或多或少是 PHPMailer 的抽象层。
Dispatcher_cl.php
public function sendTrackingEmails() {
try{
$this->processLog[] = __FUNCTION__;
/*
1.Get list of emails
2.Loop and send emails
*/
$ordersSent = array();
$ordersFailed = array();
$result = false;
$emailListAndInfo = $this->getEmailListAndInfo();
if($emailListAndInfo===false){
//No orders to dispatch emails. So do nothing.
$result = false;
}else{
$mail = new MyCustomMailer_cl();
if($mail->setSMTPParam('default')===true){
foreach($emailListAndInfo as $customer){
$sentFrom = array();
$replyTo = array();
$emailTo = array($customer['email'],$customer['name']);
$subject = array();
$body = null;
/*
Preset email settings for each brand.
When adding vendors, remember to add a BODY template and VENDOR ID to the SQL in [m_getEmailListAndInfo]
*/
if($customer['vendor_id']==3){
//Diamondphoto
$sentFrom = array('no-reply@email.com','Your order has been shipped');
$replyTo = array('no-reply@email.com','Your order has been shipped');
$subject = "Tracking for order {$customer['vendorOrderId']}";
$body = $this->getEmailTemplateFor(3,$customer);
}else{
/*
If vendor_id does not match existing setup, set TRYCOUNT to 99 as indicator and skip remaining execution.
Next script-run will not pick up this record due to 99 will be greater than the usual preset TRYCOUNT.
*/
$this->setTryCountForOrder($customer['order_id'],99);
continue;
}
$emailPackage['sentFrom'] = $sentFrom;
$emailPackage['replyTo'] = $replyTo;
$emailPackage['emailTo'] = $emailTo;
$emailPackage['subject'] = $subject;
$emailPackage['body'] = $body;
$mail->setupEmail($emailPackage);
for($i=1;$i<=$this->emailTryCount;$i++){
// $emailSentResult = $mail->send();
$emailSentResult = false;
if($emailSentResult===true){
$setFlagResult = $this->setSentFlagForOrder($customer['order_id'],$i);
if($setFlagResult===true){
$ordersSent[] = $customer['order_id'];
break;
}else{
throw new Exception("Update sent-flag for order {$customer['order_id']} failed.");
}
}else if($emailSentResult===false AND $i<$this->emailTryCount){
$this->setTryCountForOrder($customer['order_id'],$i);
// sleep($this->emailWaitTimer);
continue;
}else if($emailSentResult===false AND $i==$this->emailTryCount){
$this->setTryCountForOrder($customer['order_id'],$i);
$ordersFailed[] = $customer['order_id'];
}
}//End sending/attempting to send tracking email.
}//End of looping through the emailing list.
}//End of validation SMTP parameters.
$result = array('sent' =>$ordersSent
,'failed'=>$ordersFailed);
}//End of section for EMAIL-LIST exist
return $result;
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
MyCustomerMailer.php
<?PHP
require 'class/PHPMailer5.2/PHPMailerAutoload.php';
class MyCustomMailer_cl{
public $processLog = array();
private $dbConnect = null;
private $phpMailer = null;
private $SMTPDebug = null;
private $Debugoutput = null;
private $Host = null; //smtp.gmail.com OR smtp-relay.gmail.com
private $Port = null; //587
private $SMTPSecure = null; //tls or ssl
private $SMTPAuth = null; //true or false
private $Username = null;
private $Password = null;
private $sentFrom = array(); //array('example@gmail.com','Joe Doe');
private $replyTo = array(); //array('example@gmail.com','Joe Doe');
private $emailTo = array(); //array('example@gmail.com','Joe Doe');
private $subject = null; //Plain text
private $body = null; //Plain text
public function __construct() {
try{
$this->processLog[] = __FUNCTION__;
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
/*******************************************************************
SET functions
********************************************************************/
public function setSMTPParam($param) {
/*
$param can be a text string 'default' or an array.
$param = array( 'SMTPDebug' =>null
,'Debugoutput' =>null
,'Host' =>null
,'Port' =>null
,'SMTPSecure' =>null
,'SMTPAuth' =>null
,'Username' =>null
,'Password' =>null
);
*/
try{
$this->processLog[] = __FUNCTION__;
$paramError = 0;
$result = false;
if($param=='default'){
$param = array( 'SMTPDebug' =>0
,'Debugoutput' =>'html'
,'Host' =>'smtp-relay.gmail.com' //smtp.gmail.com OR smtp-relay.gmail.com
,'Port' =>587
,'SMTPSecure' =>'tls'
,'SMTPAuth' =>true
,'Username' =>"myEmail@email.com"
,'Password' =>"myPassword"
);
}else if(!is_array($param)){
throw new Exception('ERROR1901155: SMTP parameter is not an array.');
}
//Validation - 2019.01.17 need more work, script randomly fails check here.
foreach($param as $parameter){
if($parameter==='' OR is_null($param)){
$paramError++;
}
}
if($paramError==0){
$this->SMTPDebug = $param['SMTPDebug'];
$this->Debugoutput = $param['Debugoutput'];
$this->Host = $param['Host'];
$this->Port = $param['Port'];
$this->SMTPSecure = $param['SMTPSecure'];
$this->SMTPAuth = $param['SMTPAuth'];
$this->Username = $param['Username'];
$this->Password = $param['Password'];
$this->phpMailer = new PHPMailer;
$this->phpMailer->isSMTP();
$this->phpMailer->SMTPDebug = $this->SMTPDebug;
$this->phpMailer->Debugoutput = $this->Debugoutput;
$this->phpMailer->Host = $this->Host;
$this->phpMailer->Port = $this->Port;
$this->phpMailer->SMTPSecure = $this->SMTPSecure;
$this->phpMailer->SMTPAuth = $this->SMTPAuth;
$this->phpMailer->Username = $this->Username;
$this->phpMailer->Password = $this->Password;
$result = true;
}
return $result;
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
public function setupEmail($data) {
try{
$this->processLog[] = __FUNCTION__;
$this->sentFrom = $data['sentFrom'];
$this->phpMailer->setFrom($this->sentFrom[0],$this->sentFrom[1]);
$this->replyTo = $data['replyTo'];
$this->phpMailer->addReplyTo($this->replyTo[0],$this->replyTo[1]);
$this->emailTo = $data['emailTo'];
$this->phpMailer->addAddress($this->emailTo[0],$this->emailTo[1]);
$this->subject = $data['subject'];
$this->phpMailer->Subject = $this->subject;
$this->body = $data['body'];
$this->phpMailer->msgHTML($this->body);
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
public function send() {
try{
$this->processLog[] = __FUNCTION__;
$result = false;
if (!$this->phpMailer->send()) {
// throw new exception("error20190114: Failed to send at final stage.");
$result = false;
}else{
$result = true;
}
return $result;
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
public function sendWithRetry($attempt=3,$waitTime=5) {
try{
$this->processLog[] = __FUNCTION__;
$result = false;
for($i=1;$i<=$attempt;$i++){
if(!$this->phpMailer->send()){
if($i==$attempt){
break;
}else{
continue;
}
}else{
$result=true;
break;
}
}
return $result;
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
}
?>
我不确定如果你不展示你的代码,你如何期望任何人能够调试你的代码,但我猜你不知道 addAddress
做了什么(它不叫setAddress
是有原因的),并且您可能没有在发送循环中调用 clearAddresses
。
你的发送速度也很差;我希望发送 100 条消息不会超过几秒钟。
查看 PHPMailer 提供的邮件列表示例,它解决了所有这些问题。性能建议也可以在 PHPMailer 项目 wiki 上找到。
我创建了一个脚本,可以将一些跟踪详细信息通过电子邮件发送给每个已发货的客户订单。
该脚本是用 PHPMailer 构建的,并通过 Google SMTP 中继服务发送电子邮件。
在测试期间,一切都按预期工作。使用 100 封电子邮件进行负载测试,尽管发送到相同的电子邮件地址,但均按预期执行。没有重复或丢失的电子邮件。
然而在上线后不久,我被告知有几个客户收到了数十封电子邮件,其中包含其他客户的跟踪详细信息。
对于 gmail 用户,他们会收到其他客户的跟踪电子邮件,并将其电子邮件地址作为收件人。
使用 outlook 用户,他们会收到其他客户的电子邮件,并且在发送区域中有很多电子邮件。
我查看了代码,测试并检查了每个函数的输出,完全迷失在可能出错的地方。
下面是脚本的sudo过程。想看看是否有人可以提供一些关于如何解决此问题的提示。
- 将电子邮件列表检索到一维数组中。
- 创建 PHPMailer 实例
- 对于数组中的每封邮件,发送邮件,等待TRUE响应,如果为FALSE,等待5s,重试共3次,如果超过CONTINUE。
- 完成后,脚本结束。
其他说明
该脚本由 windows 任务调度程序触发。
脚本将花费大约 2-10 分钟到 运行,具体取决于重试次数,尽管调度程序设置为每 5 分钟 运行,但调度程序中的任务未设置为运行 任务的多个实例,如果存在 运行ning。
任何建议都很好。
干杯
代码片段。希望能提供足够的思路。
一般过程是脚本从 Dispatcher_cl.php 调用 sendTrackingEmails(),然后使用 MyCustomerMailer.php 的不同函数。 MyCustomerMailer.php 或多或少是 PHPMailer 的抽象层。
Dispatcher_cl.php
public function sendTrackingEmails() {
try{
$this->processLog[] = __FUNCTION__;
/*
1.Get list of emails
2.Loop and send emails
*/
$ordersSent = array();
$ordersFailed = array();
$result = false;
$emailListAndInfo = $this->getEmailListAndInfo();
if($emailListAndInfo===false){
//No orders to dispatch emails. So do nothing.
$result = false;
}else{
$mail = new MyCustomMailer_cl();
if($mail->setSMTPParam('default')===true){
foreach($emailListAndInfo as $customer){
$sentFrom = array();
$replyTo = array();
$emailTo = array($customer['email'],$customer['name']);
$subject = array();
$body = null;
/*
Preset email settings for each brand.
When adding vendors, remember to add a BODY template and VENDOR ID to the SQL in [m_getEmailListAndInfo]
*/
if($customer['vendor_id']==3){
//Diamondphoto
$sentFrom = array('no-reply@email.com','Your order has been shipped');
$replyTo = array('no-reply@email.com','Your order has been shipped');
$subject = "Tracking for order {$customer['vendorOrderId']}";
$body = $this->getEmailTemplateFor(3,$customer);
}else{
/*
If vendor_id does not match existing setup, set TRYCOUNT to 99 as indicator and skip remaining execution.
Next script-run will not pick up this record due to 99 will be greater than the usual preset TRYCOUNT.
*/
$this->setTryCountForOrder($customer['order_id'],99);
continue;
}
$emailPackage['sentFrom'] = $sentFrom;
$emailPackage['replyTo'] = $replyTo;
$emailPackage['emailTo'] = $emailTo;
$emailPackage['subject'] = $subject;
$emailPackage['body'] = $body;
$mail->setupEmail($emailPackage);
for($i=1;$i<=$this->emailTryCount;$i++){
// $emailSentResult = $mail->send();
$emailSentResult = false;
if($emailSentResult===true){
$setFlagResult = $this->setSentFlagForOrder($customer['order_id'],$i);
if($setFlagResult===true){
$ordersSent[] = $customer['order_id'];
break;
}else{
throw new Exception("Update sent-flag for order {$customer['order_id']} failed.");
}
}else if($emailSentResult===false AND $i<$this->emailTryCount){
$this->setTryCountForOrder($customer['order_id'],$i);
// sleep($this->emailWaitTimer);
continue;
}else if($emailSentResult===false AND $i==$this->emailTryCount){
$this->setTryCountForOrder($customer['order_id'],$i);
$ordersFailed[] = $customer['order_id'];
}
}//End sending/attempting to send tracking email.
}//End of looping through the emailing list.
}//End of validation SMTP parameters.
$result = array('sent' =>$ordersSent
,'failed'=>$ordersFailed);
}//End of section for EMAIL-LIST exist
return $result;
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
MyCustomerMailer.php
<?PHP
require 'class/PHPMailer5.2/PHPMailerAutoload.php';
class MyCustomMailer_cl{
public $processLog = array();
private $dbConnect = null;
private $phpMailer = null;
private $SMTPDebug = null;
private $Debugoutput = null;
private $Host = null; //smtp.gmail.com OR smtp-relay.gmail.com
private $Port = null; //587
private $SMTPSecure = null; //tls or ssl
private $SMTPAuth = null; //true or false
private $Username = null;
private $Password = null;
private $sentFrom = array(); //array('example@gmail.com','Joe Doe');
private $replyTo = array(); //array('example@gmail.com','Joe Doe');
private $emailTo = array(); //array('example@gmail.com','Joe Doe');
private $subject = null; //Plain text
private $body = null; //Plain text
public function __construct() {
try{
$this->processLog[] = __FUNCTION__;
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
/*******************************************************************
SET functions
********************************************************************/
public function setSMTPParam($param) {
/*
$param can be a text string 'default' or an array.
$param = array( 'SMTPDebug' =>null
,'Debugoutput' =>null
,'Host' =>null
,'Port' =>null
,'SMTPSecure' =>null
,'SMTPAuth' =>null
,'Username' =>null
,'Password' =>null
);
*/
try{
$this->processLog[] = __FUNCTION__;
$paramError = 0;
$result = false;
if($param=='default'){
$param = array( 'SMTPDebug' =>0
,'Debugoutput' =>'html'
,'Host' =>'smtp-relay.gmail.com' //smtp.gmail.com OR smtp-relay.gmail.com
,'Port' =>587
,'SMTPSecure' =>'tls'
,'SMTPAuth' =>true
,'Username' =>"myEmail@email.com"
,'Password' =>"myPassword"
);
}else if(!is_array($param)){
throw new Exception('ERROR1901155: SMTP parameter is not an array.');
}
//Validation - 2019.01.17 need more work, script randomly fails check here.
foreach($param as $parameter){
if($parameter==='' OR is_null($param)){
$paramError++;
}
}
if($paramError==0){
$this->SMTPDebug = $param['SMTPDebug'];
$this->Debugoutput = $param['Debugoutput'];
$this->Host = $param['Host'];
$this->Port = $param['Port'];
$this->SMTPSecure = $param['SMTPSecure'];
$this->SMTPAuth = $param['SMTPAuth'];
$this->Username = $param['Username'];
$this->Password = $param['Password'];
$this->phpMailer = new PHPMailer;
$this->phpMailer->isSMTP();
$this->phpMailer->SMTPDebug = $this->SMTPDebug;
$this->phpMailer->Debugoutput = $this->Debugoutput;
$this->phpMailer->Host = $this->Host;
$this->phpMailer->Port = $this->Port;
$this->phpMailer->SMTPSecure = $this->SMTPSecure;
$this->phpMailer->SMTPAuth = $this->SMTPAuth;
$this->phpMailer->Username = $this->Username;
$this->phpMailer->Password = $this->Password;
$result = true;
}
return $result;
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
public function setupEmail($data) {
try{
$this->processLog[] = __FUNCTION__;
$this->sentFrom = $data['sentFrom'];
$this->phpMailer->setFrom($this->sentFrom[0],$this->sentFrom[1]);
$this->replyTo = $data['replyTo'];
$this->phpMailer->addReplyTo($this->replyTo[0],$this->replyTo[1]);
$this->emailTo = $data['emailTo'];
$this->phpMailer->addAddress($this->emailTo[0],$this->emailTo[1]);
$this->subject = $data['subject'];
$this->phpMailer->Subject = $this->subject;
$this->body = $data['body'];
$this->phpMailer->msgHTML($this->body);
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
public function send() {
try{
$this->processLog[] = __FUNCTION__;
$result = false;
if (!$this->phpMailer->send()) {
// throw new exception("error20190114: Failed to send at final stage.");
$result = false;
}else{
$result = true;
}
return $result;
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
public function sendWithRetry($attempt=3,$waitTime=5) {
try{
$this->processLog[] = __FUNCTION__;
$result = false;
for($i=1;$i<=$attempt;$i++){
if(!$this->phpMailer->send()){
if($i==$attempt){
break;
}else{
continue;
}
}else{
$result=true;
break;
}
}
return $result;
}catch(Exception $e){
$this->processLog[] = __FUNCTION__.$e->getMessage();
throw $e;
}
}
}
?>
我不确定如果你不展示你的代码,你如何期望任何人能够调试你的代码,但我猜你不知道 addAddress
做了什么(它不叫setAddress
是有原因的),并且您可能没有在发送循环中调用 clearAddresses
。
你的发送速度也很差;我希望发送 100 条消息不会超过几秒钟。
查看 PHPMailer 提供的邮件列表示例,它解决了所有这些问题。性能建议也可以在 PHPMailer 项目 wiki 上找到。