Nodemailer发送邮件频繁ETIMEDOUT:偶发成功但超时问题求助
Nodemailer邮件发送偶发成功、频繁超时(ETIMEDOUT)问题排查求助
问题概述
邮件仅能偶尔成功发送,多数情况下会卡在“Resolved”状态后触发超时(已设置超时时间),且频繁出现ETIMEDOUT错误。触发方式包括ReactJS站点按钮点击,以及用Thunder Client直接调用API,结果一致。控制台可见邮件最终发送成功但随后超时。
相关代码
创建Transporter的函数
const createTransporter = (serviceSettings) => { // Define which service to use // gmail = Use gmail's service (must have GmailSMTPUser and GmailSMTPAppPass setup) // ll = Use LumiereLabs's service const emailService = serviceSettings.use // Configure the transporter switch (emailService) { case "gmail": return nodemailer.createTransport({ service: 'gmail', auth: { user: serviceSettings.services.gmail.user, pass: serviceSettings.services.gmail.pass }, logger: true, debug: true, maxConnections: 5, // Maximum number of connections to keep in the pool maxMessages: 100, // Maximum number of messages to send per connection rateLimit: 10, // Maximum number of messages to send per second pool: true, // disable connection pooling connectionTimeout: 10000, // 10 seconds socketTimeout: 10000, // 10 seconds greetingTimeout: 5000 // 5 seconds }) break case "ll": return nodemailer.createTransport({ host: 'smtp.lumierelabs.org', port: 587, secure: false, // true for 465, false for others requireTLS: true, auth: { user: serviceSettings.services.ll.user, pass: serviceSettings.services.ll.pass }, tls: { rejectUnauthorized: false // if using self-signed certificates }, logger: true, debug: true, maxConnections: 5, // Maximum number of connections to keep in the pool maxMessages: 100, // Maximum number of messages to send per connection rateLimit: 10, // Maximum number of messages to send per second pool: true, // disable connection pooling connectionTimeout: 10000, // 10 seconds socketTimeout: 10000, // 10 seconds greetingTimeout: 5000 // 5 seconds }) break }
邮件发送处理函数
const sendEmail = async (mailOptions, successMessage, res, serviceSettings) => { let toasts = [] const transporter = createTransporter(serviceSettings) try { let info = await transporter.sendMail(mailOptions) // Send to notification toasts.push({ message: successMessage, object: { sentEmail: true }, type: 'success' }) // Send to console console.log('Email sent: ' + info.response) } catch (error) { // Send to notification toasts.push({ message: `Error sending mail: ${error}`, object: { sentEmail: false }, type: 'error'}) // Send to console console.error('Error sending email: ', error) // Rethrow error to handle it upstream throw error } finally { transporter.close() // close the connection pool // return something if(toasts.length > 0) { // Toasts found! // Check for type if (toasts[0].type === "error") { // Error if (!res.headersSent) { return res.status(400).json(toasts) } else { console.warn('Attempted to send a response after headers were already sent.'); } } if (toasts[0].type === "unauthorized") { // Unauthorized if (!res.headersSent) { return res.status(401).json(toasts) } else { console.warn('Attempted to send a response after headers were already sent.'); } } else { if (!res.headersSent) { return res.status(200).json(toasts) } else { console.warn('Attempted to send a response after headers were already sent.'); } } } }
该函数在ExpressJS后端的userController.js中通过await sendEmail(mailOptions, successMessage, res, serviceSettings)调用。
环境信息
- Node版本:22.2.0
- NPM版本:10.7.0
- 开发系统:Windows 11
- SMTP服务器系统:Ubuntu 22.04(搭载Postfix和Dovecot)
已尝试的排查措施
- 从自建SMTP服务器(smtp.lumierelabs.org)切换至Gmail服务,问题依旧,排除SMTP服务器问题
- 搭建独立测试应用仅使用Nodemailer,问题复现
- 重启电脑,无改善
- 通过命令行telnet测试smtp.lumierelabs.org,服务器正常
- 重新安装Nodemailer
- 搜索相关问题未找到类似案例
- 关闭Windows Defender防火墙,无变化
恳请各位提供解决方案或排查思路。
内容的提问来源于stack exchange,提问作者FinuxFirit
相关产品推荐
相关产品推荐

