You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nodemailer出现Connection closed unexpectedly错误求助

邮件发送报错:Connection closed unexpectedly 问题排查与解决

问题描述

使用Node.js结合Nodemailer实现邮件发送功能,初期成功发送5-6次邮件,但后续尝试发送时出现以下错误:

Error: Connection closed unexpectedly
at SMTPConnection._onClose (D:\official\SendEmailProject\nodeContactForm\node_modules\nodemailer\lib\smtp-connection\index.js:827:34)
at TLSSocket.SMTPConnection._onSocketClose (D:\official\SendEmailProject\nodeContactForm\node_modules\nodemailer\lib\smtp-connection\index.js:193:42)
at Object.onceWrapper (node:events:628:26)
at TLSSocket.emit (node:events:525:35)
at node:net:757:14
at TCP.done (node:_tls_wrap:584:7) {
code: 'ECONNECTION',
command: 'CONN'

对应的实现代码:

const express = require('express');
const app = express();
const nodemailer = require('nodemailer');


//Middleware
app.use(express.static('frontend'));

app.use(express.json());

app.get('/',(req,res)=>{
    res.sendFile(__dirname + '/frontend/index.html');
});
app.post('/', (req,res)=>{
    console.log(req.body);
    const transporter1 = nodemailer.createTransport({
        service:"gmail",
        host: "smtp.gmail.com", // hostname
        secure: false, // use SSL
        port: 587, // port for secure SMTP
        auth: {
            user: "my email id",
            pass: "mypassword"
        },
        tls: {
            ciphers: "SSLv3",
            rejectUnauthorized: false,
        },
    });
   
    const mailOptions = {
        from:req.body.email,
        to: 'prahlad.hsrao@gmail.com',
        cc: '24septanjali@gmail.com',
        subject: 'Form Information',
        text:"firstName: "+ req.body.fname+"\n" + "lastName"+req.body.lname+"email" + req.body.email+"phone"+req.body.phone+"message"+req.body.message,
        
    }
    transporter1.sendMail(mailOptions,(error,info)=>{
        if(error){
            console.log(error);
            res.send('error');
            transporter1.close();
        }
        else{
            console.log('Email sent' + info.response);
            res.send('success'); 
            res.redirect('/');
            transporter1.close();   
        }
        
    })
})
app.listen(3000,()=>console.log('Server started...'));

问题根源

  1. 重复创建Transport实例:每次POST请求都新建连接实例,频繁创建销毁触发SMTP服务器连接限制,导致连接被意外关闭。
  2. Gmail安全策略拦截:直接使用邮箱原密码(未启用应用专用密码),多次请求后触发反滥用机制;两步验证开启后,原密码无法用于SMTP验证。
  3. 过时的TLS配置:指定ciphers: "SSLv3"已被Gmail等主流服务器弃用,导致TLS握手失败,连接中断。
  4. 响应逻辑冲突:res.send()与res.redirect()同时调用,导致响应发送异常,干扰连接状态。
  5. 手动关闭连接:主动调用transporter.close()破坏了Nodemailer的连接池复用机制,加剧连接频繁创建销毁的问题。

修复步骤

1. 全局复用Transport实例

将Transport创建移到请求处理外部,全局只初始化一次,利用连接池复用连接:

const express = require('express');
const app = express();
const nodemailer = require('nodemailer');

// 全局初始化Transport,仅创建一次
const transporter = nodemailer.createTransport({
    service:"gmail",
    host: "smtp.gmail.com",
    secure: false,
    port: 587,
    auth: {
        user: "你的Gmail邮箱地址",
        pass: "Gmail应用专用密码" // 替换为应用专用密码
    },
    tls: {
        rejectUnauthorized: false, // 保留此配置避免证书验证问题
        // 删除ciphers: "SSLv3",使用默认兼容TLS版本
    },
});

//Middleware
app.use(express.static('frontend'));
app.use(express.json());

app.get('/',(req,res)=>{
    res.sendFile(__dirname + '/frontend/index.html');
});

app.post('/', (req,res)=>{
    console.log(req.body);
    const mailOptions = {
        from:req.body.email,
        to: 'prahlad.hsrao@gmail.com',
        cc: '24septanjali@gmail.com',
        subject: 'Form Information',
        text:`firstName: ${req.body.fname}\nlastName: ${req.body.lname}\nemail: ${req.body.email}\nphone: ${req.body.phone}\nmessage: ${req.body.message}`
    };

    transporter.sendMail(mailOptions,(error,info)=>{
        if(error){
            console.log(error);
            res.send('error');
        }
        else{
            console.log('Email sent: ' + info.response);
            res.redirect('/'); // 二选一:要么重定向,要么发送success响应
        }
        // 无需手动关闭连接,Nodemailer自动管理连接池
    })
})

app.listen(3000,()=>console.log('Server started...'));

2. 配置Gmail应用专用密码

  • 确保Gmail账号已开启两步验证
  • 登录Google账号管理页面,进入「安全」-「应用专用密码」,生成对应密码,替换代码中pass字段的值,禁止使用邮箱原密码。

3. 修正响应逻辑

移除res.send('success')与res.redirect('/')的冲突调用,选择其中一种响应方式即可。

4. 移除手动关闭连接代码

删除所有transporter.close()调用,Nodemailer会自动维护连接池,空闲连接会被自动回收,无需手动干预。

内容的提问来源于stack exchange,提问作者Anjali Patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 12:20:28