如果附件很大,phpmailer会突然停止

时间:2019-05-19 16:49:23

标签: php loops phpmailer

问题

我有一个脚本可以将通讯发送给我的联系人。如果我没有附件(2,000封电子邮件证明),该脚本可以正常工作。

现在,如果我使用附件,脚本也可以正常工作。但是只能发送大约30封电子邮件。

测试设置

  • 要执行的100个电子邮件组(循环)。
  • 附件:2个文件(总计4,6 MB)->脚本在50秒内发送了34封电子邮件后终止(但没有错误消息)。 (〜156 MB)。

测试版本

  • 将php.ini memory_limit从100M更改为500M->无效。收到34封电子邮件后仍然出错。
  • 在每个循环之后放入sleep(5)->无效。收到34封电子邮件后仍然出错。
  • 没有附件:所有100封电子邮件都已发送(约30秒)。
  • 对2000封电子邮件没有附件:所有2000封电子邮件都已发送(约6分钟)。
  • 在php.ini中更改max_execution_time无效。

假设

由于这种行为,我希望有一个内存问题而不是一个时间问题。

但是对每个循环的内存(memory_get_usage())的测试表明,第一个循环的内存为1.1 MB,第34个循环的内存为1.2 MB

问题

请在下面的代码中查找,但我想应该没问题。 是否有人知道导致问题的原因?非常感谢!

myMailer.class

class myMailer extends PHPMailer {

    public function __construct(?bool $exceptions = true) {
        $config = parse_ini_file('../../ini/config.ini', true);

        parent::__construct($exceptions);

        try {
            // Language of Errors
            $this->setLanguage('en', dirname(__FILE__) . '/../external/PHPMailer/language/');

            // Server settings
            $this->SMTPDebug  = 0;                                  // Enable verbose debug output
            $this->isSMTP();                                        // Set mailer to use SMTP
            $this->SMTPAuth   = true;                               // Enable SMTP authentication
            $this->SMTPSecure = 'ssl';                              // Enable TLS encryption, `ssl` also accepted
            $this->Port       = 465;                                // TCP port to connect to
            $this->Host       = $config['smtp_server']['host'];     // SMTP server
            $this->Username   = $config['smtp_server']['username']; // SMTP username
            $this->Password   = $config['smtp_server']['password']; // SMTP password
            $this->CharSet    ='UTF-8';                             // Set Character Set
            $this->isHTML(true);                                    // Set email format to HTML
            $this->setFrom("office@superman.com", "superman OFFICE");

        } catch (Exception $e) {
            // echo 'Message could not be sent. Mailer Error: ', $mail->ErrorInfo;
            trigger_error("myMailer(): " . $this->ErrorInfo,E_USER_ERROR);
        }
    }

    public function setBody(string $salutation, string $receiver, string $message) : void {
        // Linebreak to <BR>
        $message = nl2br($message);

        // Create Body
        $body = file_get_contents('../../ini/email_template.html');
        $body = str_replace("{Receiver}",       $receiver,                  $body);
        $body = str_replace("{Salutation}",     $salutation,                $body);
        $body = str_replace("{Message}",        $message,                   $body);

        $this->Body = $body;
    }
}

send_emails.php

<?php
$groupID     = $_POST['id'];
$subject     = $_POST['Subject'];
$message     = $_POST['Message'];
$attachments = (key_exists('Files', $_POST)) ? $_POST['Files'] : array();

$group = new Group($groupID);

// Prepare and get HTML
$htmlGenerator  = HtmlGenerator::getInstance();
$htmlGenerator->setTitle("sending emails");
$header = $htmlGenerator->getWebbaseHtmlHeader();
$footer = $htmlGenerator->getWebbaseHtmlFooter();

echo $header;

