本地Zoho Mail+Nodemailer正常,生产服务器邮件发送失败问题
React + Node.js 部署后 Nodemailer 无法发送邮件问题
本地 localhost 环境下,React + Node.js 项目使用 Nodemailer 发送邮件功能完全正常,但部署到托管服务器后无法发送邮件。前端请求返回响应如下:
Response {type: 'basic', url: 'https://example.com/register', redirected: false, status: 200, ok: true, …}
但邮件实际并未发出,以下是相关代码及问题排查方案:
相关代码
package.json
"proxy": { "/auth/google": { "target": "http://localhost:8000/" } },
ContactForm.jsx
import React, { useState, useEffect } from 'react' const ContactForm = () => { const [fname, setFname] = useState(""); const [lname, setLname] = useState(""); const [email, setEmail] = useState(""); const [subject, setSubject] = useState(""); const [msg, setMsg] = useState(""); const [message, setMessage] = useState(''); useEffect(() => { setTimeout(() => setMessage(''), 9000); }, [message]) const sendEmail = async (e) => { e.preventDefault(); // 先发送请求再清空表单,避免参数为空 setMessage(`Thank you ${fname} ${lname} for enquiry. We will back to you asap.`); const res = await fetch("/register", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ fname, lname, email, subject, msg }) }); console.log(res); setFname(""); setLname(""); setEmail(""); setSubject(""); setMsg(""); } return ( <> <div className="contact-form"> <div className="contact-form-info"> <div className="contact-title"> <h3>TELL US YOUR PROJECT</h3> </div> <form id="contact-form"> <div className="contact-page-form"> <div className="contact-input"> <div className="contact-inner"> <input type="text" placeholder="First Name *" id="first-name" value={fname} onChange={(e) => setFname(e.target.value)} /> </div> <div className="contact-inner"> <input type="text" placeholder="Last Name *" id="last-name" value={lname} onChange={(e) => setLname(e.target.value)} /> </div> <div className="contact-inner"> <input type="text" placeholder="Email *" id="email" value={email} onChange={(e) => setEmail(e.target.value)} /> </div> <div className="contact-inner"> <input type="text" placeholder="Subject *" id="subject" value={subject} onChange={(e) => setSubject(e.target.value)} /> </div> <div className="contact-inner contact-message"> <textarea placeholder="Message *" value={msg} onChange={(e) => setMsg(e.target.value)}></textarea> </div> </div> <div className="contact-submit-btn"> <button className="submit-btn" type="submit" onClick={sendEmail} >Send Email</button> <p className="form-messege pt-3">{message}</p> </div> </div> </form> </div> </div> </> ) } export default ContactForm;
app.js
const express = require("express"); const app = express(); const router = require("./routes/router"); const cors = require("cors"); // 部署时使用服务器分配的动态端口,本地默认8000 const port = process.env.PORT || 8000; app.use(express.json()); app.use(cors()); app.use(router); app.listen(port, () => { console.log(`Server start on port no : ${port}`) })
router.js
const express = require("express"); const router = new express.Router(); const nodemailer = require("nodemailer"); router.post("/register", (req, res) => { const { fname, lname, email, subject, msg } = req.body; // 校验必填参数 if (!fname || !lname || !email || !subject || !msg) { return res.status(400).json({ status: 400, error: "Missing required fields" }); } const transporter = nodemailer.createTransport({ host: "smtppro.zoho.in", port: 465, secure: true, auth: { // 用环境变量存储敏感信息,避免硬编码 user: process.env.EMAIL_USER || "info@mydomain.com", pass: process.env.EMAIL_PASS || "myAppPassword", }, // 开启调试模式,便于排查SMTP连接问题 debug: true, logger: true }); const mailOptions = { from: "info@mydomain.com", cc: "info@mydomain.com", to: email, subject: "Website Form", html: ` First Name : ${fname}<br> Last Name : ${lname}<br> Email : ${email}<br> Subject : ${subject}<br> Message : ${msg} ` }; transporter.sendMail(mailOptions, (error, info) => { if (error) { console.error("Email send error:", error); return res.status(500).json({ status: 500, error: error.message }); } console.log("Email sent:", info.response); res.status(201).json({ status: 201, info }); }); }); module.exports = router;
问题排查与解决方案
1. 前端参数为空问题
原代码中先清空表单再发送请求,导致后端收到的参数全为空。调整顺序为先发送请求,再清空表单,确保参数正确传递。
2. 代理配置失效
package.json 仅配置了 /auth/google 的代理,前端请求的 /register 路径未被代理覆盖。部署环境下:
- 要么将前后端部署在同一域名下,或配置后端 CORS 允许前端域名访问
- 要么前端使用完整的后端 API 地址(通过环境变量配置,如
process.env.REACT_APP_API_URL)
3. 端口硬编码问题
托管服务器通常分配动态端口,需改用 process.env.PORT 获取端口,本地默认 fallback 到 8000。
4. 敏感信息泄露风险
直接硬编码邮箱账号密码存在安全隐患,部署时通过服务器环境变量存储这些信息,后端通过 process.env 读取。
5. SMTP 端口限制
部分托管服务商限制出站 SMTP 连接,可尝试:
- 改用 587 端口,设置
secure: false并开启requireTLS: true - 确认服务商是否允许使用外部 SMTP 服务,部分服务商要求使用自有邮件服务
6. 调试日志缺失
开启 Nodemailer 的 debug: true 和 logger: true,查看服务器端日志,确认 SMTP 连接是否成功、具体错误信息。
7. 错误处理不完善
原代码的 try/catch 无法捕获回调形式的异步错误,需在 sendMail 的回调中正确捕获并返回错误,同时打印详细日志便于排查。
内容的提问来源于stack exchange,提问作者Shahnawaz
相关产品推荐
相关产品推荐

