对后台php使用cron作业
嗨,我正在尝试使用PhpMailer为通知系统发送多封电子邮件。为了避免用户提交表单时出现时间延迟问题,我决定将所有存储在mysql表中的电子邮件排入队列,然后使用cron作业运行后台脚本发送队列。这是我使用cron job运行的脚本对后台php使用cron作业,php,mysql,Php,Mysql,嗨,我正在尝试使用PhpMailer为通知系统发送多封电子邮件。为了避免用户提交表单时出现时间延迟问题,我决定将所有存储在mysql表中的电子邮件排入队列,然后使用cron作业运行后台脚本发送队列。这是我使用cron job运行的脚本 include('config/config.php'); require_once(ROOT_PATH.'/helper/phpmailer/PHPMailerAutoload.php'); $mail = new PHPMailer; $
include('config/config.php');
require_once(ROOT_PATH.'/helper/phpmailer/PHPMailerAutoload.php');
$mail = new PHPMailer;
$mail->isSMTP();
$mail->SMTPAuth = true;
$mail->isHTML(true);
$mail->Host = SSE_HOST;
$mail->Username = SSE_USER;
$mail->Password = SSE_PASSWORD;
$mail->SMTPSecure = SSE_SECURE;
$mail->Port = 465;
$mail->SetFrom(SSE_FROM, SSE_FROM_NAME);
$mail->addReplyTo(SSE_REPLY, 'Invia Risposta');
$result = mysqli_query($conn, "SELECT queue_emails_email, queue_emails_subject, queue_emails_body FROM queue_emails WHERE queue_emails_status = '1' " );
foreach ($result as $row) {
$mail->addAddress($row['queue_emails_email']);
$subject = $row['queue_emails_subject'];
$mail->Subject = $subject;
$mail->MsgHTML($row['queue_emails_body']);
if (!$mail->send()) {
echo "Mailer Error (" . str_replace("@", "@", $row["queue_emails_email"]) . ') ' . $mail->ErrorInfo . '<br />';
break; //Abandon sending
} else {
echo "Message sent to :" . $row['queue_emails_email'] . ' (' . str_replace("@", "@", $row['queue_emails_email']) . ')<br />';
//Mark it as sent in the DB
mysqli_query($conn, "UPDATE queue_emails SET queue_emails_status = '0' WHERE queue_emails_email = '" .
mysqli_real_escape_string($conn, $row['queue_emails_email']) . "'");
}
// Clear all addresses and attachments for next loop
$mail->clearAddresses();
}
现在我的问题是:如果我收到多条不同正文但电子邮件地址相同的邮件,那么如果cron作业进程被中断会发生什么?我已经使用mailtrap在本地主机上进行了测试,它似乎工作得很好,但我想知道的是,这种方法在实时服务器上是否可行。我认为我的队列不会超过200-300封电子邮件。非常感谢您的帮助很好,您的表包含一个单独的唯一ID,因此您不需要对数据库结构进行任何更改。你只需要得到你的ID值并使用它。修改您的
选择,如下所示:
$result = mysqli_query($conn, "SELECT queue_emails_id, queue_emails_email,
queue_emails_subject, queue_emails_body FROM queue_emails WHERE
queue_emails_status = '1' " );
然后,在以后进行更新时,请使用以下命令:
mysqli_query($conn, "UPDATE queue_emails SET queue_emails_status = '0'
WHERE queue_emails_id = '" . intval($row['queue_emails_id']) . "'");
就这么简单。现在,您可以确保将零状态设置为正确的消息,无论队列中有多少消息发送到同一地址,您都不会丢失消息
顺便说一下,如果队列中有多个电子邮件地址,您的代码将丢失相同电子邮件地址的消息。无论cron
作业是否完成或中断,它都会将它们设置为已发送。假设您有以下消息:
to: john@yahoo.com
to: john@yahoo.com
to: peter@hotmail.com
to: mike@gmail.com
to: john@yahoo.com
您的查询将返回此列表,您将开始发送消息并将第一条消息发送到john@yahoo.com. 如果$mail->send()
返回OK,您将更新所有邮件john@yahoo状态为0时。因此,john将只收到一条消息,第2条和第5条消息将丢失(不发送给john)
在您的问题中,您说队列中可能有200-300条消息。我不知道你多久调用一次这个代码,我会在不超过5分钟的时间调用它,这样我的用户就可以按时收到他们的邮件,但如果太频繁,那就意味着你每天会收到很多电子邮件。考虑一下,您是否需要将它们全部保存在状态为0的表中,或者您可以删除它们以节省空间。为什么不在表中添加一个ID列,并根据此ID而不是电子邮件地址进行更新?您好,谢谢您的快速回答。抱歉,我不明白您添加id(是用户id)是什么意思?在您的DB表queue\u emails
中,添加一个可以自动递增的列,它将是您必须发送的每封电子邮件的唯一id。然后在此基础上,您可以使用queue\u emails\u status='0'
更新您刚刚发送的电子邮件,但发送给此用户(地址)的所有其他邮件将保留在队列中。如果所有的表都填写了相同的电子邮件地址,这无关紧要。好的,我现在明白了,所以基本上我需要从更新队列\u emails SET queue\u emails\u status='0'中删除where子句。我已经有一个自动递增的队列\u emails\u id表。所以,通过这种方式,即使cron作业进程超时,它也应该从if离开的位置开始,是否正确?还有什么我可以实现的吗?我添加了$mail->SMTPKeepAlive=true;按照这里的建议对Phpmailer配置不,在没有WHERE子句的情况下执行UPDATE不是一个好主意:)您将只发送一封电子邮件并更新整个表。我的意思是将WHERE子句更改为类似于UPDATE。。。设置其中queue_email_id=“$last_email_id”代码>比较您确定唯一的内容,而不是可能不唯一的地址。例如,在网上商店中,您将向新用户发送两条后续消息-一条用于成功注册,另一条用于下单。很高兴他收到了这两封信:)嗨,都铎,非常感谢你的帮助,我稍后会测试一下,让你知道。考虑到您的考虑,我想我会每15分钟调用一次代码,可能是为了避免cron重叠(我正在谷歌上搜索更多关于它的信息),然后我的计划是运行另一个cron,可能是每天一次,以删除所有status=0的行,并以这种方式保持数据库干净
to: john@yahoo.com
to: john@yahoo.com
to: peter@hotmail.com
to: mike@gmail.com
to: john@yahoo.com