?>
    <div class="container">
        <h1>Emailing</h1>
        <h3>Group: <?php echo $group->getTitle(); ?></h3>
        <h4>Number of members: <?php echo $group->getNumberOfMembers(); ?></h4>
        <?php

            $strScreenOutput = "
                <table class='table table-sm table-hover table-responsive-md'>
                    <thead class='thead-dark'>
                        <th scope='col'>Nr.</th>
                        <th scope='col'>Date</th>
                        <th scope='col'>Company</th>
                        <th scope='col'>Lastname</th>
                        <th scope='col'>Firstname</th>
                        <th scope='col'>Email</th>
                        <th scope='col'>Newsletter</th>
                        <th scope='col'>Result</th>
                    </thead>
                    <tbody>";

            $protocol = $strScreenOutput;

            echo $strScreenOutput;

            $i = 0;
            $members  = Contact::getAllOfGroup($groupID);
            foreach ($members as $contact) {
                $i++;
                $datRun = date('d.m.Y (H:i:s)');

                if ($contact->getNewsletter() === false) {
                    $result = "no sub.";
                } elseif ($contact->getEmail() === "" || $contact->getEmail() === null) {
                    $result = "no email";
                } else {
                    $return = $contact->sendEmail($subject, $message, $attachments);
                    $result = ($return===true) ? "ok" : $return;
                }

                // create feedback for browser
                $strScreenOutput  = "<tr>";
                $strScreenOutput .= "<th scope='row'>".str_pad($i, 4 ,'0', STR_PAD_LEFT)."</th>";
                $strScreenOutput .= "<td>{$datRun}</td>";
                $strScreenOutput .= "<td>{$contact->getCompany()}</td>";
                $strScreenOutput .= "<td>{$contact->getLastName()}</td>";
                $strScreenOutput .= "<td>{$contact->getFirstName()}</td>";
                $strScreenOutput .= "<td>{$contact->getEmail()}</td>";
                $strScreenOutput .= "<td>".(($contact->getNewsletter()) ? "yes" : "no")."</td>";
                $strScreenOutput .= "<td>{$result}</td>";
                $strScreenOutput .= "</tr>";
                echo str_pad($strScreenOutput,4096)."\n"; // Add some additional blanks to enable flushing (as some browsers suppress flushing)

                // create internal protocol
                $protocol .= $strScreenOutput . "\n";

                // Send to browser
                flush();
                ob_flush();

                // add some execution time
                set_time_limit(30);
            }

            $strScreenOutput = "</tbody>
                            </table>";
            $protocol .= $strScreenOutput;
            echo $strScreenOutput;
        ?>

        <h3>Emails successfully transmitted.</h3>
    </div>

<?php

    // send protocols
    $protocol = "<h3>Group: {$group->getTitle()}</h3>".$protocol;
    $protocol = "<div style='margin-top: 30px'>$protocol</div>";

    $internal = new Contact(1);
    $internal->sendEmail("PROTOCOL: ".$subject, $message . $protocol, $attachments);

echo $footer;

联系人:: sendEmail()

public  function sendEmail(string $subject, string $message, array $attachments = array()) {
    $mail = new myMailer();

    if ( is_null($this->getEmail() || $this->getEmail() == "") ) {
        return false;

    } else {
        try {
            // Compose Email
            $mail->addAddress($this->getEmail(), $this->getFirstName() . " " . $this->getLastName());
            $mail->Subject = $subject;
            $mail->setBody($this->getSalutationText(), $this->getAddress(), $message);

            foreach ($attachments as $file) {
                $uploadPath  = $_SERVER['DOCUMENT_ROOT'] . "/../../files/email_attachments/";
                $file_url = $uploadPath.$file;

                if (! is_dir($uploadPath))    { die("Folder \"$uploadPath\" does not exist.");}
                if (! file_exists($file_url)) { die("File \"$file_url\" does not exist."); }

                $mail->addAttachment($file_url);
            }

            $return = $mail->send();

            // clean up
            $mail->clearAddresses();
            $mail->clearAttachments();

        } catch (Exception $error) {
            $return = $error->getMessage();
        }

        return $return;
    }

    unset($mail);

}

1 个答案:

答案 0 :(得分:0)

这听起来确实像是内存问题-发送大型附件时,PHPMailer在内存上的效率不是很高-尝试在循环内回显从memory_get_usage()获得的内容,以确认内存消耗。

通常,由于创建新的PHPMailer实例,重新处理相同的附件并为每封邮件打开新的SMTP连接,您的发送效率非常低,所有这些仅需要执行一次。有关如何更高效地发送邮件,请查看the mailing list example provided with PHPMailerthe wiki doc on sending to lists

更有效地重用实例和连接可能会减少总体内存需求。