PHPMailer发送电子邮件非常慢

时间:2019-12-13 22:16:02

标签: php phpmailer

我有一个应用程序在PHP 7.2上使用PHPMailer发送电子邮件,我必须发送大约50封电子邮件,大约需要40秒才能完成,我认为这很多,因为根据文档,它最多可以发送300封电子邮件。第二...我尝试使用本地电子邮件服务器和Google SMTP服务(这是我们需要的,因为它将使用GSuite电子邮件作为发件人)。该函数接收一个包含每个客户所需数据的数组,但是我创建了smtp对象及其在循环外的配置,对每个客户执行一次的唯一方法是send(),如果我注释该行,它将只需不到1秒的时间即可完成,因此连接不会延迟执行,它只是send()本身。我做错了什么吗?我对该库没有太多经验,并且它是基于基本示例的,因此我不确定是否可以添加或更改任何配置以加快此速度。

public static function ejecutarEnvio($datosCorreo) {
    try {
      $mail = new PHPMailer(true);

      // Configuración general
      $mail->SMTPDebug = SMTP::DEBUG_SERVER;      
      $mail->isSMTP();
      $mail->CharSet = 'utf-8';
      $mail->Host = $_SESSION["smtp_host"];
      $mail->Username = $_SESSION["smtp_user"];
      $mail->Password = $_SESSION["smtp_pass"];
      $mail->Port = $_SESSION["smtp_port"];
      if ($_SESSION["smtp_secure"]=="TLS")
        $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
      elseif ($_SESSION["smtp_secure"]=="SSL")
        $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
      $mail->SMTPAuth = true;
      $mail->SMTPKeepAlive = true;
      $mail->isHTML(true);
      $mail->setFrom($_SESSION["no_reply"], $_SESSION["no_reply_name"]);

      // envío independiente
      for ($i = 0; $i < count($datosCorreo); $i++) {
        $datos = $datosCorreo[$i];

        // se cargan todas las variables que pueden cambiar en el arreglo de objetos para enviar correo
        if(filter_var(trim($datos['destinatario1']), FILTER_VALIDATE_EMAIL))
          $mail->addAddress(trim($datos['destinatario1']));
        if(filter_var(trim($datos['destinatario2']), FILTER_VALIDATE_EMAIL))
          $mail->addCC(trim($datos['destinatario2']));
        if(filter_var(trim($datos['destinatario3']), FILTER_VALIDATE_EMAIL))
          $mail->addCC(trim($datos['destinatario3']));
        $mail->addReplyTo($datos['replyto']);
        $mail->Subject = $datos['titulo'];
        $mail->Body = $datos['mensaje'];
        // se cargan todas las variables que pueden cambiar en el arreglo de objetos para enviar correo

        try {
          // intento hacer el envio del correo, lo hago dentro de un try independiente para que solo afecte al objeto actual
          if ($mail->send())
            $datosCorreo[$i]['mensaje_correo'] = "";
          else 
            throw new Exception("Error enviando el correo. " . $mail->ErrorInfo);
        } catch (Exception $e) {
          $datosCorreo[$i]['mensaje_correo'] = $e->getMessage();
        }

        $mail->clearAddresses();
      }

      $mail->SmtpClose();
    } catch (Exception $e) {
      for ($i = 0; $i < count($datosCorreo); $i++) {
        $datosCorreo[$i]['mensaje_correo'] = "Error configurando el envío de correo. " . $e->getMessage();;
      }
    }

    return $datosCorreo;
  } 

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

PHPMailer Wiki具有广泛的advice on sending to lists,并提供了一个示例,演示了how to send to lists efficiently

最重要的是,不是每次都创建一个新实例,而是重新使用一个实例,这使您可以启用SMTP keepalive。

$mail->SMTPKeepAlive = true;

我可以在这里看到您正在执行此操作,但是您还可以执行其他操作。通过SMTP发送到localhost时,您无需使用身份验证或加密,因此可以将其禁用:

$mail->SMTPAuth = false;
$mail->SMTPSecure = false;
$mail->SMTPAutoTLS = false;

这将消除多次往返。

花费send花费时间的原因是,PHPMailer在此之前几乎没有做任何事情-一切都已设置。

您正在验证循环中的电子邮件地址-addAddress()addCC已经这样做了,因此您在重复工作;而是检查其返回值,并continue;如果地址不正确,则忽略。

此结构是多余的:

    try {
      // intento hacer el envio del correo, lo hago dentro de un try independiente para que solo afecte al objeto actual
      if ($mail->send())
        $datosCorreo[$i]['mensaje_correo'] = "";
      else 
        throw new Exception("Error enviando el correo. " . $mail->ErrorInfo);
    } catch (Exception $e) {
      $datosCorreo[$i]['mensaje_correo'] = $e->getMessage();
    }

您可以将其简化为这个原因,因为您已经要求PHPMailer将错误抛出异常(通过将true传递给构造函数),因此它将永远不会达到您抛出自己的异常的地步:

    try {
        $mail->send();
        // intento hacer el envio del correo, lo hago dentro de un try independiente para que solo afecte al objeto actual
        $datosCorreo[$i]['mensaje_correo'] = "";
    } catch (Exception $e) {
        $datosCorreo[$i]['mensaje_correo'] = $e->getMessage();
    }

我毫不费力地每秒发送数百封邮件,任何体面的本地邮件服务器都应该能够每秒处理数千封邮件,因此这不是原因,但您应该检查一下。

要找出瓶颈在任何代码中的位置,我建议在IDE中使用探查器,而不要使用随机定时调用。它会立即告诉您问题出在哪里。带有qcachegrind或PHPStorm的xdebug对此非常有效。