简体   繁体   English

用PHP向大量用户发送电子邮件的最有效方法是什么?

[英]What is the most efficient way to email a lot of users in PHP?

My website sends an email out to my user's whenever someone PM's (Private Message) them. 每当有人PM(私人消息)向我的用户发送电子邮件时,我的网站就会向他们发送电子邮件。 It says something along the lines of "Someone just sent you a message on SITE NAME, login to view it". 上面写着“有人刚在SITE NAME上给您发送了一条消息,请登录查看它”。

At the moment my site isn't very popular so my current way of doing this hasn't been a problem performance wise: 目前,我的网站不是很受欢迎,因此我目前的操作方式还不是性能问题:

    // code that sends pm here...

    // code that stores pm in messages table here...

    // notify user by emailing them right away
    mail($user_email, $subject, $message);

Basically every time a PM is sent, the mail function is executed and the message is sent right there on the spot. 基本上,每次发送PM时,都会执行邮件功能并将消息立即发送到现场。 So for every 100 messages sent the mail() gets called 100 times. 因此,每发送100条消息,mail()就会被调用100次。

I am anticipating my site getting more popular and with more users come more PM's so I think my current way of doing it would become a performance nightmare. 我预计我的网站将会越来越受欢迎,并且随着更多的用户出现更多的PM,因此我认为我目前的做法将成为一场性能噩梦。 So I was thinking of doing it this way instead : 所以我当时想这样做:

// get the last message that was accounted for by the last cron
$query = mysql_query(" SELECT `last_checked_id` FROM `settings` ");
$last_checked_id = mysql_fetch_array($query);


$user_emails = array();

// get all messages that were added to this table since the last time this cron ran
$query = mysql_query(" SELECT `recipient_id`, `message_id` FROM `messages` WHERE `message_id` > '$last_checked_id' ");

$i = 0;
while($row = mysql_fetch_array($query)) {

    if($i == 0) {
        // set this as the last message processed
        mysql_query(" UPDATE `settings` WHERE `last_checked_id` = '". $row['message_id'] ."' ");
    }

    // only put this user in the to email list if he hasn't been added already (since there can be multiple messages for the same user but we need to notify him only once) 
    if(!in_array($row['recipient_id'], $user_emails)) {
        array_push($user_emails, $row['recipient_id']);     
    }
}
$i++;

// send email to all users at one
mail(implode(',', $user_emails), $subject, $message);

I can set this script up as a cron and have it run every hour. 我可以将此脚本设置为cron并使其每小时运行一次。 All the emails are sent in one go with the mail function being called only once. 一次性发送所有电子邮件,而邮件功能仅调用一次。 The only drawback is user's aren't notified right away when they recieve a PM, but once within the hour. 唯一的缺点是用户在收到PM时不会立即收到通知,而是在一个小时内收到通知。 But that's not a big deal and something I can live with. 但这不是什么大问题,我可以接受。

My questions are: 我的问题是:

  • is the cron method significantly better performance wise or is the increase negligable cron方法在性能上明显更好,还是可以忽略不计?
  • is this the way most big sites do it? 这是大多数大型网站的做法吗? or is there a better way, some established library maybye? 还是有更好的方法,建立一些图书馆呢?

Thanks. 谢谢。

You can insert mails a mysql table (emailoutgoing) 您可以在mysql表中插入邮件(emailoutgoing)

And with a cron job running every "3" minutes, you can get unsent (100?) emails from table, send and mark row as sent. 并且,每隔“ 3”分钟运行一次cron作业,您可以从表中收到未发送的(100?)电子邮件,发送并将行标记为已发送。

If I understood correctly you would be sending exactly same email to every person? 如果我理解正确,您将向每个人发送完全相同的电子邮件吗? In that case you should use bcc field for email adresses or everybody would see other recipients but in that case you can have problems with anti-spam engines that might disregard your emails since they will not see their user as a recipient of email (not located in to or cc field ). 在这种情况下,您应该将密件抄送字段用于电子邮件地址,否则每个人都会看到其他收件人,但是在这种情况下,反垃圾邮件引擎可能会出现问题,因为它们不会将其用户视为电子邮件的收件人(未找到),因此可能会忽略您的电子邮件在to或cc字段)。

But you should really think about sending personalized email for each user (they will be much more eager if you add sneek preview into who sent a message and/or part of a message) 但是您应该真正考虑为每个用户发送个性化电子邮件(如果您在发送消息的人和/或消息的一部分中添加时髦的预览,他们会更加渴望)

Firstly, read the link in Mike B's comment. 首先,请阅读Mike B评论中的链接。

Secondly, your code has some entertaining failure modes - it could fail, mark all mails as sent, and nobody would ever know. 其次,您的代码有一些有趣的失败模式-它可能会失败,将所有邮件标记为已发送,并且没人会知道。 A key thing about CRON and other unattended processes (including websites in general) is that you need to know when things go wrong. 有关CRON和其他无人值守的流程(包括一般的网站)的关键是,您需要知道何时出错。 I'd consider putting the "update" statement right at the end, after you've sent the mail. 发送邮件后,我考虑将“ update”语句放在最后。 Put in some kind of logging so you can keep track of what's going on. 进行某种日志记录,以便您可以跟踪发生的情况。

Thirdly, please don't send this email to all these people in the "to" field - as Miro says, it's spam bait, but it also exposes users to more information than they should probably have - they know the email addresses of random other users of your site who happen to have had a PM within an hour of them. 第三,请不要将此电子邮件发送给“收件人”字段中的所有这些人-正如Miro所说的,这是垃圾邮件诱饵,但它也向用户提供了比他们应有的更多信息-他们知道其他人的电子邮件地址您网站的用户在一个小时内碰巧遇到了PM。 If you're building a dating site or social network, that's almost certainly going to make people angry. 如果您要建立一个约会网站或社交网络,那几乎肯定会让人们生气。

Finally, other sites I've worked on that had similar requirements tended to have an "events" table, which was monitored by daemon/service style processes. 最后,我处理过的其他具有类似要求的站点都趋向于有一个“事件”表,该表由守护程序/服务风格流程进行监视。 The daemon would make smart decisions about what to do. 守护程序将做出明智的决定。 We designed the solution to be suitable for running on multiple threads and even multiple machines, though in practice never needed this. 我们设计的解决方案适合在多线程甚至多台机器上运行,尽管实际上从不需要。

So, you might have an "events" table as follows: 因此,您可能有一个“事件”表,如下所示:

eventID    eventDate    eventType     eventStatus     eventMeta
-------------------------------------------------------------------
1          1 Feb 2012        PM           NEW         <from>bob@banana.com</from><to>alice@passionfruit.com</to>
2          1 Mar 2012        PM           COMPLETE    <from>fred@pear.com</from><to>jennifer@avocado.com</to> 

The daemon constantly scans for records where eventStatus is NEW, sets them to "in progress", deals with them, and then sets the status to complete. 守护程序会不断扫描eventStatus为NEW的记录,将它们设置为“进行中”,进行处理,然后将状态设置为完成。

This allows you to see what's going on in the system - if a record is "in progress" for more than a second, something is broken. 这使您可以查看系统中正在发生的事情-如果记录“正在进行中”超过一秒钟,则说明某些内容已损坏。 If the number of "NEW" records keeps growing, and the number of "complete" records doesn't, something is broken. 如果“ NEW”记录的数量持续增长,而“ complete”记录的数量没有增长,则说明出现了问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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