NodeJS发送延迟的电子邮件

时间:2017-02-04 17:03:28

标签: javascript node.js express nodemailer

我正在使用Nodemailer在我的NodeJS / 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!' });
    });
  }
}); 

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

2 个答案:

答案 0 :(得分:4)

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

但是您的代码存在问题:您在发送200 - &#39;已发送的消息之前等待邮件程序成功。对用户的回应。叫我疯子,但我很确定用户不会盯着浏览器窗口看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
    );
  }
}); 

但是这个解决方案存在许多可能的缺陷。如果您预计该端点上的流量很大,您最终可能会遇到许多会占用堆栈的预定回调。此外,如果出现问题,用户当然无法知道。

如果这是一个重大/严肃的项目,请考虑使用该cronjob软件包或使用外部存储机制,您可以对此进行排队&#34;待定&#34;消息(Redis会做,而且它非常简单),并有一个不同的进程从那里读取任务并执行电子邮件发送。

编辑:在代码中看到了更多内容。

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

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

3)如果您仍想在单个Node.js应用中执行此操作,而不是在每次请求此端点时安排电子邮件,您最好存储电子邮件数据(从,到,主题, body) somewhere 并每隔20分钟安排一个函数,它将获取所有待处理的电子邮件,逐个发送,然后重新安排自己在20分钟后重新运行。这将使您的内存使用率降低。服务器崩溃仍会导致所有电子邮件丢失,但如果您将REDIS添加到混合中,那么您可以在应用启动时直接从REDIS获取所有待处理的电子邮件。

对于答案可能太多了,抱歉,如果不需要的话! :)

答案 1 :(得分:2)

我认为CharlieBrown的答案是正确的,因为我在阅读这个问题时脑子里有两个答案,我感谢他简化了我的答案,成为他的替代品。

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

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

根据您的偏好和需求,我认为这个答案或CharlieBrown都应该足够了。