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

使用Nodemailer发验证链接遇阻:开发正常,Cyclic.sh部署后Gmail拦截邮件

部署到Cyclic.sh后Nodemailer发送Gmail验证邮件失败且被拦截

我用Nodemailer给用户发邮箱验证链接,本地开发模式下邮件能正常送到用户邮箱,但部署到Cyclic.sh之后,邮件发不出去,还会被Gmail拦截。

拦截提示截图:
Gmail拦截提示

相关代码:

const nodemailer = require('nodemailer');
const jwt = require("jsonwebtoken");
const path = require("path");
if(process.env.NODE_ENV !== "production") {
    require('dotenv').config({ path: path.join(__dirname, "..", ".env") });
}

const transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
        user: process.env.MAIL_ID,
        pass: process.env.MAIL_PASSWORD
    }
});

module.exports = {
    sendVerificationLink: async (id, email, name) => {
        const token = jwt.sign({
            data: { userid: id, name: name, email: email },
            exp: Math.floor(Date.now() / 1000) + (60 * 60) 
        }, process.env.ACCESS_TOKEN_SECRET);
        const mailOptions = {
            from: process.env.MAIL_ID,
            to: `${email}`,
            subject: "Verify your email",
            html: `
                    <p>Hi ${name}, please click on the following link to verify your email</p>
                    <a href = "http://${process.env.DOMAIN}/auth/verify/${token}">Verify your email</a>
                  `
        };
        await transporter.sendMail(mailOptions);
        return;
    }
}

问题原因及解决办法

1. 修复Gmail账户权限问题

本地能用是因为开发机器IP在Gmail信任列表里,但Cyclic.sh的服务器IP属于陌生地址,Gmail会判定为风险登录直接拦截。按以下步骤操作:

  • 登录Gmail账户进入「安全」设置,开启两步验证。
  • 两步验证开启后,在同页面找到「应用专用密码」,生成一个仅用于Nodemailer的密码,替换.env里的MAIL_PASSWORD。
  • 确保「不太安全的应用访问」处于关闭状态(该选项已被两步验证替代,无需开启)。

2. 优化邮件内容降低垃圾邮件判定概率

Gmail的反垃圾机制会严格检查邮件属性:

  • 给发件人添加友好名称:把from字段改成"你的应用名称" <${process.env.MAIL_ID}>,比如from: "MyApp <myapp@gmail.com>",提升邮件辨识度。
  • 替换HTTP链接为HTTPS:部署后的DOMAIN要使用HTTPS开头,HTTP链接会被标记为不安全,触发拦截。
  • 可选:在邮件底部添加退订提示,符合邮件发送规范,减少被判定为垃圾邮件的可能。

3. 调整Nodemailer的SMTP配置

使用service: 'gmail'偶尔会有兼容性问题,换成明确的SMTP配置更稳定:

const transporter = nodemailer.createTransport({
    host: 'smtp.gmail.com',
    port: 465,
    secure: true, // 启用SSL加密
    auth: {
        user: process.env.MAIL_ID,
        pass: process.env.APP_SPECIFIC_PASSWORD // 这里填应用专用密码
    }
});

4. 检查Cyclic.sh环境变量配置

确保Cyclic.sh后台的环境变量里,MAIL_ID、APP_SPECIFIC_PASSWORD、DOMAIN都配置正确,没有拼写错误,同时NODE_ENV设置为production,避免本地dotenv的影响。

5. 捕获错误日志排查问题

在sendMail代码中添加错误捕获,方便查看具体失败原因:

try {
    await transporter.sendMail(mailOptions);
} catch (error) {
    console.error('邮件发送失败:', error);
    throw error; // 根据业务需求处理错误
}

然后在Cyclic.sh的控制台查看日志,能精准定位是认证失败、连接超时还是其他问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 19:15:01