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

Nodemailer发送邮件报535用户名密码不接受错误咨询

Nodemailer 对接 Mailtrap 报 EAUTH 535 认证失败排查

问题场景

  • 技术栈:使用 Nodemailer 实现邮件发送能力,指定 Mailtrap.io 作为 SMTP 服务器
  • 项目文件:
    • email.js:邮件公共配置、发送方法封装
    • authController.js:包含forgotPassword忘记密码接口的处理逻辑
  • 触发场景:请求接口 http://localhost:8000/api/v1/users/forgotPassword 时返回错误
  • 错误特征:错误码EAUTH,SMTP响应码535,提示Username and Password not accepted,错误堆栈指向AUTH PLAIN认证流程失败

完整错误日志

Error: Invalid login: 535-5.7.8 Username and Password not accepted. Learn more at
535 5.7.8  BadCredentials g16-20020a05600c4ed000b003974860e15esm21842702wmq.40 - gsmtp
    at SMTPConnection._formatError (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:784:19)
    at SMTPConnection._actionAUTHComplete (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:1536:34)
    at SMTPConnection.<anonymous> (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:540:26)
    at SMTPConnection._processResponse (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:947:20)
    at SMTPConnection._onData (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:749:14)
    at TLSSocket.SMTPConnection._onSocketData (E:\starter\node_modules\nodemailer\lib\smtp-connection\index.js:189:44)
    at TLSSocket.emit (node:events:527:28)
    at addChunk (node:internal/streams/readable:315:12)
    at readableAddChunk (node:internal/streams/readable:289:9)
    at TLSSocket.Readable.push (node:internal/streams/readable:228:10)
    at TLSWrap.onStreamRead (node:internal/stream_base_commons:190:23) {
  code: 'EAUTH',
  response: '535-5.7.8 Username and Password not accepted. Learn more at\n' +
    '535 5.7.8  BadCredentials g16-20020a05600c4ed000b003974860e15esm21842702wmq.40 - gsmtp',
  responseCode: 535,
  command: 'AUTH PLAIN'
}

原有问题代码

email.js 邮件配置代码

const nodemailer = require('nodemailer');

const sendEmail = async (options) => {
  //1 创建邮件传输实例
  const transporter = nodemailer.createTransport({
    service: 'Gmail',
    host: process.env.EMAIL_HOST,
    port: process.env.EMAIL_PORT,
    auth: {
      user: process.env.EMAIL_USERNAME,
      pass: process.env.EMAIL_PASSWORD,
    },
  });
  //2 定义邮件配置项
  const mailOptions = {
    from: 'Farhan Ajmal <18251598-146@uog.edu.pk>',
    to: options.email,
    subject: options.subject,
    text: options.message,
  };
  //3 发送邮件
  await transporter.sendMail(mailOptions);
};

module.exports = sendEmail;

authController.js 接口逻辑代码

const jwt = require('jsonwebtoken');
const { promisify } = require('util');
const User = require('../models/userModel');
const catchAsync = require('../utils/catchAsync');
const AppError = require('../utils/appError');
const sendEmail = require('../utils/email');

exports.forgotPassword = catchAsync(async (req, res, next) => {
  //根据提交的邮箱查询用户
  const user = await User.findOne({ email: req.body.email });
 

  if (!user) {
    next(new AppError('There is no user with that email address ', 404));
  }

  
  //发送邮件

  try {
    await sendEmail({
      email: user.email,
      subject: 'Your password is only valid for 10 min',
      message,
    });

    res.sendStatus(200);
  } catch (err) {
    console.log(err);
    return next(
      new AppError('There was an error sending the email. Try again later'),
      500
    );
  }
});

问题根因

  1. 核心配置冲突:创建Nodemailer传输实例时同时配置了service: 'Gmail'和自定义host/port,Nodemailer识别到service字段后会自动忽略自定义的host、port参数,强制连接Gmail官方SMTP服务器,根本没有对接预期的Mailtrap服务。错误日志里出现的gsmtp标识就是Gmail SMTP的返回,和Mailtrap无关。
  2. 凭据配置错误风险:即使修正配置冲突,如果环境变量里填的是Mailtrap注册账号密码、或者个人邮箱账号密码,也会触发认证失败——Mailtrap的SMTP服务需要使用对应测试收件箱生成的随机专属用户名、密码,和平台登录凭据不通用。
  3. 代码逻辑漏洞:
    • 查询不到对应用户时,next()调用后没有加return,代码会继续向下执行到发邮件逻辑,触发空指针错误
    • 调用sendEmail时传入了未定义的message变量,就算SMTP配置正确也会直接抛出语法错误
    • AppError实例化时500状态码写在了next参数的括号外,错误状态码不会被正确识别

修复步骤

  1. 修正邮件传输实例配置,删除冲突的service: 'Gmail'字段,确保Nodemailer连接Mailtrap服务器:
const transporter = nodemailer.createTransport({
  host: process.env.EMAIL_HOST, // 填写Mailtrap后台给出的SMTP地址,通常为smtp.mailtrap.io
  port: Number(process.env.EMAIL_PORT), // 填写Mailtrap后台给出的对应端口,支持25、465、587、2525
  auth: {
    user: process.env.EMAIL_USERNAME, // 填写Mailtrap测试收件箱生成的专属SMTP用户名
    pass: process.env.EMAIL_PASSWORD, // 填写Mailtrap测试收件箱生成的专属SMTP密码
  },
});
  1. 补全接口逻辑漏洞,修正后的forgotPassword方法参考:
exports.forgotPassword = catchAsync(async (req, res, next) => {
  // 根据提交的邮箱查询用户
  const user = await User.findOne({ email: req.body.email });
  if (!user) {
    // 加return终止后续逻辑执行
    return next(new AppError('There is no user with that email address ', 404));
  }

  // 生成密码重置token(替换为项目里的实际token生成逻辑)
  const resetToken = user.createPasswordResetToken();
  await user.save({ validateBeforeSave: false });
  const resetURL = `${req.protocol}://${req.get('host')}/api/v1/users/resetPassword/${resetToken}`;
  // 定义邮件正文内容,修复message未定义问题
  const message = `Forgot your password? Submit a PATCH request with your new password to: ${resetURL}.\nIf you didn't request a password reset, please ignore this email.`;

  try {
    await sendEmail({
      email: user.email,
      subject: 'Your password reset token is only valid for 10 min',
      message,
    });
    // 修正响应格式
    res.status(200).json({
      status: 'success',
      message: 'Reset token has been sent to your email'
    })
  } catch (err) {
    console.log(err);
    // 发信失败时清除生成的重置token
    user.passwordResetToken = undefined;
    user.passwordResetExpires = undefined;
    await user.save({ validateBeforeSave: false });
    return next(
      new AppError('There was an error sending the email. Try again later', 500)
    );
  }
});
  1. 核对环境变量配置:打开项目根目录的.env文件,确认EMAIL_HOST、EMAIL_PORT、EMAIL_USERNAME、EMAIL_PASSWORD四个参数和Mailtrap后台给出的SMTP信息完全一致,没有多余空格、拼写错误,确认服务启动时环境变量被正确加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:33:34