【问题标题】:PHPMailer and Google SMTP-Relay. Excess duplicate email with receiver receiving other customer emailPHPMailer 和谷歌 SMTP 中继。收件人收到其他客户电子邮件的重复电子邮件过多
【发布时间】:2019-01-19 16:04:25
【问题描述】:

我创建了一个脚本,通过电子邮件将一些跟踪详细信息发送给每个已发货的客户订单。

该脚本是用 PHPMailer 构建的,并通过 Google SMTP-Relay 服务发送电子邮件。

在测试期间,一切都按预期工作。对 100 封电子邮件进行了负载测试,尽管发送到相同的电子邮件地址,但都按预期执行。没有重复或丢失的电子邮件。

但在上线后不久,我被告知有几个客户收到了数十封电子邮件,其中包含其他客户的跟踪详细信息。

对于 gmail 用户,他们收到了其他客户的跟踪电子邮件,其电子邮件地址为发送至。

对于 Outlook 用户,他们会收到其他客户的电子邮件,其中许多电子邮件在已发送至区域中。

我已经查看了代码,测试并检查了每个函数的输出,完全迷失在可能出错的地方。

下面是脚本的 sudo 过程。看看是否有人可以提供一些关于如何解决此问题的提示。

  1. 将电子邮件列表检索到一维数组中。
  2. 创建一个 PHPMailer 实例
  3. 对于数组中的每封邮件,发送邮件,等待TRUE响应,如果是FALSE,WAIT 5s,总共重试3次,如果超过CONTINUE。
  4. 完成后,脚本结束。

其他说明

脚本由 Windows 任务调度程序触发。

脚本运行大约需要 2-10 分钟,具体取决于重试次数,尽管调度程序设置为每 5 分钟运行一次,但调度程序中的任务已设置为不运行任务的多个实例(如果现有正在运行) .

任何建议都会很棒。

干杯

代码片段。希望能提供足够的想法。

一般过程是脚本从 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;
    }
}   

}

?>

【问题讨论】:

    标签: smtp phpmailer


    【解决方案1】:

    如果您不显示代码,我不确定您希望任何人能够调试您的代码,但我猜您不知道 addAddress 做了什么(它不称为 setAddress一个原因),并且您可能没有在发送循环中调用clearAddresses

    你的发送速度也很差;我预计发送 100 条消息不会超过几秒钟。

    看看 PHPMailer 提供的邮件列表示例,它解决了所有这些问题。性能建议也可以在 PHPMailer 项目 wiki 上找到。

    【讨论】:

    • 您好,感谢您的反馈。最初我认为没有人希望代码进行实际调试。但是我已经添加到它以供任何其他可能想要查看它的人使用。我很惊讶你说速度很差,因为我看到的帖子表明它是正常的。我个人会同意你的看法。这意味着我错过了一些重要的事情。是的,我将查看 addAddress 和 clearAddresses。在浏览样本时,我一定错过了一些重要的事情。谢谢!
    • 堆栈溢出是关于代码的全部!虽然这显示了你的包装类,但它没有显示你是如何驱动它的,这就是你的问题所在。
    • 我刚刚在一个非常相似的问题上看到了你的另一篇文章。 stackoverflow.com/questions/49912975/… 没有阅读正确的样本是我的错。非常感谢。
    • 如果您的列表中有 100 个收件人并且您不调用 clearAddresses,您将发送 1+2+3...+100 条消息,而不仅仅是 100 条,这可能就是它看起来的原因慢。
    猜你喜欢
    • 2018-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多