使用Node.js TLS Socket连接Gmail SMTP时遭遇协议违规错误
Gmail SMTP 451 协议违规问题解决
问题背景
使用Node.js的TLS Socket连接Gmail SMTP服务器,自定义SMTP命令生成类发送邮件时,MAIL FROM和RCPT TO命令能收到服务器的OK响应,但发送DATA命令后收到:
451 4.5.0 SMTP protocol violation, see RFC 2821 k12-20020adff5cc000000b0021e4c3b2966si4569901wrp.1037 - gsmtp
后续尝试中,服务器返回"Go Ahead"后发送FROM:开头的邮件头,仍收到相同的451错误。
涉及代码
TLS连接处理代码
secure.on('secureConnect', () => { //secure.setEncoding('base64'); let caretka = `\r\n`; console.log(secure.authorized); console.log('IN SECURE'); //secure.write('EHLO hailmail\r\n'); com.forEach(command => { secure.write(command); }); secure.write('quit\r\n'); secure.on('data', chunk => { const response = chunk.toString(); console.log(`Response in secure: ${response}`); }) secure.on('keylog', (line) => { console.log(`Line in secure: ${line}`); }) secure.on('close', () => { console.log('closed'); }) });
SMTP命令生成类
class creatingCommandsForSMTP { constructor(msg) { this.helo = `EHLO hailmail\r\n`; this.mailFrom = `MAIL FROM: <${msg.from}>\r\n`; this.recipient = `RCPT TO: <${msg.recipient}>\r\n`; this.commandData = `DATA`; //this.dataFrom = `FROM: <${msg.from}>\r\n`; //this.dataTo = `TO: <${msg.recipient}>\r\n`; //this.dataSubject = `SUBJECT: ${msg.subject}\r\n`; //this.dataText = `${msg.text}\r\n`; //this.dot = `.\r\n`; //this.commandQuit = 'QUIT\r\n'; } getValue(command) { return this[command] } }
问题根源及修复方案
1. DATA命令格式错误
RFC 2821要求所有SMTP命令必须以\r\n结尾,你的commandData字段只写了DATA,缺少结尾的换行符,导致服务器无法识别为完整命令。修改命令生成类:
this.commandData = `DATA\r\n`;
2. 违反SMTP请求-响应交互模式
SMTP是逐命令交互的协议,必须等待服务器返回前一个命令的响应后,才能发送下一个命令。你的代码直接通过forEach一次性发送所有命令,会导致命令在TCP缓冲区堆积,服务器无法按顺序处理,触发协议违规。
重构为响应驱动的发送逻辑:
secure.on('secureConnect', () => { console.log(secure.authorized); console.log('IN SECURE'); // 按顺序排列的命令队列 const commands = [ `EHLO hailmail\r\n`, `MAIL FROM: <your-email@gmail.com>\r\n`, `RCPT TO: <recipient@example.com>\r\n`, `DATA\r\n`, `FROM: <your-email@gmail.com>\r\n`, `TO: <recipient@example.com>\r\n`, `SUBJECT: Test Email\r\n`, `\r\n`, // 邮件头与正文的分隔空行 `This is the email content.\r\n`, `.\r\n`, // 邮件内容结束标记 `QUIT\r\n` ]; let commandIndex = 0; // 发送第一个命令 secure.write(commands[commandIndex]); secure.on('data', chunk => { const response = chunk.toString(); console.log(`Response: ${response}`); // 2xx/3xx响应表示可以继续发送下一个命令 if ((response.startsWith('2') || response.startsWith('3')) && commandIndex < commands.length - 1) { commandIndex++; secure.write(commands[commandIndex]); } }); secure.on('close', () => { console.log('closed'); }); });
3. 邮件内容格式规范
服务器返回354 Go Ahead后,发送的邮件内容必须符合RFC 2822格式:
- 邮件头和正文之间必须有一个空行(
\r\n) - 邮件内容必须以单独一行的
.结束(即.\r\n) - 如果邮件内容中有行以
.开头,需要转写成..,避免被误判为结束标记
额外注意事项
Gmail SMTP的强制要求:
- 必须使用TLS加密(端口465)或STARTTLS(端口587)
- 开启两步验证的账号需使用应用专用密码
- 发送频率和邮件内容需符合Gmail反垃圾政策
内容的提问来源于stack exchange,提问作者Cribe
相关产品推荐
相关产品推荐

