Node.js/NodeMailer/Express/Outlook smtp 主机 - 超过并发连接限制
Node.js/NodeMailer/Express/Outlook smtp host - Concurrent connections limit exceeded
希望你一切都好。我正在开发一个使用 express 和 nodemailer 的应用程序。我的应用程序成功发送了电子邮件,但问题是我无法以我喜欢的方式一次发送一封电子邮件。我不想将一组地址放入 'to' 字段,我希望每封电子邮件都单独发送。
我已经成功了,但是有一个问题。微软似乎已经写了某种限制,以防止应用程序一次拥有超过一定数量的连接。 (link 在 post 的文档末尾有解释。)
我试图通过一些权宜之计来解决这个问题。不是所有这些我都会麻烦你。其中大部分涉及 setInterval()
和 map
或 forEach
。我不打算发送所有那么多电子邮件 - 当然不是任何一种标准的调情。我什至不希望我的电子邮件中有任何 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 循环
email.json_agg[i].email
,但很明显,一旦我达到连接限制,它就停止工作了。
- 我使用了 Whosebug 并查看了性质相似的问题。例如,this 问题几乎是相似的,但是这个人有超过 8000 个连接,如果你阅读下面我 post 由微软编写的规则,他们在 之后实施了连接规则 他做到了 post.
- 我已经尝试过
setInterval
和 forEach
以及 await
因为它与每个承诺相关联,但是因为这不是问题的根源,所以这也不起作用。
- 我已经尝试过与您在上面看到的类似的代码,只是我将间隔设置为长达 20 秒。
随着我对这个问题的理解的加深,我发现我要么想办法等待足够长的时间,这样我就可以发送另一封电子邮件——连接不会超时,或者每次都断开连接当我发送一封电子邮件时,这样当我发送下一封电子邮件时,我就有了新的连接。在我看来,如果后者是可能的,那么每个人都会这样做并违反微软的政策。
我有没有办法解决这个问题,每 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
}
});
首先,向许多用户发送同一封电子邮件的最有效方法是将其发送给您自己并密件抄送所有收件人。这将允许您向 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 个请求。
希望你一切都好。我正在开发一个使用 express 和 nodemailer 的应用程序。我的应用程序成功发送了电子邮件,但问题是我无法以我喜欢的方式一次发送一封电子邮件。我不想将一组地址放入 'to' 字段,我希望每封电子邮件都单独发送。
我已经成功了,但是有一个问题。微软似乎已经写了某种限制,以防止应用程序一次拥有超过一定数量的连接。 (link 在 post 的文档末尾有解释。)
我试图通过一些权宜之计来解决这个问题。不是所有这些我都会麻烦你。其中大部分涉及 setInterval()
和 map
或 forEach
。我不打算发送所有那么多电子邮件 - 当然不是任何一种标准的调情。我什至不希望我的电子邮件中有任何 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 循环
email.json_agg[i].email
,但很明显,一旦我达到连接限制,它就停止工作了。 - 我使用了 Whosebug 并查看了性质相似的问题。例如,this 问题几乎是相似的,但是这个人有超过 8000 个连接,如果你阅读下面我 post 由微软编写的规则,他们在 之后实施了连接规则 他做到了 post.
- 我已经尝试过
setInterval
和forEach
以及await
因为它与每个承诺相关联,但是因为这不是问题的根源,所以这也不起作用。 - 我已经尝试过与您在上面看到的类似的代码,只是我将间隔设置为长达 20 秒。
随着我对这个问题的理解的加深,我发现我要么想办法等待足够长的时间,这样我就可以发送另一封电子邮件——连接不会超时,或者每次都断开连接当我发送一封电子邮件时,这样当我发送下一封电子邮件时,我就有了新的连接。在我看来,如果后者是可能的,那么每个人都会这样做并违反微软的政策。
我有没有办法解决这个问题,每 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
}
});
首先,向许多用户发送同一封电子邮件的最有效方法是将其发送给您自己并密件抄送所有收件人。这将允许您向 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 封电子邮件,则可以使用