如何在 Vercel 上正确发送邮件(解决本地正常但部署后静默失败的问题)
发布时间 - 2026-01-07 00:00:00 点击率:次vercel 默认 edge 运行时限制了 node.js 原生网络模块的使用,导致 resend/nodemailer 等邮件客户端在部署后无报错、无响应。需显式声明 `runtime: 'nodejs'` 并启用动态路由,才能确保邮件 api 正常调用。
在 Vercel 上发送邮件失败(如日志停在 console.log('subject', subject) 后不再继续),并非因免费账户限制——Vercel 本身不提供 SMTP 服务,也不拦截邮件请求;真正原因是其默认运行时行为:
✅ Edge Functions(默认):基于 WebAssembly 的轻量运行时,不支持 node:net、node:tls 等底层模块,而 Resend SDK(v3+)和绝大多数邮件库(包括 Nodemailer)底层依赖这些模块发起 HTTPS 请求。即使使用 fetch,Edge 环境对 Content-Type、重定向、证书验证等也有更严格限制,易导致静默挂起或连接超时。
✅ Node.js Serverless Functions(需显式启用):完整兼容 CommonJS/ESM、原生 Node 模块及标准 https/http 客户端,是调用 Resend、SendGrid、Nodemailer 等服务的唯一可靠选择。
✅ 正确配置方式(以 Resend 为例)
在你的 API 路由文件(如 app/api/send/route.ts 或 pages/api/send.ts)顶部添加:
// app/api/send/route.ts
export const runtime = 'nodejs'; // 关键:强制使用 Node.js 运行时
export const dynamic = 'force-dynamic'; // 确保每次请求都执行,避免缓存干扰
import { Resend } from 'resend';
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
try {
const { to, subject, html } = await request.json();
console.log('sendEmail - start');
console.log('to:', to);
console.log('subj
ect:', subject);
const resend = new Resend(process.env.RESEND_API_KEY!);
const response = await resend.emails.send({
from: process.env.SMTP_FROM_EMAIL!,
to,
subject,
html,
});
console.log('Resend success:', response);
return NextResponse.json({ success: true, data: response });
} catch (error) {
console.error('Email send error:', error);
return NextResponse.json(
{ success: false, error: (error as Error).message },
{ status: 500 }
);
}
}⚠️ 注意事项:runtime = 'edge' ❌ 是错误方案(官方文档旧示例已过时);Edge 下 Resend v3+ 会因缺少 node:crypto/node:stream 等模块直接抛 ReferenceError,但 Vercel 日志可能截断错误堆栈,造成“无输出”假象。环境变量必须在 Vercel 项目设置中配置(Settings → Environment Variables),且不能仅在本地 .env 中定义;RESEND_API_KEY 和 SMTP_FROM_EMAIL 需标记为 Production 作用域。若使用 pages/api 路由,请确保导出 config 对象(Next.js 13–14 兼容写法):export const config = { runtime: 'nodejs' };
? 验证是否生效
部署后访问 Vercel 日志(Dashboard → Your Project → Logs),成功调用应显示完整日志链:
sendEmail - start
to: user@example.com
subject: Test Email
Resend success: { id: "xxx", ... } 若仍卡住,请检查:
- 是否误将 runtime 写在 async function 内部(必须为顶层导出);
- RESEND_API_KEY 是否拼写错误或未保存到 Vercel 后台;
- HTML 内容是否含非法字符(如未转义
✅ 总结
Vercel 不限制邮件发送功能本身,也无需升级 Pro 计划——关键在于匹配运行时环境。只要将函数明确指定为 runtime: 'nodejs',即可稳定调用 Resend、SendGrid、Mailgun 或自建 SMTP(Nodemailer)。这是 Vercel 官方推荐且生产验证的实践方式。
# nodejs
# html
# js
# node.js
# json
# node
# app
# edge
# 栈
# ai
# 路由
# 环境变量
# 堆
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?
魔方云NAT建站如何实现端口转发?
Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】
大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?
Android使用GridView实现日历的简单功能
简单实现Android验证码
如何挑选高效建站主机与优质域名?
Win11怎么设置默认图片查看器_Windows11照片应用关联设置
怎么用AI帮你为初创公司进行市场定位分析?
再谈Python中的字符串与字符编码(推荐)
Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区
Android 常见的图片加载框架详细介绍
香港服务器建站指南:外贸独立站搭建与跨境电商配置流程
通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】
Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】
JavaScript如何实现音频处理_Web Audio API如何工作?
Laravel如何使用Passport实现OAuth2?(完整配置步骤)
敲碗10年!Mac系列传将迎来「触控与联网」双革新
最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?
如何在不使用负向后查找的情况下匹配特定条件前的换行符
Laravel如何理解并使用服务容器(Service Container)_Laravel依赖注入与容器绑定说明
linux写shell需要注意的问题(必看)
iOS中将个别页面强制横屏其他页面竖屏
JavaScript如何实现类型判断_typeof和instanceof有什么区别
javascript如何操作浏览器历史记录_怎样实现无刷新导航
Laravel如何处理文件下载请求?(Response示例)
php结合redis实现高并发下的抢购、秒杀功能的实例
百度浏览器网页无法复制文字怎么办 百度浏览器复制修复
韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南
Internet Explorer官网直接进入 IE浏览器在线体验版网址
google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤
js代码实现下拉菜单【推荐】
Laravel如何实现事件和监听器?(Event & Listener实战)
制作电商网页,电商供应链怎么做?
android nfc常用标签读取总结
如何在宝塔面板中创建新站点?
Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】
Laravel如何生成URL和重定向?(路由助手函数)
制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?
无锡营销型网站制作公司,无锡网选车牌流程?
Win11怎么更改系统语言为中文_Windows11安装语言包并设为显示语言
JavaScript常见的五种数组去重的方式
Python文件操作最佳实践_稳定性说明【指导】
node.js报错:Cannot find module 'ejs'的解决办法
Swift中循环语句中的转移语句 break 和 continue
如何用5美元大硬盘VPS安全高效搭建个人网站?
PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)
什么是javascript作用域_全局和局部作用域有什么区别?
java获取注册ip实例
Laravel如何使用Eloquent ORM进行数据库操作?(CRUD示例)


ect:', subject);
const resend = new Resend(process.env.RESEND_API_KEY!);
const response = await resend.emails.send({
from: process.env.SMTP_FROM_EMAIL!,
to,
subject,
html,
});
console.log('Resend success:', response);
return NextResponse.json({ success: true, data: response });
} catch (error) {
console.error('Email send error:', error);
return NextResponse.json(
{ success: false, error: (error as Error).message },
{ status: 500 }
);
}
}