NodeJS延迟发送电子邮件

ron*_*yrr 2 javascript node.js express nodemailer

我正在使用NodemailerNodeJS / Express服务器中发送邮件。我不想直接发送邮件,而是要等待20分钟才能发送邮件。我认为这比直接发送邮件更具个性。

但是我不知道如何实现这一目标。我想我不需要像这样的NodeCron程序包之类的NodeJS cronjob之类的东西,还是吗?

router.post('/', (req, res) => {
    const transporter = nodemailer.createTransport(smtpTransport({
      host: 'smtp.gmail.com',
      port: 465,
      auth: {
          user: 'noreply@domain.nl',
          pass: 'pass123'
      }
    }));

    const mailOptions = {
      from: `"${req.body.name}" <${req.body.email}>`,
      to: 'info@domain.nl',
      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!' });
    });
  }
}); 
Run Code Online (Sandbox Code Playgroud)

我的路由器如下图所示。因此,如果调用post,我希望此请求等待20分钟。我不想执行一次cronjob,而是只执行一次,但有一点延迟。有关如何执行此操作的任何建议?

Cha*_*own 6

好吧,有些人可能会来这里告诉您使用外部队列系统,等等。但是您可以简单地使用普通的旧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: 'noreply@domain.nl',
          pass: 'pass123'
      }
    }));

    const mailOptions = {
      from: `"${req.body.name}" <${req.body.email}>`,
      to: 'info@domain.nl',
      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
    );
  }
}); 
Run Code Online (Sandbox Code Playgroud)

但是,此解决方案可能存在许多缺陷。如果您期望该终结点计算机上的流量很大,则可能会遇到许多计划中的回调,这些回调将占用堆栈。此外,如果出现故障,用户当然也不会知道。

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

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

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

2)除了上述问题之外,如果您的服务器崩溃了,将永远不会发送电子邮件。

3)如果您仍想在单个Node.js应用中执行此操作,则最好将电子邮件数据(从,到,主题,正文)存储在某个地方并安排时间,而不是在对该端点的每个请求上安排电子邮件该功能每20分钟发送一次,该功能将获取所有待处理的电子邮件,一次将其发送出去,然后重新安排自身以在20分钟后重新运行。这将使您的内存使用率较低。服务器崩溃仍然会使所有电子邮件丢失,但是,如果将REDIS添加到组合中,则可以在应用启动时简单地从REDIS中获取所有待处理的电子邮件。

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


Laj*_*pad 2

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

setTimeout实际上是一个好主意,但它有一个缺点:如果有任何原因停止服务器代码(服务器重新启动、模块安装、文件管理等),您的回调将安排在 s time 参数的setTimeout末尾将不会被执行,并且某些用户将不会收到电子邮件。

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

我认为这个答案或查理布朗的答案应该足以满足您的需求,具体取决于您的喜好和需求。