NodeJS 延迟发送电子邮件
NodeJS sending e-mails with a delay
我正在使用 Nodemailer 在我的 NodeJS/Express 服务器中发送邮件。我不想直接发送邮件,而是想等 20 分钟再发送邮件。我认为这比直接发送邮件感觉更个性化。
但我不知道如何实现。我想我不需要像这样的 NodeJS cronjob 这样的东西 NodeCron 包,或者我需要吗?
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 只执行一次 post,但有一点延迟。有关如何执行此操作的任何建议?
有些人可能会来这里告诉您使用外部队列系统和 bla bla...但您可以简单地使用普通的旧 Javascript 将发送 20*60*1000 毫秒安排到未来开始做事。 :)
但是您的代码存在问题:您在等待邮件程序成功,然后再向用户发送 200 - 'Message sent' 响应。叫我疯子,但我很确定用户不会盯着浏览器 window 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 包或使用外部存储机制,您可以在其中对 "pending" 消息进行排队(Redis 可以做到,而且非常简单),并且有一个不同的从那里处理读取任务并执行电子邮件发送。
编辑:在您的代码中看到了更多内容。
1) 您可能不需要在 POST 处理程序中创建新的 transport
,在外部创建它并重新使用它。
2) 除了上述问题,如果您的服务器崩溃,将永远不会发送电子邮件。
3) 如果您仍想在单个 Node.js 应用程序中执行此操作,而不是为每个对此端点的请求安排一封电子邮件,您最好存储电子邮件数据(从、到、主题,正文)某处 并每 20 分钟安排一个函数,该函数将获取所有待处理的电子邮件,一个接一个地发送,然后在 20 分钟后重新安排到 re-run。这将使您的内存使用率保持在较低水平。服务器崩溃仍然会丢失所有电子邮件,但如果您将 REDIS 添加到组合中,那么您可以在应用程序启动时从 REDIS 中简单地获取所有待处理的电子邮件。
答案可能太多了,如果不需要,抱歉! :)
我认为 CharlieBrown 的回答是正确的,因为我在阅读问题时脑子里有两个答案,我感谢他简化了我的答案以替代他的答案。
setTimeout
其实是个好主意,但它有一个缺点:在有任何理由停止服务器代码(服务器重启、模块安装、文件管理等)的情况下你的回调计划在 setTimeout
的时间参数结束时将不会执行,部分用户将不会收到电子邮件。
如果上述问题是 serious-enough,那么您可能希望将计划发送的电子邮件存储在数据库或 Redis 中,并使用 cron 作业定期检查电子邮件集并发送电子邮件(如果有)有一些。
我认为这个答案或 CharlieBrown 的答案应该足以满足您的需求,具体取决于您的喜好和需要。
我正在使用 Nodemailer 在我的 NodeJS/Express 服务器中发送邮件。我不想直接发送邮件,而是想等 20 分钟再发送邮件。我认为这比直接发送邮件感觉更个性化。
但我不知道如何实现。我想我不需要像这样的 NodeJS cronjob 这样的东西 NodeCron 包,或者我需要吗?
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 只执行一次 post,但有一点延迟。有关如何执行此操作的任何建议?
有些人可能会来这里告诉您使用外部队列系统和 bla bla...但您可以简单地使用普通的旧 Javascript 将发送 20*60*1000 毫秒安排到未来开始做事。 :)
但是您的代码存在问题:您在等待邮件程序成功,然后再向用户发送 200 - 'Message sent' 响应。叫我疯子,但我很确定用户不会盯着浏览器 window 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 包或使用外部存储机制,您可以在其中对 "pending" 消息进行排队(Redis 可以做到,而且非常简单),并且有一个不同的从那里处理读取任务并执行电子邮件发送。
编辑:在您的代码中看到了更多内容。
1) 您可能不需要在 POST 处理程序中创建新的 transport
,在外部创建它并重新使用它。
2) 除了上述问题,如果您的服务器崩溃,将永远不会发送电子邮件。
3) 如果您仍想在单个 Node.js 应用程序中执行此操作,而不是为每个对此端点的请求安排一封电子邮件,您最好存储电子邮件数据(从、到、主题,正文)某处 并每 20 分钟安排一个函数,该函数将获取所有待处理的电子邮件,一个接一个地发送,然后在 20 分钟后重新安排到 re-run。这将使您的内存使用率保持在较低水平。服务器崩溃仍然会丢失所有电子邮件,但如果您将 REDIS 添加到组合中,那么您可以在应用程序启动时从 REDIS 中简单地获取所有待处理的电子邮件。
答案可能太多了,如果不需要,抱歉! :)
我认为 CharlieBrown 的回答是正确的,因为我在阅读问题时脑子里有两个答案,我感谢他简化了我的答案以替代他的答案。
setTimeout
其实是个好主意,但它有一个缺点:在有任何理由停止服务器代码(服务器重启、模块安装、文件管理等)的情况下你的回调计划在 setTimeout
的时间参数结束时将不会执行,部分用户将不会收到电子邮件。
如果上述问题是 serious-enough,那么您可能希望将计划发送的电子邮件存储在数据库或 Redis 中,并使用 cron 作业定期检查电子邮件集并发送电子邮件(如果有)有一些。
我认为这个答案或 CharlieBrown 的答案应该足以满足您的需求,具体取决于您的喜好和需要。