如何安排电子邮件发送

Posted

技术标签:

【中文标题】如何安排电子邮件发送【英文标题】:How to schedule emails to send out 【发布时间】:2011-02-04 00:37:44 【问题描述】:

使用 php,我有一个查询通过我的数据库查找在一天中的某些时间带有提醒触发器的待处理任务。我有一个每 10 分钟运行一次的 cronjob,并检查数据库中是否有“remind_me”字段设置为在接下来的 10 分钟内关闭的任何行。如果它确实找到了一些东西,那么将包含任务信息的电子邮件排队的最佳方式是什么?

我想我需要某种消息队列系统,但电子邮件部分是如何工作的?我是否需要另一个每分钟运行一次的 cronjob 来检查队列系统?

【问题讨论】:

@lucktaxi。我一直在思考这个问题,我想出了一个 PHP 解决方案来解决你的问题。此外,我将修改我的帖子以包含我现在正在使用的 Java 解决方案,如果你问我,这将非常酷;)。完成后我会使用 java 解决方案。 为什么你需要一个消息队列,只需要你已经拥有的 cron 脚本来实际发送电子邮件?如果需要精确到分钟,只需每分钟运行一次 cron 作业 因为如果我有 5 封电子邮件都需要在上午 10:15 发送出去,我可以从队列中拉出一个 cron 作业,就像假设访问数据库一样。我不认为我想每分钟循环遍历表格。 【参考方案1】:

我们有一个类似的系统(这是一个 ASP.NET 应用程序,所以我们有使用内部调度程序运行它的服务......但细节并不重要)。我们有一个大型消息队列表,其中包含要发送的电子邮件数据、收件人地址和主题行(实际的电子邮件是从模板生成的)。我们系统的工作方式是,一旦填充了一行,我们就会立即触发一个发送任务,该任务收集所有待处理的电子邮件并发送它们。它尝试发送它们 3 次,如果失败,它们将进入失败的重发状态。我们有一个类似 cron 的作业,它每 5 分钟运行一次以清除任何失败的任务(很少会失败,如果它们在 99% 的情况下都是网络问题)。

【讨论】:

嗯嗯听起来很酷。我想我被困在的地方是如何在截止日期前“15 分钟”发送一封电子邮件。当然它不一定要精确,这是否是另一个每分钟运行的 cronjob 发挥作用的地方?每分钟运行的 cronjob 对服务器的影响有多大?只是好奇。【参考方案2】:

PHP解决方案

我对你的问题考虑了更多,这就是我想出的 PHP 解决方案。

#!/opt/lamp/bin/php 是我的 php 解释器的路径。你应该改变它 到您的路径或仅使用 php 运行它 -f scheduler.php

scheduler.php

#!/opt/lampp/bin/php
<?php
// For testing purpose I set this to 5 seconds. You should set it to 600.
$time = 5;

while (true) 
    /*  
    let's assume you store the emails scheduled from the database in this
    in memory array.
    */
    $array = array( 
        "Message to run last", #message which is scheduled last.
        "Message to run after first message",
        "Message to run immediately", #message which is scheduled first.
    );

    $message = array_pop($array);    
    while ($message != NULL) 
            echo $message . "\r\n";
            /* 
            For testing purpose I am just simply echoing out messages.
            In here you should sent mails using for exmample
            http://php.net/manual/en/function.mail.php
            */
            $message = array_pop($array); // Get next message.
    

    /*
    sleep $time. This is the "cron" part of your problem.
    */
    sleep($time); 

您应该从 bash 脚本中运行此脚本以查看它的作用。此外,代码已经很好地记录在案。该脚本应该永远运行(在后台)。

Java 解决方案

这也不是仅 PHP 的解决方案,但我认为这将比我提出的 PHP 解决方案更好地扩展。我仍在努力,但我喜欢我目前的想法。

Google App Engine 解决方案

我知道这不是 PHP 解决方案,但是当您无法安装消息队列时,我认为 Google App Engine 是最好的解决方案。 当我看到这个 video introduction 从 Brett Slatkin 到使用 Python SDK 的谷歌应用引擎时,我被卖给了谷歌应用引擎。它只需要您 10 分钟的时间,您将学习如何创建基本的留言簿并将其部署到云中。如果有兴趣,我将在下面尝试解释您需要在 Google 的 App Engine 上执行此操作的部分。


我想我需要一些信息 排队系统

也许您可以使用 google 应用引擎的 taskqueue 来 qeueu 任务。任务队列甚至有一个eta,您可以将其设置为在特定时间运行。谷歌应用引擎有一个慷慨的free quota。您可以每天免费为任务添加100,000 队列。

但是电子邮件部分是如何工作的

我会为此使用谷歌应用引擎。您可以使用谷歌应用引擎的mail 服务。它还有一个慷慨的免费配额(每天 2000 名收件人)。我建议你只调用队列中的邮件 api 来发送消息。

