Next.js集成Nodemailer时出现模块找不到错误求助
解决Next.js + Nodemailer启动错误及邮件发送配置问题
先处理核心错误:Module not found: Can't resolve '@vercel/turbopack-ecmascript-runtime/dev/client/hmr-client.ts'
这个错误和Turbopack(Next.js实验性打包工具)对Server Action的兼容问题有关,同时你的文件结构不符合Next.js 13+规范,按以下步骤修复:
1. 调整Server Action的文件位置
你把带"use server"的sendEmail.js放在了pages/api目录下,这是错误的——pages/api是旧版API路由的专属目录,而Server Action("use server"标记的函数)应和页面组件同级,或放在单独的actions文件夹中,避免和API路由机制混淆。
示例调整:
- 在项目根目录创建
app/actions文件夹,将sendEmail.js移入,可重命名为sendEmail.server.js(更清晰标记服务端代码)。
2. 禁用Turbopack(临时/可选)
如果启动命令用了next dev --turbo,改成直接执行next dev。Turbopack目前对部分Server Action场景的支持不完善,用传统Webpack打包可绕过该依赖错误。
修正邮件发送配置和表单逻辑
1. 修复Nodemailer的SMTP配置错误
你的Gmail SMTP参数完全不正确,正确配置如下:
"use server" import nodemailer from "nodemailer" const transporter = nodemailer.createTransport({ host: "smtp.gmail.com", // 需填写完整SMTP地址,不是"gmail" port: 587, // 对应secure: false;若用465端口则设secure: true secure: false, auth: { user: "你的Gmail邮箱地址", pass: "你的Gmail应用专用密码", // 注意:必须开启两步验证后生成App Password,不能直接用账号密码 }, }); export default async function sendEmail(formData) { // 从表单数据中提取用户输入,比如邮箱 const userEmail = formData.get('email'); const info = await transporter.sendMail({ from: '"Job Portfolio" <你的Gmail邮箱>', to: "你的目标收件邮箱", subject: "来自作品集的联系请求", text: `发件人邮箱:${userEmail}`, html: `<p>发件人邮箱:${userEmail}</p>`, }); console.log("Message sent: %s", info.messageId); return { success: true }; }
2. 修正客户端组件的表单提交逻辑
直接把sendEmail传给onSubmit会导致两个问题:未阻止表单默认跳转、无法传递表单数据。修改Contact.tsx如下:
"use client" import React from 'react'; import { useState } from 'react'; import sendEmail from '@/app/actions/sendEmail'; // 对应调整后的文件路径 const Contact = () => { const[email, setEmail] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); // 阻止表单默认跳转行为 setIsSubmitting(true); try { // 用FormData传递表单数据 const formData = new FormData(); formData.append('email', email); await sendEmail(formData); alert('邮件发送成功'); setEmail(''); } catch (err) { alert('邮件发送失败,请重试'); console.error(err); } finally { setIsSubmitting(false); } } return ( <form onSubmit={handleSubmit}> <input type="email" onChange={(e) => setEmail(e.target.value)} value={email} placeholder="你的邮箱" required /> <button type="submit" disabled={isSubmitting}> {isSubmitting ? '发送中...' : '发送邮件'} </button> </form> ) } export default Contact
额外注意事项
- Gmail必须开启两步验证,并生成应用专用密码(App Password),否则无法通过SMTP登录。
- 若你使用的是Next.js Pages Router而非App Router,应放弃Server Action,改用旧版API路由(
pages/api/sendEmail.js),不要加"use server"标记,通过接口请求的方式处理邮件发送。
内容的提问来源于stack exchange,提问作者atryknaav
相关产品推荐
相关产品推荐

