Node.js使用Nodemailer发并发邮件遇到421限制错误如何解决
错误根因分析
你遇到的421报错不是Outlook SMTP服务的限制,是本地安装的Avast杀毒软件的邮件防护模块限制了单进程的SMTP并发连接数,上线后如果服务器没有安装同类限制SMTP并发的安全软件,这个特定错误大概率不会出现,但你现有代码本身也存在会引发并发发信问题的缺陷:
- 你把
transporter的创建逻辑写在了接口请求的回调里,每来一个发信请求就会新建一个SMTP连接实例,没有复用连接,高并发下很容易触达邮件服务商的并发连接限制,也会极大浪费资源 transporter.sendMail的回调前加了无效的await,属于语法错误,await只能用于Promise对象,你这里混用了回调写法,会导致异步逻辑混乱
优化方案
1. 基础代码优化(必做)
把transporter提到全局,复用单连接池,Nodemailer自带连接池配置,可以直接设置并发数、连接阈值:
const express = require('express'); const nodemailer = require('nodemailer'); const app = express(); app.use(express.json()); // 全局创建复用的transporter,开启内置连接池 const transporter = nodemailer.createTransport({ host: "smtp-mail.outlook.com", secureConnection: false, port: 587, pool: true, // 开启连接池 maxConnections: 5, // 最大并发连接数,Outlook普通账号建议不要超过10 maxMessages: 100, // 单个连接最多发送的邮件数 tls: { ciphers:'SSLv3', rejectUnauthorized: false }, auth: { user: 'generic-email@outlook.com', pass: 'generic-password' } }); app.post('/', async (req, res) => { const mailOptions = { from: 'generic-email@outlook.com', to: req.body.email_name, subject: 'testing <No-Reply Email>', text: 'testing', html: `<div>testing</div>` }; try { await transporter.sendMail(mailOptions); console.log('Message sent'); return res.json({stat:'all good'}); } catch (error) { console.log(error); return res.json({stat:'not good'}); } }); app.listen(3000, () => { console.log('Listening at Port 3000...'); });
2. 针对你提出的两个解决方向的评估
- 重试逻辑是必要的,但不能无限制重试:可以搭配轻量的重试工具库,设置最多重试3次,每次重试间隔指数退避,只针对连接超限、临时服务不可用这类可重试的错误重试,不要对收件人地址无效、账号被封这类不可重试错误重试
- 如果你站点上线后日均发信量超过100封,建议更换专业的事务性邮件服务:Outlook个人/普通商务账号本来就不适合用于业务发信,存在发信量限制、送达率低、容易被标记为垃圾邮件的问题,主流的邮件API服务按发送量计费,不需要自己维护SMTP连接、重试逻辑,送达率更有保障
3. 本地测试的临时解决方法
如果本地测试批量发信需要绕过Avast的限制,可以直接在Avast设置里关闭邮件防护功能,或者调整SMTP并发连接限制阈值。
内容的提问来源于stack exchange,提问作者user15573857
相关产品推荐
相关产品推荐