【讨论】:

同意,我没有对你投反对票。 :-P ...我正在学习 Ruby,因此可以选择进行排队。 我运行自己的 VPS,因此这些工具可能会起作用。我不想重新发明***,但我发现有些工具有时过于复杂。我可能会将 PHP 留给应用程序,并使用“真正的”脚本语言来完成繁重的工作。 穿上火焰套装 是的,我喜欢你的想法。我想知道谁一直拒绝投票给你。 :-P 无论如何,我在后端运行 mongodb,我喜欢 redis,因为它的 key:value 方法。我可以使用 mongodb,但我很想尝试 redis。【参考方案3】:

您希望多久发送一次电子邮件?如果它正在发生(您现有的 cronjob 发现它的那一刻,即每 10 分钟一次),您可以使查找提醒我标志的脚本执行以下操作:

1 - 添加对在数组中找到标志的每一行的引用,例如

$reminders = array(1, 3, 212);

数组中的每个元素都引用了您的任务表的一个主键,这里我使用了“任务”。

2 - 数据库查找完成后,查看 $reminders 是否不为空,然后运行类似的查询

$query = "SELECT * FROM tasks WHERE id = '".implode(',', $reminders)."'";

获取所有特定于任务的数据

3 - 使用 mail 向您自己发送包含此数据的电子邮件。

这就是你要找的吗?

【讨论】:

仅在触发“remind_me_on”标志时发送电子邮件。即我有一个任务要在今晚@9PM 到期。提前15分钟给我发个提醒。所以在 8:45 它应该给我发一封电子邮件。如果我使用 5 分钟的间隔,它可以在我的 cronjob 搜索表格并在那一刻发送电子邮件的地方工作。我认为这将在小范围内起作用,但如果我决定将其公开,则绝对是一个消息队列。【参考方案4】:

我最近刚刚使用 PHP 和 mysql 编写了自己的解决方案来解决一个非常相似的问题。 本质上:cron 作业以设定的时间间隔运行脚本,该脚本检查数据库中的待处理作业、运行它们并删除作业。

这只是我需要做的,但可以修改它以在时间间隔内工作。 我编写了一个单独的 PHP 脚本来运行实际的工作(通讯系统),以使这种自动化更加有用。也就是说,我可以从它运行任何我想要的命令,我通过将实际命令的名称及其参数存储在 automator 脚本中来实现这一点。

exec("~/scripts/$row['command'] $row['args']");

允许我将参数存储到数据库中,以使我的时事通讯脚本更有用。您使用数组 $argv 来获取参数, $argv[0] 是脚本名称,参数依次跟随。

我将所有时事通讯信息存储在数据库中的一个单独的表中,该表按时间顺序对它们进行排序。其他重要的字段是电子邮件的主题和正文。然后,我只需将两个参数传递给 newsletter.php 以使其完全符合我的要求:通讯编号和订阅者编号(或全部)。

测试时间(10分钟前)可以用这样的方法完成(为了更容易理解,我过度简化了):

date_default_timezone_set('America/Denver');
$month=;//without leading zeros
$day=;//without leading zeros
$hour=;//24 hour without leading zeros
$min=;//needs leading zeros
if($month==date(n) and $day==date(j))
    if($hour==date(G))
        if(($min-date(i))<=10)
            //run command
        
    elseif(($hour-1)==date(g))
        if(($min-date(i))<=(-50))
            //run command
        
    

您需要将时区更改为您自己的时区,并以某种方式从数据库中提取日期和时间信息。 脚本的第二部分(运行一个小时的前 9 分钟安排的命令)未经测试,但我刚刚快速测试了第一部分。 希望这可以帮助。

【讨论】:

【参考方案5】:

如果你想做一个邮件队列系统,我建议你看看PEAR::Mail_Queue 和相关的教程。

您可以在 10 分钟脚本运行时将邮件排队,并通过 cron 作业每 10 分钟清空一次邮件队列。您还可以每分钟清空邮件队列,并在相关邮件的队列中设置“之前不要发送”时间。

或者,您可以每分钟运行一次检查脚本,检查过去十分钟内到期的提醒项目并立即发送邮件,这样就无需排队系统。

这可以通过记录您上次发送警报的时间来实现(这样您就不会错过任何一个,也不会两次发送警报)

希望对您有所帮助。

【讨论】:

以上是关于如何安排电子邮件发送的主要内容,如果未能解决你的问题,请参考以下文章

Mandrill 重新发送已发送的电子邮件,而不是重新安排

Laravel:检查是不是有新项目添加到 db 表并安排一个工作给用户发送电子邮件

如果我的 Google Cloud Scheduler 作业失败,如何发送电子邮件提醒?

如何在不影响 Node.JS 应用程序的情况下从后台异步发送大量电子邮件?

在 php 中安排电子邮件

Gmail现在支持安排电子邮件,如何使用gmail rest api工作,还是api支持此功能?