修复 Vercel 上的 Nodemailer SMTP 问题

修复 Vercel 上的 Nodemailer SMTP 问题
修复 Vercel 上的 Nodemailer SMTP 问题

解决生产中的电子邮件问题

当您的应用程序部署在 Vercel 上时,您是否遇到 Nodemailer 问题?虽然一切都在您的本地环境中完美运行,但过渡到生产有时可能会导致意外错误。

在本文中,我们将探讨常见问题及其解决方案,特别关注为什么您的 SMTP 电子邮件设置可能在 Vercel 上失败,即使它在本地工作。让我们深入探讨故障排除和解决这些问题。

命令 描述
NextRequest 表示 Next.js API 路由中的请求对象,允许访问传入的请求数据。
NextResponse 用于在 Next.js API 路由中创建响应对象,从而能够发送 JSON 响应。
nodemailer.createTransport 初始化传输对象,以便使用 SMTP 和 Nodemailer 发送电子邮件。
transport.sendMail 使用通过nodemailer.createTransport 创建的传输对象发送电子邮件。
await request.json() 从异步函数中传入的请求中提取 JSON 数据。
fetch 执行 HTTP 请求,例如将表单数据发送到 API 端点。
useState 管理 React 功能组件内的状态,对于处理表单输入很有用。

了解 Nodemailer 问题的解决方案

提供的后端脚本旨在使用以下方式处理通过联系表单发送的电子邮件 Nodemailer 在 Next.js API 路由中。当向此端点发出 POST 请求时,脚本会从请求正文中提取电子邮件、名称和消息。然后,它使用这些详细信息构建 HTML 电子邮件内容。传输对象是用以下命令创建的 nodemailer.createTransport,指定 SMTP 服务器详细信息,包括主机、端口和身份验证凭据。

交通设置完毕后, transport.sendMail 使用电子邮件选项调用来发送电子邮件。如果成功,则返回成功的JSON响应;否则,将发回错误消息。在前端, sendEmail 函数使用以下方式将表单数据发送到 API 端点 fetch 带有 POST 请求的命令。状态的管理使用 useState 捕获和更新表单输入值。提交表格后, handleSubmit 功能触发电子邮件发送过程,确保流畅的用户体验。

后端代码:处理 Next.js 中的 Nodemailer 设置

JavaScript(Next.js API 路线)

import { type NextRequest, NextResponse } from 'next/server';
import nodemailer from 'nodemailer';

export async function POST(request: NextRequest) {
  try {
    const { email, name, message } = await request.json();

    const htmlContent = `
      <html>
        <head>
          <style>
            body {
              font-family: Arial, sans-serif;
              font-size: 16px;
            }
            .container {
              max-width: 600px;
              margin: 0 auto;
            }
            .subject {
              color: #b02d1f;
              margin-bottom: 20px;
            }
          </style>
        </head>
        <body>
          <div class="container">
            <h2 class="subject">New Message From Contact Form</h2>
            <p><strong>Name:</strong> ${name}
            <p><strong>Email:</strong> ${email}
            <p><strong>Message:</strong> ${message}
          </div>
        </body>
      </html>`;

    const transport = nodemailer.createTransport({
      host: "example.prod.iad2.secureserver.net",
      port: 465,
      secure: true,
      auth: {
        user: process.env.MY_EMAIL,
        pass: process.env.MY_PASSWORD,
      },
    });

    const mailOptions = {
      from: process.env.MY_EMAIL,
      to: process.env.MY_EMAIL,
      subject: `New Message from ${name} (${email})`,
      html: htmlContent,
      replyTo: email,
    };

    await new Promise((resolve, reject) => {
      transport.sendMail(mailOptions, function (err) {
        if (!err) {
          resolve('Email sent!');
        } else {
          reject(err);
        }
      });
    });

    return NextResponse.json({ message: 'Email sent' });
  } catch (err) {
    return NextResponse.json({ error: err.message || "An error occurred" }, { status: 500 });
  }
}

前端代码:通过联系表发送电子邮件

