为什么 nodemailer 发送重复的电子邮件?

Why is nodemailer sending duplicate emails?

所以这是一个非常奇怪的问题,我不希望有人真正对此有答案,但我来这里是想看看是否有人遇到过同样的问题。

我注意到的问题是我们的应用程序似乎在发送重复的电子邮件。例如,我可以从我们的应用程序发送一份报告,它会发送一次该电子邮件,然后看起来恰好在一分钟后发送了另一封。

我正在使用 nodemailer 从我们的应用程序服务器发送电子邮件,我们在办公室使用的默认电子邮件是 Outlook v16.0.12130.20272 使用 IMAP.这些电子邮件是通过我们的 noreply 电子邮件发送的,我相信这是通过 GoDaddy.

托管的

我自己发送了测试电子邮件并查看了网络选项卡以查看是否可能是超时问题,但响应以 200 OK status 完成并且计时也显示为已完成。此外,当我控制台记录响应时,它只发生一次,这让我相信它实际上只发送一封电子邮件。在主机发送电子邮件和我们的收件人实际收到它们之间一定发生了一些事情,但我不太确定。

这里是 server.js 文件。这是发出 smtp 请求的地方。

var nodemailer = require("nodemailer");

const path = require('path');
const express = require('express');
const http = require('http');
const fs = require('fs');
const socketIO = require('socket.io');
const bodyParser = require('body-parser')



import env from '../env.config.json';

const PORT = require('../env.config.json').SERVER.PORT;
const publicPath = path.join(__dirname, '../public');
import api from './routers/api-routing';
//---------------------------------------------------------------------------

var smtpTransport = nodemailer.createTransport({
    service: env.EMAIL.SERVICE,
    host: env.EMAIL.HOST,
    auth: {
        user:env.EMAIL.AUTH.USER,
        pass:env.EMAIL.AUTH.PASS
    }
});

var mailCounter = 0;
var numPeople = 0;

var app = express();
var server = http.createServer(app);
const port = PORT || 3000;
app.use(express.static(publicPath));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true}));

const io = socketIO(server);
app.use('/api', api(app, io));
// require('./routers/api-routing')(app, io);
//$.get("/send", { to: to, subject: subject).value, text: 'html' }, function (data) { });
app.get('*', function (request, response) {
    if (request.get('x-auth')) console.log("x-auth: ", request.get('x-auth'));
    const proto = request.get('X-Forwarded-Proto');
    if (proto) {
        if (proto === 'http') response.redirect(301, "https://ourdomain.com".concat(request.url));
    }
    response.sendFile(path.resolve(__dirname, '../', 'public', 'index.html'))
    if ((request.url).substring(0, 5) == "/send") {
        var mailOptions = {
            to: request.query.to,
            bcc: request.query.bcc,
            subject: request.query.subject,
            text: request.query.text
        }
        //console.log(mailOptions); Read up on NodeMailer for details.
        smtpTransport.sendMail({  //email options
            from: "COMPANY <noreply@ouremail.com>", // sender address.  Must be the same as authenticated user if using Gmail.
            to: mailOptions.to,
            bcc: "COMPANY <noreply@ouremail.com>",    // sending to itself
            subject: mailOptions.subject, // subject
            html: mailOptions.text, // body
        }, function (error, response) {  //callback
            if (error) {
                console.log(error);
            } else {
                console.log("Message sent");
               //console.log("Amount of people getting this email: " + response.accepted.length);
            }

            smtpTransport.close(); // shut down the connection pool, no more messages.  Comment this line out to continue sending emails.
        });
    }

});



io.on('connection', (socket) => {

    require('./middleware/sockets')(socket);


});

server.listen(port, () => {
  console.log(`Server is up on port ${port}.`);
});

这是我们 env.config.file 中与电子邮件相关的部分。

"EMAIL": {
    "SERVICE": "Godaddy",
    "HOST": "smtp.gmail.com",
    "AUTH": {
      "USER": "noreply@ouremail.com",
      "PASS": "OURPASS"
    }
  }

如果有人有任何想法或建议,我将不胜感激,谢谢!

您的电子邮件是根据发送到您服务器的任何请求发送的,因此如果您通过浏览器访问它,浏览器将发送两个请求,一个用于请求的路径,一个用于 favicon.ico 和您'当请求 /favicon.ico 时,我们还会发送电子邮件。

这可能会发生,因为您的路由处理程序配置为:

app.get('*', ...);

这意味着您正在尝试为每个传入的 http 请求发送一封电子邮件,而不考虑路径。

因此,如果您使用位于 http://yourdomain/ 的浏览器访问您的主机,它将首先请求 /,然后浏览器将请求 /favicon.ico,然后您将发送一个第二封邮件。

我的建议是改成这样:

app.get('*', ...);

对此:

app.get('/', ...);

或者,更具体如:

app.get('/sendemail', ...);

因此,您仅在一个特定路径请求上发送电子邮件,它不会在没有其他请求(例如网站图标)时发送电子邮件。您可能想为任何其他路由添加一个通用的 express 404 处理程序。


注意:在 REST 设计中,您可能会发送带有 POST 请求的电子邮件,而不是 GET 请求。 GET 将以不更改任何状态的只读方式检索资源,因此不会产生发送电子邮件的副作用。注意:这与您的问题完全无关,只是对典型 REST 设计的评论。

一段时间后,我终于弄清楚了这种行为的原因。该问题部分与 jfriend00 发布的内容有关。我最终为电子邮件本身制作了一个单独的路由处理程序,这样它就不会干扰主路由处理程序。问题是每个请求仍将通过该路由,因为它正在寻找 * 指示的任何请求,并且如果有人在 http 路由上发出请求而不是 https,那么它会创建第二个请求或在我的例子中是第二封电子邮件。

您可以在此处的这一行中看到发生的情况:

if (proto) {
        if (proto === 'http') response.redirect(301, "https://ourdomain.com".concat(request.url));
    }

实际的解决方法是为电子邮件本身创建一个单独的路由处理程序,然后将我的 nginx 服务器配置为重新路由到 https,如果有人改为访问应用程序的 http 路由。在此之后,我们再也没有遇到过重复的电子邮件。

另一种方法是完全删除 ```*```` 路由处理程序并单独设置其他路由。希望这会在不久的将来对某人有所帮助。