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

史蒂夫

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

我已经成功了,但是有一个问题。Microsoft 似乎已经编写了某种限制,以防止应用程序一次具有超过一定数量的连接。(链接与帖子文件末尾的解释。)

我试图通过一些权宜之计解决这个问题。不是所有这些我都会给你带来麻烦。其中大多数涉及setInterval()和 或mapforEach我不打算发送那么多电子邮件——当然不是为了挑逗任何类型的标准。我什至不想在我的电子邮件中包含任何 HTML。只是纯文本。但是,当我的应用程序发送 2/3 电子邮件时,我遇到了它们的错误消息(响应代码 432)。

下面你会看到我的代码。

  • 如您所见,我什至愿意尝试将增量器添加到 setInterval 中,好像更改电子邮件触发的间隔实际上会有所帮助。
  • 现在,这是发送一些电子邮件,但我最终遇到了那个块。这通常发生在 2/3 左右的电子邮件中。然而,它奇怪地不一致。

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

  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);
    });
  });
}
  • 我最初尝试了一个简单的 for 循环遍历联系人 iterable email.json_agg[i].email,但显然一旦我达到连接限制,它就停止工作。
  • 我来到了 stackoverflow 并审查了性质相似的问题。例如,这个问题几乎是相似的,但是这个人有超过 8000 个连接,如果你阅读我在下面由微软发布的规则,他们发布该帖子实施了连接规则
  • 我曾尝试setIntervalforEachawait因为它与每个连接的承诺,但是这不是问题的根源,这也不能工作。
  • 我尝试了与您在上面看到的类似的代码,但我已将间隔设置为 20 秒。

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

有没有办法让我解决这个问题,每说 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

jfriend00

首先,将同一封电子邮件发送给大量用户的最有效方法是将其发送给您自己并密件抄送所有收件人。这将让您向 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()回调,那么它将返回一个您可以直接使用的承诺 - 无需将其包装在您自己的承诺中。

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

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

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

如果您不想一次发送一封电子邮件,而是想一次发送 N 封电子邮件,则可以使用类似的方法mapConcurrent()来执行此操作。它迭代一个数组并同时保持最多 N 个请求。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

PHPMailer + smtp.gmail.com:无法连接到SMTP主机

PHPMailer,SMTP错误无法连接到smtp主机

xampp + PHPMailer + Gmail = SMTP 错误:无法连接到 SMTP 主机

无法与主机建立 Prestashop SMTP 连接

javax.mail.MessagingException:无法连接到SMTP主机?

无法连接到SMTP主机:smtp.gmail.com,端口:465

无法连接到SMTP主机:smtp.office365.com,端口:587;

Spring Boot-无法连接到SMTP主机:smtp.gmail.com,端口:25,响应:421

Jenkins电子邮件插件:无法连接到SMTP主机:smtp.gmail.com,端口:465;

javax.mail.MessagingException:无法连接到SMTP主机:<主机名>端口:25响应:554

Yii2:在godaddy主机中无法与主机smtp.gmail.com建立连接[连接被拒绝#111]

使用Gmail SMTP的SwiftMailer突然停止工作:无法与主机smtp.gmail.com建立连接[#0]

java.lang.RuntimeException:javax.mail.MessagingException:无法连接到SMTP主机:smtp.gmail.com,端口:465

javax.mail.MessagingException: 无法连接到 SMTP 主机:smtp.gmail.com,端口:587 无法解决此问题

Laravel在Localhost上-无法与主机smtp.gmail.com建立连接[连接超时#110]

无法在laravel 5.2中与主机smtp.gmail.com建立连接[连接超时#110]

Swift_TransportException·无法与主机smtp.sendgrid.net建立连接[连接超时#110]

javax.mail.MessagingException:无法连接到SMTP主机:172.16.100.185,端口:25;

无法与主机smtp.gmail.com建立连接[权限被拒绝#13]

使用 hosts.deny 拒绝来自未知和未经验证的主机的 smtp 连接

(AWS SES / Laravel) - 无法与主机 smtp.mailtrap.io 建立连接

mutt:无法连接到<smtp_url>(没有通往主机的路由)

应用程序无法使用Docker连接到SMTP主机和端口587

发送邮件错误,javax.mail.MessagingException:无法连接到SMTP主机:localhost,端口:25;

“无法与主机smtp.gmail.com建立连接”。Symfony。迅捷邮件

MailConnectException:无法连接到主机,端口:smtp.gmail.com,465; 超时-1

将Node express限制为特定的主机名?

如何从本地主机发送SMTP邮件

smtp 主机在 android 中设置为 localhost