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

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环境配置与额外排查步骤

  1. 环境变量配置:

    • 在Vercel项目控制台 -> Settings -> Environment Variables 中添加以下变量(选择Production环境):
      • SMTP_HOST:SMTP服务器地址(如smtp.xxx.com)
      • SMTP_PORT:端口(465或587)
      • SMTP_USER:SMTP账号
      • SMTP_PASS:SMTP密码/授权码
      • SMTP_FROM:发件邮箱地址
    • 配置完成后重新部署项目,确保环境变量生效
  2. 查看Vercel函数日志:
    不要只看构建日志,去Vercel控制台的Functions页面,找到/api/contact函数,查看执行日志,里面会显示具体错误信息(如SMTP连接失败、认证错误等)

  3. SMTP服务商限制:

    • 部分服务商(如Gmail)需要启用App Password(开启2FA后)或使用OAuth2认证,不能直接用账号密码
    • 企业邮箱可能需要添加IP白名单,但Vercel的Serverless函数IP是动态的,这种情况建议改用SendGrid、Mailgun等第三方邮件服务,更适合Serverless环境
    • 尝试切换端口:如果465端口失败,换成587端口,同时设置secure: false和requireTLS: true
  4. Vercel函数超时限制:
    Serverless函数默认执行时间限制为10秒,如果SMTP连接或发送耗时过长,可能会被中断,建议优化SMTP配置或改用更快的邮件服务

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 00:55:13