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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 03:51:21