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

Nodemailer本地运行正常 部署上线后无法发送邮件问题求助

Nodemailer部署后无法发送邮件解决方案

代码问题排查修正

  • 发件人地址不完整:当前配置的user: "subrata@spineor"、from: "subrata@spineor"均缺失域名后缀,需补全为完整邮箱地址(例:subrata@spineor.com),本地环境校验宽松未报错,服务器严格校验会直接拒绝请求。
  • SMTP加密规则缺失:587端口对应STARTTLS加密方式,需明确配置加密规则,避免服务器安全策略拦截请求。
  • 异步逻辑无响应:当前邮件发送为异步操作,未向接口返回响应,服务器可能提前销毁请求上下文导致发送中断。
  • 参数顺序错误:原代码将接口参数res和req写反,且第一个参数实际应为表单提交数据,需调整参数顺序。

服务器/邮箱侧限制排查

  • 端口放行检查:大部分云服务商默认封禁25、587等邮件发送端口,需登录服务器安全组放开587端口的出方向访问规则,部分服务商需额外提交工单申请解封邮件端口。
  • 邮箱安全限制检查:Outlook/live邮箱默认拦截陌生IP的登录请求,登录发件人邮箱的安全中心,将服务器IP加入信任列表;若邮箱开启了两步验证,需生成应用专用密码替换代码中的原登录密码。

修正后代码示例

const nodemailer = require('nodemailer');
// 调整为async函数支持异步等待
exports.sendMail = async function (formData, req, res) {
  console.log("In Mail Service", formData);
  try {
    const transporter = nodemailer.createTransport({
      host: "smtp.live.com",
      port: 587,
      secure: false, // 587端口对应非加密连接,开启STARTTLS
      tls: {
        rejectUnauthorized: false // 忽略自签名证书错误,适配服务器环境
      },
      auth: {
        user: "subrata@spineor.com", // 补全完整邮箱地址
        pass: "你的登录密码/应用专用密码",
      },
    });

    const mailOptions = {
      from: "subrata@spineor.com", // 补全完整发件人地址
      to: "muskan@spineor.com",
      subject: "A New Client!",
      text: "welcome to Mailer ",
      html: `<!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Contacted us</title>
      <style>
          *,
          *::before,
          *::after {
              box-sizing: border-box;
              margin: 0;
              padding: 0;
          }
          table {
              border-collapse: collapse;
              box-shadow: 0 5px 10px #e1e5ee;
              text-align: left;
              overflow: hidden;
              width: 100%;
          }
          thead {
              box-shadow: 0 5px 10px #e1e5ee;
          }
          th {
              padding: .5rem 1rem;
              text-transform: uppercase;
              letter-spacing: 0.1rem;
              font-size: 0.7rem;
              font-weight: 900;
          }
          td {
              padding: .5rem 1rem;
          }
          a {
              text-decoration: none;
              color: #2962ff;
          }
          .status {
              border-radius: 0.2rem;
              background-color: red;
              padding: 0.2rem 1rem;
              text-align: center;
          }
          .status-pending {
              background-color: #fff0c2;
              color: #a68b00;
          }
          .status-paid {
              background-color: #c8e6c9;
              color: #388e3c;
          }
          .status-unpaid {
              background-color: #ffcdd2;
              color: #c62828;
          }
          .amount {
              text-align: right;
          }
          tr:nth-child(even) {
              background-color: #f4f6fb;
          }
      </style>
  </head>
  <body>
      <table width="100%" border="0" align="center" cellpadding="0" cellspacing="0">
          <tbody>
              <tr>
                  <td align="center">
                      <table class="col-600" width="600" border="0" align="center" cellpadding="0" cellspacing="0">
                          <tbody>
                              <tr>
                                  <td align="center" valign="top" bgcolor="#66809b"
                                      style="background-size:cover; background-position:top;height:400px">
                                      <table class="col-600" width="600" height="200" border="0" align="center"
                                          cellpadding="0" cellspacing="0">
                                          <tbody>
                                              <tr>
                                                  <td height="40"></td>
                                              </tr>
                                              <tr>
                                                  <td height="50"></td>
                                              </tr>
                                          </tbody>
                                      </table>
                                  </td>
                              </tr>
                          </tbody>
                      </table>
                  </td>
              </tr>
              <tr>
                  <td align="center">
                      <table class="col-600" width="400" border="0" align="center" cellpadding="0" cellspacing="0"
                          style="margin-left:20px; margin-right:20px;">
                          <tbody>
                              <tr>
                                  <td align="center">
                                      <table class="col-600" width="400" border="0" align="center" cellpadding="0"
                                          cellspacing="0"
                                          style=" border-left: 1px solid #dbd9d9; border-right: 1px solid #dbd9d9;">
                                          <tbody>
                                              <tr>
                                                  <td height="50"></td>
                                              </tr>
                                              <tr>
                                                  <td align="center">
                                                      <table>
                                                          <thead>
                                                              <tr>
                                                                  <th>Name</th>
                                                                  <th>Email</th>
                                                                  <th>Phone</th>
                                                                  <th>Query</th>
                                                              </tr>
                                                          </thead>
                                                          <tr>
                                                              <td>${formData.name}</td>
                                                              <td>${formData.email}</td>
                                                              <td>${formData.phone}</td>
                                                              <td>${formData.query}</td>
                                                          </tr>
                                                      </table>
                                                  </td>
                                              </tr>
                                              <tr>
                                                  <td height="50"></td>
                                              </tr>
                                          </tbody>
                                      </table>
                                  </td>
                              </tr>
                          </tbody>
                      </table>
                  </td>
              </tr>
          </tbody>
      </table>
  </body>
  </html>`,
    };
    // 等待邮件发送完成再返回响应
    const info = await transporter.sendMail(mailOptions);
    console.log("Email sent: " + info.response);
    // 可根据业务需求调整返回内容
    return res.status(200).json({code:200, msg:"邮件发送成功"});
  } catch (error) {
    console.log("mail send error", error);
    return res.status(500).json({code:500, msg:"邮件发送失败", error: error.message});
  }
};

内容的提问来源于stack exchange,提问作者Jaspreet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 06:21:03