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

Nodemailer本地正常但Cyclic.sh部署后无法发送邮件问题排查

问题描述

以下是发送邮件的Node.js函数:

function sendEmail(num, email, customerName) {
    var readHTMLFile = function (path, callback) {
        fs.readFile(path, { encoding: 'utf-8' }, function (err, html) {
            if (err) {
                throw err;
                callback(err);
            }
            else {
                callback(null, html);
            }
            
        });
    };

let transporter = nodemailer.createTransport({
        host: "smtp.gmail.com",
        secure: true,
        port: 465,

        auth: {
            user:process.env.USEREMAIL,
            pass:process.env.USERPASS
        },
    });
 
    readHTMLFile(__dirname + '/views/layouts/first.html', function (err, html) {
        var template = handlebars.compile(html);
        var replacements = {
            otp: `${num}`,
            customerName: `${customerName}`

        };
        var htmlToSend = template(replacements);
        var mailOptions = {
            from: process.env.USEREMAIL,
            to: email,
            subject: "Hello ✔",
            html: htmlToSend
        };
        transporter.sendMail(mailOptions, function (error, response) {
            if (error) {
                console.log(error);
            } else {
                console.log("Email sent");
            }
        });
    });
}

该函数在本地localhost:8000运行时一切正常,但部署到Cyclic.sh平台后,应用正常运行且返回“Email sent”的成功提示,却实际未收到邮件,请问该函数存在什么问题?

问题排查与解决思路

1. Gmail SMTP 授权限制是核心问题

本地能正常发邮件,大概率是因为你本地环境被Gmail信任(比如开启了低安全应用访问,或者用了普通密码),但Cyclic.sh属于云平台,Gmail默认会拦截这类非信任环境的登录请求。解决办法:

  • 给你的Gmail账号开启两步验证,然后生成一个应用专用密码,把这个密码替换环境变量USERPASS的值,别再用原来的账号密码。
  • 这是云环境用Gmail SMTP的标配操作,普通密码在云服务器上基本都会被拦截。

2. 文件路径与错误处理的潜在问题

__dirname + '/views/layouts/first.html'在本地没问题,但Cyclic.sh部署后,项目的文件结构可能和本地有差异,或者__dirname的指向不符合预期,导致模板文件读取失败。而且你的readHTMLFile函数错误处理有bug:如果fs.readFile出错,先throw err再调用callback(err),但throw会直接终止回调函数,callback根本不会执行,这会导致后续的邮件发送逻辑完全没触发。建议:

  • 用path.join(__dirname, 'views', 'layouts', 'first.html')拼接路径,避免不同系统下的路径分隔符问题。
  • 去掉throw err,直接调用callback(err),防止异步回调里的未捕获异常。

3. 邮件被拦截或归为垃圾邮件

就算发送请求成功,Cyclic.sh的服务器IP可能被邮箱服务商标记为垃圾IP,导致邮件直接进垃圾箱或者被拦截。可以:

  • 先检查收件人的垃圾邮件文件夹,看看是不是被归类了。
  • 确保mailOptions里的from地址和你的Gmail账号完全一致,避免因为发件人不符被拦截。

4. 错误日志没抓全

当前代码里transporter.sendMail的回调只打印错误,但Cyclic.sh的日志可能没被你实时查看,实际发送过程中可能有错误,但你只看到了“Email sent”的提示。建议把错误信息用console.error(error)输出,这样能在Cyclic.sh的日志面板里看到具体的错误原因,比如授权失败、IP被限制等,方便定位问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 12:40:32