我正在使用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我只想执行一次帖子,但有一点延迟。有关如何做到这一点的任何建议吗?
答案 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都应该足够了。