问题
I want to make a newsletter feature in my application. I need to send emails about 5000-6000 after I create a newsletter. When the newsletter is published it will create an email queue which will be stored in the database. Since it requires a lot of time I need to run it in the background. So I made a command to send the mail using YiiMailer and the email queue from the database.
My command is working, but it is getting terminated after some time without completing the job. Also I need to run it in the background, but now it is not. Any help appreciated.
My controller
public function actionSend(){
$command = new MailQueueCommand("test", "test");
$command->run(null);
$this->render('index');
}
My MailQueueCommand.php
<?php
class MailQueueCommand extends CConsoleCommand
{
public function run($args)
{
$criteria = new CDbCriteria(array(
'condition' => 'success=:success AND attempts < max_attempts',
'params' => array(
':success' => 0,
),
));
$queueList = EmailQueue::model()->findAll($criteria);
/* @var $queueItem EmailQueue */
foreach ($queueList as $queueItem)
{
$mail = new YiiMailer();
$mail->IsSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = 'xxxx';
$mail->Password = 'xxxxx';
$mail->SMTPSecure = 'tls';
$mail->Port = 587;
$mail->setFrom('exmampl@gmail.com', 'Name');
$mail->setTo($queueItem->to_email);
$mail->setSubject($queueItem->subject);
$mail->setBody($queueItem->message, 'text/html');
if ($this->sendEmail($mail))
{
$queueItem->attempts = $queueItem->attempts + 1;
$queueItem->success = 1;
$queueItem->last_attempt = new CDbExpression('NOW()');
$queueItem->date_sent = new CDbExpression('NOW()');
$queueItem->save();
}
else
{
$queueItem->attempts = $queueItem->attempts + 1;
$queueItem->last_attempt = new CDbExpression('NOW()');
$queueItem->save();
}
}
}
private function sendEmail($mail)
{
$sendStatus = false;
if ($mail->send() > 0)
$sendStatus = true;
return $sendStatus;
}
}
?>
回答1:
Based on my experience in sending email notifications
The reason usually your mail job gets stopped in between is because usually there is time limit on php execution, and sending 5000,6000 mails will take a long time . Using a service like Amazon SES you can send 5 per second so that is like 1200 seconds or 20 mins ..most mail servers will give you similar or slower speeds, Typical php(CLI) execution time is 30 seconds, which is where your problem is.
What I do is send only 100-200 mails per batch, and run the console command through cron every one minute.It will be slightly slower but you will get there.
$criteria = new CDbCriteria(array(
'condition' => 'success=:success AND attempts < max_attempts',
'params' => array(
':success' => 0,
),
'limit'=>200,
));
Set up cron using crontab -e
* * * * * <path-to-yii>protected/yiic MailQueueCommand run &> /dev/null
Hope this helps..
Note: if actually using SES this won't be a problem as they queue all your requests and send them 5 per second, and there is no limit on queing really.
Note: cron is not like calling from command line you might have unexpected issues setting it up.
来源:https://stackoverflow.com/questions/20396147/send-emails-as-a-background-process