Node.js/NodeMailer/Express/Outlook smtp 主机 - 超过并发连接限制

Node.js/NodeMailer/Express/Outlook smtp host - Concurrent connections limit exceeded

希望你一切都好。我正在开发一个使用 express 和 nodemailer 的应用程序。我的应用程序成功发送了电子邮件,但问题是我无法以我喜欢的方式一次发送一封电子邮件。我不想将一组地址放入 'to' 字段,我希望每封电子邮件都单独发送。

我已经成功了,但是有一个问题。微软似乎已经写了某种限制,以防止应用程序一次拥有超过一定数量的连接。 (link 在 post 的文档末尾有解释。)

我试图通过一些权宜之计来解决这个问题。不是所有这些我都会麻烦你。其中大部分涉及 setInterval()mapforEach。我不打算发送所有那么多电子邮件 - 当然不是任何一种标准的调情。我什至不希望我的电子邮件中有任何 HTML。只是纯文本。但是,当我的应用程序发送了 2/3 的电子邮件时,我遇到了他们的错误消息(响应代码 432)。

下面你会看到我的代码。

这是我的代码的第一个相关部分。

  db.query(sqlEmailGetQuery, param)
    .then(result => {
      handleEmail(result, response);
    }).catch(error => {
      console.error(error);
      response.status(500).json({ error: 'an unexpected error occured.' });
    });
});

这是第二部分。

function handleEmail(result, response) {
  const email = result.rows[0];
  let i = 0;

  email.json_agg.map(contact => {
    const msg = {
      from: process.env.EMAIL_USER,
      to: email.json_agg[i].email,
      subject: email.subject,
      text: email.emailBody + ' ' + i
    };
    i++;
    return new Promise((resolve, reject) => {
      setInterval(() => {
        transporter.sendMail(msg, function (error, info) {
          if (error) {
            return console.log(error);
          } else {
            response.status(200).json(msg);
            transporter.close();
          }
        });
      }, 5000 + i);
    });
  });
}

随着我对这个问题的理解的加深,我发现我要么想办法等待足够长的时间,这样我就可以发送另一封电子邮件——连接不会超时,或者每次都断开连接当我发送一封电子邮件时,这样当我发送下一封电子邮件时,我就有了新的连接。在我看来,如果后者是可能的,那么每个人都会这样做并违反微软的政策。

我有没有办法解决这个问题,每 3 秒发送 3 封电子邮件,然后等待,再发送三封?电子邮件的数量如此之大,如有必要,我可以等待十秒钟。是否有其他限制较少的 smtp 主机?

请告诉我您的想法。如果有帮助,我的传输配置如下。

const transporter = nodemailer.createTransport({
  pool: true,
  host: 'smtp-mail.outlook.com',
  secureConnection: false,
  maxConnections: 1,
  port: 587,
  secure: false,
  tls: { ciphers: 'SSLv3' },
  auth: {
    user: process.env.EMAIL_USER,
    pass: process.env.EMAIL_PASS
  }
});

https://docs.microsoft.com/en-us/exchange/troubleshoot/send-emails/smtp-submission-improvements#new-throttling-limit-for-concurrent-connections-that-submitmessages

首先,向许多用户发送同一封电子邮件的最有效方法是将其发送给您自己并密件抄送所有收件人。这将允许您向 SMTP 服务器发送一封电子邮件,然后它会将这封电子邮件分发给所有收件人,没有收件人能够看到任何单个收件人的电子邮件地址。

其次,您无法使用计时器可靠地控制一次 运行 请求的数量,因为计时器与给定请求完成所需的时间无关,因此计时器只是对平均时间的猜测一个请求,他们可能在某些情况下工作,而在事情响应较慢时不工作。相反,您必须实际使用一个请求的完成才能知道可以发送下一个请求。

如果您仍想发送单独的电子邮件并连续发送电子邮件,一个接一个地发送,以避免一次处理太多,您可以这样做:

async function handleEmail(result) {
    const email = result.rows[0];
    for (let [i, contact] of email.json_agg.entries()) {
        const msg = {
          from: process.env.EMAIL_USER,
          to: contact.email,
          subject: email.subject,
          text: email.emailBody + ' ' + i
        };
        await transporter.sendMail(msg);
    }
}

如果您不传递 transporter.sendMail() 回调,那么它将 return 一个您可以直接使用的承诺 - 无需将其包装在您自己的承诺中。

请注意,此代码不会发送对您的 http 请求的响应,因为这应该是调用代码的责任,而您之前的代码试图为每封电子邮件发送响应,而您只能发送一个响应如果出现错误,之前的代码不会发送任何响应。

这段代码依赖于 returned 承诺返回给调用者来传达它是成功还是遇到错误,然后调用者可以决定如何处理这种情况。

你也不应该将 result 传递给这个函数,而应该只传递 email 因为没有理由让这段代码知道它必须进入某些数据库查询结果才能得到它需要的值。这应该是调用者的责任。那么,这个函数就通用多了。

如果您不想一次发送一封电子邮件,而是一次发送 N 封电子邮件,则可以使用 之类的方法来做到这一点。它迭代一个数组并同时保持最多 N 个请求。