JavaScript(反应)

import { FormData } from '@/components/ContactForm';

export function sendEmail(data: FormData) {
  const apiEndpoint = '/api/email';

  fetch(apiEndpoint, {
    method: 'POST',
    body: JSON.stringify(data),
  })
    .then((res) => res.json())
    .catch((err) => console.error("Error sending email:", err));
}

// Example of how to use sendEmail function:
import { useState } from 'react';
import { sendEmail } from '@/utils/send-email';

export default function ContactForm() {
  const [formData, setFormData] = useState({ name: '', email: '', message: '' });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData({ ...formData, [name]: value });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    sendEmail(formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" value={formData.name} onChange={handleChange} />
      <input name="email" value={formData.email} onChange={handleChange} />
      <textarea name="message" value={formData.message} onChange={handleChange} />
      <button type="submit">Send</button>
    </form>
  );
}

确保正确的环境变量配置

在处理上述问题时,经常被忽视的一个关键方面是生产环境中环境变量的正确配置。虽然本地开发环境通常可以通过 .env 文件轻松访问环境变量,但部署到 Vercel 等服务需要在平台设置中正确设置这些变量。这可确保敏感信息(例如电子邮件凭据)在运行时得到安全管理并可供应用程序访问。

要在 Vercel 上配置环境变量,您需要转到项目设置并在“环境变量”部分下添加所需的变量。确保环境变量的名称与代码中使用的名称完全匹配。此步骤对于使用 Nodemailer 通过 SMTP 服务器发送电子邮件等功能的无缝运行至关重要。

有关 Vercel 上的 Nodemailer 和 SMTP 的常见问题

  1. 为什么我的电子邮件可以在本地使用,但不能在 Vercel 上使用?
  2. 确保在 Vercel 上正确设置环境变量。检查 SMTP 配置和身份验证详细信息。
  3. 如何在 Vercel 上设置环境变量?
  4. 转到 Vercel 上的项目设置,找到“环境变量”部分,然后在其中添加变量。
  5. Nodemailer 在生产中的常见问题有哪些?
  6. 问题通常包括不正确的环境变量、错误配置的 SMTP 设置或网络限制。
  7. 我可以将任何 SMTP 服务器与 Nodemailer 一起使用吗?
  8. 是的,只要您有正确的配置详细信息,例如主机、端口和身份验证凭据。
  9. 如何调试电子邮件 API 中的 500 错误?
  10. 检查服务器日志中的特定错误消息,并确保所有依赖项和配置均已正确设置。
  11. 发送电子邮件的安全最佳实践有哪些?
  12. 使用环境变量来存储敏感信息、安全连接 (SSL/TLS),并正确验证您的电子邮件服务器。
  13. 我是否需要针对本地和生产环境进行不同的设置?
  14. 虽然设置可能相似,但请确保在生产中正确应用特定于环境的配置。
  15. 有没有 Nodemailer 的替代方案来发送电子邮件?
  16. 是的,其他选项包括 SendGrid、Mailgun 和 AWS SES,它们提供用于发送电子邮件的强大 API。
  17. 为什么我的电子邮件被标记为垃圾邮件?
  18. 确保您的电子邮件内容格式正确,包含正确的标头,并且您的发送域具有正确的 SPF/DKIM 记录。
  19. 我可以在生产中将 Gmail 与 Nodemailer 一起使用吗?
  20. 是的,您可以使用 Gmail,但您需要使用应用程序密码对其进行配置,并启用安全性较低的应用程序或使用 OAuth2 以获得更高的安全性。

总结故障排除指南

总之,解决 Nodemailer 在本地工作但在 Vercel 上无法工作的问题涉及几个关键步骤。确保在 Vercel 设置中正确配置环境变量。验证您的 SMTP 服务器详细信息(包括主机、端口和身份验证凭据)是否准确。这些措施应该可以解决您在生产构建中遇到的 500 错误。通过正确的设置和对细节的仔细关注,您的联系表单应该在本地和生产环境中无缝运行,为您的应用程序提供可靠的通信功能。