2017-02-04 143 views
1

我使用Nodemailer在我的NodeJS/Express服务器中发送邮件。我不想直接发送邮件,而是希望在发送邮件之前等待20分钟。我认为这样直接发送邮件会更有个性。NodeJS发送延迟电子邮件

但我不知道如何做到这一点。我想我不需要像这个NodeCron包这样的NodeJS cronjob,或者我需要?

router.post('/', (req, res) => { 
    const transporter = nodemailer.createTransport(smtpTransport({ 
     host: 'smtp.gmail.com', 
     port: 465, 
     auth: { 
      user: '[email protected]', 
      pass: 'pass123' 
     } 
    })); 

    const mailOptions = { 
     from: `"${req.body.name}" <${req.body.email}>`, 
     to: '[email protected]', 
     subject: 'Form send', 
     html: `Content` 
    }; 

    transporter.sendMail(mailOptions, (error, info) => { 
     if (error) res.status(500).json({ responseText: error }); 
     res.status(200).json({ responseText: 'Message send!' }); 
    }); 
    } 
}); 

我的路由器看起来像上图所示。所以如果发布帖子,我希望这个请求等待20分钟。而不是使用cronjob,我只想执行一次该帖子,但有点延迟。有关如何做到这一点的任何建议?

回答

2

我认为查理布朗的答案是正确的,因为在阅读问题时我在脑海中有两个答案,所以我感谢他简化了我的答案,成为他的替代答案。

setTimeout实际上是一个好主意,但它有一个缺点:在有任何理由停止服务器代码(服务器重启,模块安装,文件管理等)的情况下)您的回调计划在setTimeout的时间参数结束时不会执行,并且一些用户不会收到电子邮件。

如果上述问题严重不足,那么您可能希望将定期发送的电子邮件发送到数据库或Redis中,并使用cron作业定期检查电子邮件设置并在发送电子邮件时发送电子邮件。

我认为,这个答案或查理布朗的应该适合你,这取决于你的喜好和需求。

+0

嘿拉霍斯,你还记得我的想法,我刚刚更新了我的答案,包括同样的担忧:) – CharlieBrown

+0

@CharlieBrown是的,看起来我们觉得在这里:) –

+0

非常感谢与@CharlieBrown一起指出这一点!我会去解决这个问题,标记就是我接受的答案。 – ronnyrr

3

那么一些人可能会来这里告诉你使用外部队列系统和bla bla ...但是你可以简单地使用普通的旧Javascript来安排发送20 * 60 * 1000毫秒到未来以开始工作。 :)

但是,您的代码存在问题:在向用户发送200'消息发送'响应之前,您正等待邮件程序成功。打电话给我是一个疯子,但我很肯定用户不会在20分钟内盯着浏览器窗口,所以你可能必须尽快回答,然后安排邮件。修改您的代码:

router.post('/', (req, res) => { 
    const DELAY = 20*60*1000 // min * secs * milliseconds 
    const transporter = nodemailer.createTransport(smtpTransport({ 
     host: 'smtp.gmail.com', 
     port: 465, 
     auth: { 
      user: '[email protected]', 
      pass: 'pass123' 
     } 
    })); 

    const mailOptions = { 
     from: `"${req.body.name}" <${req.body.email}>`, 
     to: '[email protected]', 
     subject: 'Form send', 
     html: `Content` 
    }; 

    res.status(200).json({ responseText: 'Message queued for delivery' }); 

    setTimeout(function(){ 
     transporter.sendMail(mailOptions, (error, info) => { 
     if (error) 
      console.log('Mail failed!! :(') 
     else 
      console.log('Mail sent to ' + mailOptions.to) 
     }), 
     DELAY 
    ); 
    } 
}); 

但是,此解决方案存在许多可能的缺陷。如果你期望在该端点上有很大的流量,那么最终可能会有很多预定的回调会吃掉堆栈。另外,如果某件事失败,用户当然不会知道。

如果这是一个大的/严重的项目,可以考虑使用该cronjob包或使用外部存储机制,在这里你可以对这些“待处理”消息进行排队(Redis会这样做,而且这很简单)并且有不同的进程读取任务从那里执行电子邮件发送。

编辑:在你的代码上看到了更多的东西。

1)您可能不需要在POST处理程序中创建新的transport,在外部创建它并重新使用它。

2)除了上述问题,如果你的服务器崩溃了,将不会发送任何电子邮件。

3)如果你仍然想在一个Node.js应用程序中完成它,而不是每次请求到这个端点都安排一封电子邮件,那么你最好存储电子邮件数据(从,到,subject,body )某处并且每20分钟计划一次函数,该函数将获得所有待处理的电子邮件,逐个发送它们,然后重新安排自己重新运行20分钟后重新运行。这会让你的内存使用率降低。服务器崩溃仍然会使所有电子邮件丢失,但是如果您将REDIS添加到组合中,那么您可以在应用程序启动时从REDIS获取所有未决电子邮件。

可能太多的答案,对不起,如果它不需要! :)

+0

感谢您的完整回复。因为这是一个非常严肃的项目,我认为'setTimeout'不是一个可靠的选项。我会去外部保存数据,并使用cronjob每20分钟左右检查一次。感谢您指出Redis,但我认为MongoDB对我来说会更好一些:)。 PS:谢谢你的编辑提示。 1)被覆盖了,这被简化了。其他与主要问题有关,但无论如何感谢。 – ronnyrr