简体   繁体   中英

Zend Framework: Fatal error when trying to use Zend Mail Transport to send multiple emails with attachments

I don't totally understand how all this works, but I'm getting this error:

Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to allocate 261858 bytes) in /Users/andrew/Sites/myApp/library/Zend/Mail/Transport/Smtp.php on line 213

I'm running this code locally on my Mac running MAMP. Not sure if that has anything to do with it. This is my code, basically:

$config = array('ssl' => 'tls', 'port' => 587, 'auth' => 'login', 'username' => 'username', 'password' => 'password');
    $smtpConnection = new Zend_Mail_Transport_Smtp('smtp.gmail.com', $config);

    foreach ($subscribers as $subscriber) {
        $message = new Zend_Mail('utf-8');
        $message->setFrom('my@mailinglist.com', 'Mailing List')
                ->addTo($subscriber->email)
                ->setSubject($subject)
                ->setBodyText($body);
        $attachment = $message->createAttachment(file_get_contents($filepath));
        $attachment->type = 'application/pdf';
        $attachment->filename = $filename;
        $message->send($smtpConnection);
    }

However, the more subscribers there are, the higher this number ends up getting, and this fix will only help for so long:

ini_set("memory_limit","12M");

I need to figure out how to send an email with an attachment to a couple hundred people. Here's something else I've come up with but it seems a little hacky to only set the bcc and not the to address:

$message = new Zend_Mail('utf-8');
    $message->setFrom('my@mailinglist.com', 'Mailing list')
            ->setSubject($subject)
            ->setBodyText($body);
    $attachment = $message->createAttachment(file_get_contents($filepath));
    $attachment->type = 'application/pdf';
    $attachment->filename = $filename;

    foreach ($subscribers as $subscriber) {
        $message->addBcc($subscriber->email);
    }
    $message->send($smtpConnection);

However, even doing this, I need to specify the "memory_limit". Can you please point me in the right direction with this? Is there something I'm not doing?

I'm guessing your pdf is about 250Kbytes? You're reading it into memory once per email you send out. Don't. Read it once. :) It might also be an encoding-thing in the Zend framework.

  • Call file_get_contents() once before your loop
  • Set the memory limit much higher as long as your server can handle it (I'd say along the lines of 32-128 Mbytes)
  • unset() your variables - should force php to GC it (in theory)
  • You could reuse the $message object (ugly hack, but could save bytes if Zend does some sort of file-encoding and it uses lots of memory)

I'd also make a cron-job for sending the emails, and making sure that each email (or a reference to it) is stored in the database along with a status. This way you won't send duplicate mails if you hit another memory limit, or bug.

There's no need to create a new attachment with each message. Just create it once and then attach it each time you send.

$config = array('ssl' => 'tls', 'port' => 587, 'auth' => 'login', 'username' => 'username', 'password' => 'password');
$smtpConnection = new Zend_Mail_Transport_Smtp('smtp.gmail.com', $config);

$attachment = new Zend_Mime_Part(file_get_contents($filepath));
$attachment->type = 'application/pdf';
$attachment->disposition = Zend_Mime::DISPOSITION_ATTACHMENT;
$attachment->filename = $filename;

foreach ($subscribers as $subscriber) {
    $message = new Zend_Mail('utf-8');
    $message->setFrom('my@mailinglist.com', 'Mailing List')
            ->addTo($subscriber->email)
            ->setSubject($subject)
            ->setBodyText($body);
    $message->addAttachment($attachment);
    $message->send($smtpConnection);
}

I have had the similar problem with memory limit and sending by one SMTP connection for a lot of messages. Zend_Mail_Protocol_Abstract holds its internal log in memory. There are logged all mail requests in the log. The log is growing up with each message sent. You has to call $protocol->resetLog() sometimes. (It depends on your data amount for each message. You can check your memory use by memory_get_usage() PHP function.) Try something like this:

  $transport = new Zend_Mail_Transport_Smtp();
  $protocol = new Zend_Mail_Protocol_Smtp('localhost');
  $protocol->connect();
  $protocol->helo('localhost');
  $transport->setConnection($protocol);
  foreach(){
    $mail = new Zend_Mail('utf-8');
    ...
    $protocol->rset();
    $mail->send($transport);
    $protocol->resetLog();  // you don't need to resetLog for each message
  }

This also might be helpful: http://framework.zend.com/manual/en/zend.mail.multiple-emails.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM