AL2023虚拟机Node.js邮件服务器无法发送邮件求助
Node.js SMTP 服务器无法发送邮件(接收功能正常)
我在AL2023 Linux虚拟机上使用smtp-server npm包搭建了Node.js邮件服务器,目前能正常接收邮件,但无法发送邮件。已在安全组配置25和587端口,且通过netstat -tuln命令确认端口已正常开放。相同的发件客户端代码对接Gmail服务器时可正常工作,因此问题肯定出在邮件服务器的配置环节。
服务器端代码
import path from "node:path"; import dotenv from "dotenv"; dotenv.config({path: path.resolve(__dirname + './../../.env')}); import fs from 'fs'; import connectDB from "./db"; import logger from "./logger"; import { SMTPServer } from "smtp-server"; import { simpleParser } from "mailparser"; import MailRepository from "./repositories/mail.repository"; const repo = new MailRepository(); const server = new SMTPServer({ onConnect(session, cb) { cb(); }, onMailFrom(address, session, cb) { cb(); }, onRcptTo(address, session, cb) { cb(); }, onData(stream, session, callback) { simpleParser(stream) .then((parsed) => { const obj = { mail: JSON.parse(JSON.stringify(parsed)), }; repo.create(obj); callback(null); }) .catch((err) => { console.error("Error parsing email:", err); callback(err); }); }, disabledCommands: ["AUTH"], disableReverseLookup: true, logger: false, secure: false, hideSTARTTLS: true, hide8BITMIME: true, hidePIPELINING: true, hideSMTPUTF8: true, }); const serverFor587 = new SMTPServer({ authOptional: false, onAuth(auth, session, cb){ try{ logger.info('587 on auth : username - '+ auth.username + ' password - ' + auth.password); if (auth.username === 'demo' && auth.password === 'Demo@123') { cb(null, { user: 'demo' }); } else { cb(new Error('Authentication failed')); } } catch(err){ logger.error('on auth error :' + err); cb(new Error("Authentication Failed")); } }, onConnect(session, callback) { logger.info('Client connected, sending greeting...'); callback(); }, onData(stream, session, callback) { logger.info('ondata'); stream.pipe(process.stdout); stream.on('end', callback); }, onClose(session) { console.log('Connection closed from:', session.remoteAddress); }, secure: false, needsUpgrade: true, // Enable STARTTLS key: fs.readFileSync('/etc/letsencrypt/live/mail.demo.in/privkey.pem'), cert: fs.readFileSync('/etc/letsencrypt/live/mail.demo.in/fullchain.pem') }); serverFor587.on('error', (err) => { logger.error('Error:', err); }); connectDB() .then(() => { server.listen(25, () => logger.info("mail server running on port 25 for receiving mails")); serverFor587.listen(587, () => logger.info("mail server running on port 587 for sending mails")); }) .catch((err) => { logger.error("db connection failed !!! ", err); });
发件客户端代码
import nodemailer from 'nodemailer'; import logger from "./../logger/log.js"; export class SendMails{ private transporter = nodemailer.createTransport({ host: 'mail.demo.in', port: 587, secure: false, auth: { user: 'demo', pass: 'Demo@123' }, tls: { rejectUnauthorized: false } }); constructor(){ this.transporter .verify() .then(result => logger.info("mailer connected "+ result)) .catch(err => logger.error("error in mail connection " + err)); } async sendMail(frm: string, to: string, cc:string, bcc:string, sbjct: string, text: string, html: string){ await this.transporter.sendMail( { from: frm, to: to, subject: sbjct, text: text, html: html, cc:cc, bcc:bcc, }, function (error, info) { if (error) { logger.error(error); } else { logger.info("Email sent: " + info.response); } } ); } }
问题分析与修复方案
核心问题
smtp-server包本身仅负责接收邮件,不具备邮件转发/发送到外部邮箱的能力。你当前587端口的服务器配置只是将客户端发来的邮件内容输出到控制台,没有执行实际的邮件转发操作,这是无法发送邮件的根本原因。
具体修复步骤
1. 为587端口服务器添加邮件转发逻辑
引入nodemailer作为出站邮件的处理工具,在onData回调中解析邮件后,将其转发到目标收件人的邮件服务器:
import nodemailer from 'nodemailer'; // 创建用于转发邮件的transporter(可配置中继服务器或直接使用目标邮箱SMTP) const forwardTransporter = nodemailer.createTransport({ host: 'smtp.your-relay-server.com', // 若无中继,可使用目标邮箱SMTP(如Gmail的smtp.gmail.com) port: 587, secure: false, auth: { user: 'your-relay-account', pass: 'your-relay-password' } }); const serverFor587 = new SMTPServer({ // 保留原有配置... onData(stream, session, callback) { logger.info('开始处理待发送邮件'); simpleParser(stream) .then(async (parsed) => { const forwardOptions = { from: parsed.from.text, to: parsed.to.text, cc: parsed.cc?.text || '', bcc: parsed.bcc?.text || '', subject: parsed.subject, text: parsed.text, html: parsed.html }; try { const info = await forwardTransporter.sendMail(forwardOptions); logger.info(`邮件转发成功: ${info.response}`); callback(null); } catch (err) { logger.error(`邮件转发失败: ${err}`); callback(err); } }) .catch((err) => { logger.error(`解析邮件失败: ${err}`); callback(err); }); }, // 保留原有配置... });
2. 验证STARTTLS配置有效性
确认证书文件路径正确且证书有效,生产环境建议移除客户端的rejectUnauthorized: false配置,确保证书可信。
3. 配置域名邮件认证记录
外部邮件服务器会拒绝来自无认证记录的邮件,需完成以下配置:
- 为
mail.demo.in设置反向DNS解析(PTR记录) - 添加SPF记录,授权你的服务器发送邮件
- 配置DKIM签名,提升邮件可信度
4. 检查服务器出站限制与黑名单状态
部分云服务商(如AWS)默认限制25端口出站流量,需申请解除限制;同时可通过工具检查服务器IP是否被列入邮件黑名单。
内容的提问来源于stack exchange,提问作者Samarth Srivastava
相关产品推荐
相关产品推荐

