0
$i = 1;
foreach ($recipients as $email => $name) {
    $mail->ClearAddresses();
    $mail->AddBCC($email, $name); 
    if (!$mail->send()) {
        $send = 0;
    } else {
        $send = 1;
    }
    $query = "INSERT INTO `newsletter_send`(`email`, `id_newsletter`, `date`, `send`) VALUES ('$email',$id_newsletter, NOW(),$send) ";
    $stmt = $link->prepare($query) or die('error');
    $stmt->execute();
    $mail->clearAllRecipients(); 

    if (($i % 100) == 0) {
        sleep(60);
    }

    $i++;
}

What is the best way to send a large emails without sleep() and without to wait the page to finish loading? In addition to the cron job you have other ideas ?

EDIT: I have 680 users who will receive the email, but after a while I get 500 Internal Server Error.. why? It maybe time_limit? enter image description here

Community
  • 1
  • 1
Eliana
  • 395
  • 3
  • 10
  • 20
  • Try to send it through cron – Web Artisan May 24 '16 at 09:09
  • You could use a queue manager like beanstalk if you don't want to use cron. You'd need extra software on the server though, where a task scheduler is already available. – jeroen May 24 '16 at 09:10
  • Why are you making the `sleep()` call? The mail server should queue the messages and send when the server is ready - unless it has restrictions. – Tigger May 24 '16 at 09:10
  • 3
    Why do you send it separate? Add _all_ recipients via BCC and send the message _once_. – arkascha May 24 '16 at 09:11
  • I have built a system similar to cron jobs, where I schedule emails to be sent (storing the details in a database), then using a page that checks every 15 seconds if a job is available (only processing one job every 15 seconds). I can send multiple emails this way to my clients, without the SMTP server thinking I am spamming. – andreini May 24 '16 at 09:13
  • @Tigger The server has restrictions. – Eliana May 24 '16 at 09:13
  • @arkascha I send separate because i send email foreach 100 users – Eliana May 24 '16 at 09:13
  • 1
    For such an amount (what is that, spam?) you should think about using a mail service provider. – arkascha May 24 '16 at 09:14
  • @arkascha The mail server can flag you as spam if you do that. Also, there is a limit for BCC entries. – andreini May 24 '16 at 09:15
  • @niandrei That actually is a question of your subscription plan, typically. Mail service providers actually _live_ by offering a service for mass email campaigns... – arkascha May 24 '16 at 09:22
  • @arkascha You're nice! ;) of course it's not spam – Eliana May 24 '16 at 09:29
  • @Eliana The alternative in my answer can be done on a server with restrictions :). It doesn't require any root access and can be done in shared hosting or any of the options provided by hosting providers I would assume. Let me know what you think of it. – Webeng May 24 '16 at 09:42
  • Take a look at [the mailing list example provided with PHPMailer](https://github.com/PHPMailer/PHPMailer/blob/master/examples/mailing_list.phps). – Synchro May 25 '16 at 06:21

2 Answers2

2

Message queues.

beanstalkd is a good solution.

You can then use a SDK like pheanstalk to handle the queue and its jobs.

EDIT: If you have restricted access to your server (for example, if you are using a shared hosting) message queues as a service are also an option.

GiamPy
  • 3,543
  • 3
  • 30
  • 51
  • Would you happen to know the answer to this question about beanstalk/pheanstalk?: http://stackoverflow.com/questions/37408325/beanstalkd-pheanstalk-security-issue – Webeng May 24 '16 at 09:12
  • I was just about to answer the same thing as you hahah, but you beat me to it, but then I remembered I had a recent question I posted relative to beanstalk queues and security, so why not ask someone who might know the answer to it :) – Webeng May 24 '16 at 09:13
  • 1
    You can avoid those situations by placing beanstalkd behind a firewall or in a private network. DigitalOcean (for example) offers such a service where you have a private network IP address which can be accessed only from servers of the same location. We've been using beanstalkd in our company for more than a year, and we haven't had any of those issues yet. – GiamPy May 24 '16 at 09:14
  • I see, but what if the producer was a page called index.php, where when someone entered it, a job would be sent to the queue. In this situation, wouldn't the server have to be an open network? Now I assume that a firewall designed specifically for the port where beanstalkd runs would be sufficient, though I have no idea what is done in practice or if that would be enough. – Webeng May 24 '16 at 09:17
  • Oh and I'm open to anyone answering that question (http://stackoverflow.com/questions/37408325/beanstalkd-pheanstalk-security-issue) and giving a green checkmark – Webeng May 24 '16 at 09:19
  • I have added some alternatives to self-hosted ones. – GiamPy May 24 '16 at 09:55
-1

A good way to send a large amount of emails at a fast pace is to have a lot of worker scripts doing the job instead of 1 php page (GiamPy gave a good example for one of the ways that can be done and I won't mention it since I don't want to be redundant).

One simple (though somewhat hacky) option is: for you to make 20 php scripts in a file. You could name them mailer1.php, mailer1.php, ..., mailer20.php. Then, you could create a folder called mail and put two files inside:

mail/config.txt

and

mail/email.txt

Inside mail/config.txt, you would include the following lines of text:

T
15

where the first line has a T for TRUE meaning you want the mailers to send the mail out as fast as they can in intervals of 15 seconds each. You can obviously change the interval time as well to whatever you like.

And in mail/email.txt you would have the complete email you want to send

After having done all that you make the mailer files. You can make 1 first, write the code, and then copy paste it 19 times to have 20 scripts in total. The code inside could look something like this:

<?php

$pathconfig = "mail/config.txt";
$pathemail = "mail/email.txt";

$email = file_get_contents($pathemail);//now you have the email saved
$filehandleconfig = fopen($pathconfig, "r");
$bool = trim(fgets($pathconfig));
$sleeptime = (integer) trim(fgets($pathconfig));
fclose($filehandleconfig);

while ($bool === 'T')
{
  //... code that sends the email

  //recheck if 'T' is still 'T':
  $filehandleconfig = fopen($pathconfig, "r");
  $bool = trim(fgets($pathconfig));
  fclose($filehandleconfig);

  sleep($sleeptime);
}


?>

So what the previous code would basically do is extract the email that needs to be sent at the beginning, and also extract the time it will sleep after sending an email, and if it should continue to send emails.

What that means is that the mail/config.txt file is your controlpanel, and if you change 'T' to be anything else that 'T' (like 'F' for instance), then all the scripts will terminate.

The downside to this option is that it's a bit hacky, though the upside is that it can be developed in a matter of minutes.

Webeng
  • 7,050
  • 4
  • 31
  • 59
  • I'd personally rather just use cronjobs in that case, your alternative method is *reeeaally* hacky! :) – GiamPy May 24 '16 at 09:49
  • @GiamPy it is hacky hahah, I'm just putting it out there because I like to brainstorm. Sometimes far out ideas lead to better ones. yolo. Also having a list of options can benefit future readers in gaining a more `complete` understanding I suppose. – Webeng May 24 '16 at 09:52