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

Next.js+Nodemailer发送事务邮件遇队列/未送达问题求助

问题:Next.js中Nodemailer结合SMTP发送事务邮件失败,邮件未送达

我在Next.js网站里用Nodemailer搭配SMTP凭证发送订阅、重置密码这类事务邮件,先后试了Mailgun、Sendinblue、MSG91、Postmark的免费版,要么邮件进积压队列,要么SMTP服务器返回队列状态;用Sendinblue API也没用,邮件根本到不了收件人邮箱。

以下是我的API代码(跳过注释逻辑,查看Nodemailer部分)和请求返回结果:

API代码

import ConnectDB from "@/utils/connect_db"
import User from "@/models/user"
const nodemailer = require('nodemailer');
const jwt = require("jsonwebtoken")

const forgotPassword = async (req, res) => {
try {

        if (req.method === 'POST') {
            await ConnectDB()
            // let user = await User.findOne({ email: req.body.email })
            // if (!user) user = await User.findOne({ username: req.body.email }) //because user can put the username or email in the same field and api should verify from both ways
            // if (!user) return res.status(404).json({ success: false, msg: "You don't have an account with this email!" })
            // const token = jwt.sign({ id: user._id }, process.env.SECRET_KEY, { expiresIn: '2m' })
    
            // USING Postmark
            const transport = nodemailer.createTransport({
                host: "smtp.postmarkapp.com",
                port: 587,
                auth: {
                    user: "34dd6ee8-8015-444a-92e5-25194cf742cc",
                    pass: "34dd6ee8-8015-444a-92e5-25194cf742cc"
                }
            });
    
            // create email message object
            const message = {
                from: 'binarshadsaad6@gmail.com',
                to: 'saad19rsf@gmail.com',
                text: "hellow this is a text email body to check the email service",
                subject: 'You subscribed our Newsletter',
                html: `<html><body><h1>Fitte Moooo!</h1><p>Dear valuable Jheengu this email is to notify you that you have successfully recieved the 'Fitte Moo' reward for literally just existing at this time of morning.</p></body></html>`
            };
    
            // send email using nodemailer
            let info = await transport.sendMail(message);
            console.log(info)
            res.json({ success: true, info })
    
        }
        else {
            res.status(400).json({ success: false, msg: "bad request, you are using wrong request method!" })
        }
    }
    catch (error) {
        console.log(error)
        res.status(500).json({ success: false, msg: "Internal server error occurred, pleae try again later" })
    }

}
export default forgotPassword

请求返回结果

{
  "success": true,
  "info": {
    "accepted": [
      "saad19rsf@gmail.com"
    ],
    "rejected": [],
    "ehlo": [
      "PIPELINING",
      "SIZE 20480000",
      "VRFY",
      "ETRN",
      "AUTH PLAIN LOGIN CRAM-MD5 DIGEST-MD5",
      "AUTH=PLAIN LOGIN CRAM-MD5 DIGEST-MD5",
      "ENHANCEDSTATUSCODES",
      "8BITMIME",
      "DSN"
    ],
    "envelopeTime": 622,
    "messageTime": 452,
    "messageSize": 858,
    "response": "250 2.0.0 Ok: queued as 3B28D414C40",
    "envelope": {
      "from": "binarshadsaad6@gmail.com",
      "to": [
        "saad19rsf@gmail.com"
      ]
    },
    "messageId": "<50a33941-a951-b4eb-2290-781a58eda83d@gmail.com>"
  }
}

解决思路

1. 验证发件人地址合法性

从返回结果看,Postmark已接收邮件并进入队列,但未送达的核心原因是发件人地址未通过服务商验证。你用的binarshadsaad6@gmail.com属于第三方邮箱,未在Postmark后台完成授权/域名验证,会被收件方反垃圾系统拦截。

解决:在Postmark后台验证自定义域名,使用该域名下的邮箱作为发件人(如noreply@yourdomain.com);若坚持用Gmail,需在Postmark后台完成该邮箱的授权流程。

2. 优化邮件内容合规性

测试邮件里的俚语(如Fitte Moooo!、Jheengu)、不符功能的主题(当前是重置密码接口,主题却写订阅通知)会触发反垃圾标记。事务邮件需:

  • 主题清晰匹配功能(如「请重置你的账户密码」)
  • 内容正式简洁,避免无意义俚语
  • HTML结构规范,添加必要的合规元素(如退订链接,部分服务商强制要求)

3. 修复SMTP配置细节

Postmark的587端口用STARTTLS加密,需补充配置确保连接安全:

const transport = nodemailer.createTransport({
    host: "smtp.postmarkapp.com",
    port: 587,
    secure: false, // 587端口无需直接SSL,用STARTTLS
    requireTLS: true, // 强制加密连接
    auth: {
        user: "你的Postmark Server Token",
        pass: "你的Postmark Server Token"
    }
});

4. 排查投递日志

不要只依赖Nodemailer返回,去Postmark后台查看投递日志,里面会明确显示邮件是被拒收、进垃圾箱还是延迟投递。若收件方是Gmail,可先检查垃圾箱,或把发件人添加到联系人列表。

5. 改用服务商官方SDK

SMTP层可能存在兼容问题,直接用Postmark官方SDK更稳定:

// 先安装依赖:npm install postmark
import postmark from 'postmark';

const client = new postmark.ServerClient('你的Postmark Server Token');

const sendResult = await client.sendEmail({
    From: 'noreply@yourdomain.com', // 已验证的发件地址
    To: 'saad19rsf@gmail.com',
    Subject: '账户密码重置',
    TextBody: '点击链接重置密码:xxx',
    HtmlBody: '<p>点击链接重置密码:<a href="xxx">重置</a></p>'
});

6. 检查免费版限制

所有服务商免费版有发送量限制(如Postmark每月1000封),新注册账户可能需要人工审核才能正常投递,若长期队列积压,可联系服务商客服确认账户状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 22:22:08