NextJS 13.4中Nodemailer本地正常,部署Vercel后无法发邮件
Next.js 13.4 + Nodemailer 部署到 Vercel 生产环境无法发送邮件的解决方法
核心问题排查
从你提供的代码和描述来看,本地正常但Vercel生产环境失效,问题集中在代码逻辑疏漏、环境变量配置或Vercel Serverless函数特性限制上,以下是具体修复方案:
代码中的明显错误
1. API路由(app/api/contact/route.ts)问题
- 未导入
NextResponse:代码中使用了NextResponse.json()但没引入,会导致运行时错误 mailData变量未定义:直接调用transporter.sendMail(mailData)但未定义该变量,属于致命错误- 响应返回时机错误:在
transporter.sendMail回调里返回NextResponse.json()无效,回调函数的返回值不会作为API路由响应 - 未处理Promise异常:邮件发送失败时,Promise reject后没有返回错误响应,导致Vercel日志显示200但实际执行失败
- 多余的
res参数:Next.js 13.4 App Router的API路由不需要传入res: Response参数 - 环境变量未正确引用:直接使用
username/password变量,但未从环境变量中读取
2. Server Action(sendEmail)问题
- 未处理异步:使用
fetch().then()但未返回Promise或用await,可能导致请求被中断 - 冗余API调用:Server Action本身是服务端执行逻辑,没必要再调用内部API路由,增加不必要的网络开销
修复后的代码示例
方案1:优化API路由(保留原调用方式)
// app/api/contact/route.ts import { NextResponse } from 'next/server'; import nodemailer from 'nodemailer'; export async function POST(req: Request) { try { const { name, company, email, phone, message } = await req.json(); // 从环境变量读取SMTP配置 const transporter = nodemailer.createTransport({ port: parseInt(process.env.SMTP_PORT || '465'), host: process.env.SMTP_HOST, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS, }, secure: process.env.SMTP_PORT === '465', // 465端口用SSL,587用STARTTLS requireTLS: process.env.SMTP_PORT === '587', }); // 定义邮件内容 const mailData = { from: process.env.SMTP_FROM, // 发件邮箱需与SMTP账号一致或服务商允许 to: 'your-receive-email@example.com', // 你的收件邮箱 subject: `联系消息:${name}`, text: `姓名:${name}\n公司:${company}\n邮箱:${email}\n电话:${phone}\n内容:${message}`, html: `<p><strong>姓名:</strong>${name}</p> <p><strong>公司:</strong>${company}</p> <p><strong>邮箱:</strong>${email}</p> <p><strong>电话:</strong>${phone}</p> <p><strong>内容:</strong>${message}</p>`, }; // 发送邮件 await transporter.sendMail(mailData); return NextResponse.json({ message: '邮件发送成功' }, { status: 200 }); } catch (error) { console.error('邮件发送失败:', error); return NextResponse.json({ message: '邮件发送失败', error: (error as Error).message }, { status: 500 }); } }
方案2:直接在Server Action中处理(更高效)
"use server"; import nodemailer from 'nodemailer'; export async function sendEmail(data: Inputs) { try { const { name, company, email, phone, message } = data; const transporter = nodemailer.createTransport({ port: parseInt(process.env.SMTP_PORT || '465'), host: process.env.SMTP_HOST, auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS, }, secure: process.env.SMTP_PORT === '465', requireTLS: process.env.SMTP_PORT === '587', }); const mailData = { from: process.env.SMTP_FROM, to: 'your-receive-email@example.com', subject: `联系消息:${name}`, text: `姓名:${name}\n公司:${company}\n邮箱:${email}\n电话:${phone}\n内容:${message}`, html: `<p><strong>姓名:</strong>${name}</p> <p><strong>公司:</strong>${company}</p> <p><strong>邮箱:</strong>${email}</p> <p><strong>电话:</strong>${phone}</p> <p><strong>内容:</strong>${message}</p>`, }; await transporter.sendMail(mailData); return { success: true, message: '邮件发送成功' }; } catch (error) { console.error('发送失败:', error); return { success: false, message: '邮件发送失败', error: (error as Error).message }; } }
Vercel环境配置与额外排查步骤
环境变量配置:
- 在Vercel项目控制台 ->
Settings->Environment Variables中添加以下变量(选择Production环境):SMTP_HOST:SMTP服务器地址(如smtp.xxx.com)SMTP_PORT:端口(465或587)SMTP_USER:SMTP账号SMTP_PASS:SMTP密码/授权码SMTP_FROM:发件邮箱地址
- 配置完成后重新部署项目,确保环境变量生效
- 在Vercel项目控制台 ->
查看Vercel函数日志:
不要只看构建日志,去Vercel控制台的Functions页面,找到/api/contact函数,查看执行日志,里面会显示具体错误信息(如SMTP连接失败、认证错误等)SMTP服务商限制:
- 部分服务商(如Gmail)需要启用
App Password(开启2FA后)或使用OAuth2认证,不能直接用账号密码 - 企业邮箱可能需要添加IP白名单,但Vercel的Serverless函数IP是动态的,这种情况建议改用SendGrid、Mailgun等第三方邮件服务,更适合Serverless环境
- 尝试切换端口:如果465端口失败,换成587端口,同时设置
secure: false和requireTLS: true
- 部分服务商(如Gmail)需要启用
Vercel函数超时限制:
Serverless函数默认执行时间限制为10秒,如果SMTP连接或发送耗时过长,可能会被中断,建议优化SMTP配置或改用更快的邮件服务
内容的提问来源于stack exchange,提问作者Rokas
相关产品推荐
相关产品推荐

