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

Vercel部署NextJs+NodeMailer时邮件无法送达问题排查

Next.js + Nodemailer 部署Vercel后无法发件的解决方案

问题背景

本地环境下用Next.js和Nodemailer实现的邮件发送功能完全正常,但部署到Vercel后,POST请求已触发(日志可查)、环境变量也已配置,邮件却无法送达。


核心排查与修复步骤

1. 修正环境变量命名

Vercel中NEXT_PUBLIC_前缀的变量会暴露给前端,敏感信息(如邮箱密码)不能用这个前缀,且后端Node.js环境读取非NEXT_PUBLIC_变量更稳定:

  • 将环境变量NEXT_PUBLIC_EMAIL改为EMAIL,NEXT_PUBLIC_EMAIL_PASSWORD改为EMAIL_PASSWORD
  • Vercel后台同步修改变量名称,重新部署项目

2. 修复Nodemailer配置错误

你的代码存在两处配置错误:

  • auth参数格式错误:auth.user和auth.pass应直接传字符串,不是对象(比如user: email而非user: { email })
  • 混用配置模式:用Gmail时直接指定service: "gmail"即可,无需手动写port和host

修正后的传输配置:

const transporter = nodemailer.createTransport({
  service: "gmail",
  auth: {
    user: process.env.EMAIL,
    pass: process.env.EMAIL_PASSWORD,
  },
  secure: true,
})

3. 处理异步发送逻辑

当前代码中transporter.sendMail是异步操作,但你直接返回了响应,导致Vercel可能提前终止函数执行,邮件还没发送完成就被中断:

  • 将API函数改为async,用await等待邮件发送完成
  • 错误时返回500状态码,让前端能捕获真实错误

修正后的contact.js:

export default async function (req, res) {
  let nodemailer = require('nodemailer')
  const transporter = nodemailer.createTransport({
    service: "gmail",
    auth: {
      user: process.env.EMAIL,
      pass: process.env.EMAIL_PASSWORD,
    },
    secure: true,
  })
  const mailData = {
    from: `${req.body.name} <${req.body.email}>`, // 规范发件人格式:名称<邮箱>
    to: process.env.EMAIL,
    subject: `Message From ${req.body.name}`,
    text: `Message: ${req.body.message} | Name: ${req.body.name} | Phone: ${req.body.phone}`,
    html: `<p>Name: ${req.body.name}</p><p>Phone: ${req.body.phone}</p><p>Email: ${req.body.email}</p><div>${req.body.message}</div>`
  }

  try {
    await transporter.sendMail(mailData)
    res.status(200).json({ success: true })
  } catch (err) {
    console.error(err)
    res.status(500).json({ success: false, error: err.message })
  }
}

4. 调整Gmail授权方式(若使用Gmail)

Vercel服务器IP属于陌生环境,Google会拦截常规密码登录:

  • 开启两步验证后,创建应用专用密码,用该密码替换原邮箱密码
  • 未开启两步验证的话,临时开启不太安全的应用访问(不推荐,建议用应用专用密码)

5. 优化Vercel函数超时(可选)

Vercel Serverless Function默认超时10秒,可通过vercel.json调整最大时长(上限10秒):

{
  "functions": {
    "api/contact.js": {
      "maxDuration": 10
    }
  }
}

原始代码参考

API 请求函数

export const sendContactForm = async (data) =>
fetch("/api/contact", {
    method: "POST",
    body: JSON.stringify(data),
    headers: { "Content-Type": "application/json", Accept: "application/json" },
}).then((res) => {
    if (!res.ok) throw new Error("Failed to send message")
    return res.json()
})

Nodemailer 配置文件(Nodemailer.js)

import nodemailer from "nodemailer"

const email = process.env.NEXT_PUBLIC_EMAIL
const pass = process.env.NEXT_PUBLIC_EMAIL_PASSWORD

export const transporter = nodemailer.createTransport({
    service: "gmail",
    auth: {
        user: { email },
        pass: { pass },
    },
    secure: true
})

export const mailOptions = {
    from: { email },
    to: { email },
}

前端提交逻辑

const onSubmit = async () => {
        setState((prev) => ({
            ...prev,
            isLoading: true,
        }))

        try {
            await sendContactForm(values)
            setTouched({})
            setState(initState)
        } catch (error) {
            setState((prev) => ({
                ...prev,
                isLoading: false,
                error: error.message,
            }))
        }
    }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:47:12