【问题标题】:PHP Mail service sends mail to everyone in loop. How to avoid that?PHP Mail 服务循环发送邮件给每个人。如何避免这种情况?
【发布时间】:2019-09-13 18:33:26
【问题描述】:

对于我的网页,我有一个 php 邮件服务,可让我通过以下方式发送邮件

EmailService::getService()->sendEmail($email, $first_name, $subject, $body);

除非我将此行放入一个循环中,否则这很好用,例如通知所有列出的管理员:

$sql = "SELECT * FROM admin_notifications";
$result = mysqli_query($con, $sql);
while($row = mysqli_fetch_assoc($result)){      
    EmailService::getService()->sendEmail($row['email'], $row['first_name'], $subject, $body);
}

现在每个管理员都会收到每封邮件。例如,如果有 3 个管理员,每个管理员都会收到 3 封不同的邮件。该服务似乎向每个接收者发送 3 封邮件。

由于我没有实现邮件服务本身,而且我不完全理解它,我真的不知道从哪里开始寻找这个错误。

也许这里有人有建议?

这是邮件服务的代码:

<?php

    /*Verschickt Emails*/
    use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;

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

    class EmailService{
        /**
        * instance
        *
        * Statische Variable, um die aktuelle (einzige!) Instanz dieser Klasse zu halten
        *
        * @var Singleton
        */
       protected static $_instance = null;
       protected $mail;

       /**
        * get service
        *
        * Falls die einzige Service-Instanz noch nicht existiert, erstelle sie
        * Gebe die einzige Service-Instanz dann zurück
        *
        * @return   Singleton
        */
       public static function getService()
       {
           if (null === self::$_instance)
           {
               self::$_instance = new self;
           }
           return self::$_instance;
       }

       /**
        * clone
        *
        * Kopieren der Service-Instanz von aussen ebenfalls verbieten
        */
       protected function __clone() {}

       /**
        * constructor
        *
        * externe Instanzierung verbieten
        */
       protected function __construct() {
           //new PHPMailerAutoload();
           $this->mail = new PHPMailer();

           $configs = ConfigService::getService()->getConfigs();
           $this->mail->SMTPDebug = 3;          //Gibt starke Debugging Ausgaben aus - für Realease Deaktivieren (später auf 2)
           $this->mail->setLanguage('de');
           $this->mail->IsSendmail();
           $this->mail->Host = $configs['email_host'];
           $this->mail->Port = $configs['email_port'];
           $this->mail->SMTPSecure = "ssl";
           $this->mail->SMTPAuth = true;
           $this->mail->Username = $configs['email_username'];
           $this->mail->Password = $configs['email_password'];
           $this->mail->From       = $configs['email_username'];
           $this->mail->FromName   = "Studienführer - VWI-ESTIEM-Karlsruhe e.V.";
           $this->mail->CharSet =  'UTF-8';
           $this->mail->isHTML(true);
       }


       /**
        * sendet Email
        *
        * Sendet eine Email an den Nutzer. Gibt ein gewisses Format vor
        */
       public function sendEmail($toEmail, $userName, $subject, $body){
           $this->mail->AddAddress($toEmail, $userName);
           $this->mail->Subject = $subject;

             $this->mail->AddEmbeddedImage(__DIR__ . '/../../pictures/logo_studi.png', 'studilogo.png', 'studilogo.png');
             $this->mail->AddEmbeddedImage(__DIR__ . '/../../pictures/email/facebook.png', 'facebook.png', 'facebook.png');
             $this->mail->AddEmbeddedImage(__DIR__ . '/../../pictures/email/instagram.png', 'instagram.png', 'instagram.png');

           $htmlWithoutCSS = '
            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
            <html>
                <head>
                    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
                    <title>My Mail</title>
                    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
                </head>
                '.'
                <body>
                    <p>Hallo $userName,</p>
                    $body
                </body>
            </html>
            ';
           $cssToInlineStyles = new CssToInlineStyles();
           $this->mail->Body = $cssToInlineStyles->convert(
                $htmlWithoutCSS,
                file_get_contents(__DIR__ . '/../../res/css/emails.css')
            );
           if(!$this->mail->Send()){
               return false;
           }else{
               return true;
           }
       }
    }

?>

【问题讨论】:

  • 那么谁应该收到电子邮件,谁不应该收到呢?
  • admin_notifications由什么组成?
  • 您一定对如何调试有所了解?您可以从数据库返回到 $row 的内容开始?这是否将所有人列出了三遍?
  • 你向我们展示了EmailService类中的所有方法吗?

标签: php email


【解决方案1】:

每次循环都使用同一个实例,每次调用 sendEmail() 时,它都会向实例添加地址。

您可以每次创建一个新实例,而不是调用getService(),它会重新开始。

while($row = mysqli_fetch_assoc($result)){    
    $mailer = new EmailService;  
    $mailer->sendEmail($row['email'], $row['first_name'], $subject, $body);
}

【讨论】:

  • 因为它解决了同样的问题,我相信这也可以,但我选择了 RiggsFollys 解决方案,因为这也适用于使用该服务的其他人,而无需告诉他们任何事情。无论如何,谢谢!
  • 我同意这一点。原始设计不适用于单例模式。
【解决方案2】:

您的问题的原因是这一行

$this->mail->AddAddress($toEmail, $userName);

每次调用时都会将新的电子邮件地址添加到地址列表中。这导致您向最后一位管理员发送一封电子邮件,向倒数第二位管理员发送两封电子邮件等

public function sendEmail($toEmail, $userName, $subject, $body){ 似乎并未设计为每次实例化多次调用,但一个简单的更改将解决问题

在这样的方法中添加$mail-&gt;ClearAllRecipients();

public function sendEmail($toEmail, $userName, $subject, $body){

    // remove previous recipients if being called multiple times in a loop
    $this->mail->ClearAllRecipients();  

    $this->mail->AddAddress($toEmail, $userName);
    $this->mail->Subject = $subject;

    . . .

【讨论】:

  • addEmbeddedImage会不会有类似的问题?每次调用 sendEmail 时,它都会添加 3 个图像(尽管它们与之前的调用具有相同的名称——如果在内部用作关联数组中的键,它们就不会相乘)。
  • 这似乎是使用单例模式几乎固有的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
  • 1970-01-01
  • 2020-03-28
  • 1970-01-01
  • 1970-01-01
  • 2020-09-28
相关资源
最近更新 更多