队列中等待"/>
Outlook graph V1.0 API 批量发送邮件时邮件在队列中等待
我们正在使用 outlook graph v1.0 API 在我们的 Node js 服务器中发送电子邮件。为了发送批量电子邮件,我们将电子邮件分成多个块,每个块包含 20 个具有不同消息的收件人。
- 现在考虑一下,我一次发送大量 1000 个收件人,其中包含不同的消息。
- 它分成 50 个块,每块 20 条消息。
- 然后我尝试点击 batch API。
- 现在我将单独过滤状态为429的失败响应,并在我在失败响应中获得的重试超时时间内使用相同的消息重试。
- 在这段时间内,如果任何其他用户试图点击sendMail API,则需要一些时间(20 分钟、30 分钟)才能在收件人的收件箱中收到邮件。但是在我们的服务器中,我们在访问 API 时得到了成功响应。 我们在生活环境中正面临这个问题。
下面附上我为 outlook 邮件服务尝试的代码参考。
从下面的批量电子邮件发送代码开始,我正在使用 sendBulkMail 函数,之后对于我正在使用 sendSingleMail 函数的任何单个电子邮件。
我可以得到任何解决方案吗?
let tokenConfig = {
access_token: '',
token_type: '',
expires_in: 0
};
const isTokenValid = () => {
try {
if (tokenConfig.access_token) {
return (tokenConfig.expires_in > moment().toDate().getTime());
}
return false;
} catch (error) {
return false;
}
};
const getToken = async () => {
try {
if (isTokenValid()) {
return tokenConfig;
}
tokenConfig = {
access_token: '',
token_type: '',
expires_in: 0
};
const tokenUrl = `${config.mail.smtp.azureAadEndpoint}/${config.mail.smtp.tenantId}/oauth2/token`;
const requestBody = {
grant_type: 'client_credentials',
client_id: config.mail.smtp.clientId,
client_secret: config.mail.smtp.clientSecret,
resource: config.mail.smtp.azureGraphEndpoint
};
const bodyPayload = Object.keys(requestBody).map((key) => `${key}=${encodeURIComponent(requestBody[key])}`).join('&');
const headersConfig = { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } };
const tokenResp = await request.post('', tokenUrl, bodyPayload, headersConfig);
tokenConfig = {
access_token: tokenResp.data.access_token,
token_type: tokenResp.data.token_type,
expires_in: moment().add(tokenResp.data.expires_in, 'seconds').toDate().getTime(),
};
return tokenConfig;
} catch (error) {
tokenConfig = {
access_token: '',
token_type: '',
expires_in: 0
};
return tokenConfig;
}
};
const sendMail = async (mailBody, batch = false) => {
try {
const { access_token, token_type } = await getToken();
if (batch) {
const sendMailUrl = `${config.mail.smtp.azureGraphEndpoint}/${config.mail.smtp.azureGraphEndpointVersion}/$batch`;
const headersConfig = {
headers: {
'Content-Type': 'application/json',
Authorization: `${token_type} ${access_token}`
}
};
const mailSendResp = await timeouutSendMail(sendMailUrl, mailBody, headersConfig);
return mailSendResp;
} else {
const sendMailUrl = `${config.mail.smtp.azureGraphEndpoint}/${config.mail.smtp.azureGraphEndpointVersion}/users/${config.mail.fromMailId}/sendMail`;
const headersConfig = {
headers: {
'Content-Type': 'application/json',
Authorization: `${token_type} ${access_token}`
}
};
const mailSendResp = await timeouutSendMail(sendMailUrl, mailBody, headersConfig);
return mailSendResp;
}
} catch (error) {
return Promise.reject(error);
}
};
const retryMailTimeout = (reqBody, batch = false, retrySec = 0) => {
return new Promise((resolve, reject) => {
setTimeout(async () => {
try {
const outlookSendResp = await sendMail(reqBody, batch);
resolve(outlookSendResp);
} catch (error) {
reject(error);
}
}, (retrySec + 1) * 1000);
});
};
const retryMailTillSuccess = async (messages, retrySec = 0) => {
try {
let allMailResponses = [];
const splitRetryMail = async (innerMessages = []) => {
if (!innerMessages.length) { innerMessages = messages; }
let returnResponses = [];
const msgSplits = _.chunk(innerMessages, 20);
for (const msgData of msgSplits) {
const outlookSendResp = await retryMailTimeout({ requests: msgData }, true, (retrySec + 1));
returnResponses = [...returnResponses, ...outlookSendResp.data.responses];
}
const retryResponses = _.filter(returnResponses, { status: 429 }).map(innerData => {
innerData.id = Number(innerData.id);
innerData.headers['Retry-After'] = Number(innerData.headers['Retry-After']);
return innerData;
});
const maxRetrySec = Math.max(...retryResponses.map(o => o.headers['Retry-After']));
const retryMessages = retryResponses.map(retryData => _.find(innerMessages, { id: retryData.id }));
allMailResponses = [...allMailResponses, ..._.filter(returnResponses, respData => { return (respData.status != 429); })].filter((v, i, a) => a.findIndex(v2 => (v2.id === v.id)) === i);
if (retryMessages.length) {
const outlookSendResp = await splitRetryMail(retryMessages, maxRetrySec);
return outlookSendResp;
}
return returnResponses;
};
await splitRetryMail();
return allMailResponses;
} catch (error) {
return Promise.reject(error);
}
};
const sendBulkMail = async (messages = []) => {
try {
if (messages.length) {
messages = messages.map((innerData, idx) => {
innerData.from = config.mail.fromMailId;
if (innerData.htmlTemplate) { innerData.html = innerData.htmlTemplate; }
const mailBody = {
message: {
subject: innerData.subject,
body: {
contentType: ((innerData.htmlTemplate || innerData.html) ? 'HTML' : 'Text'),
content: (innerData.text || (innerData.htmlTemplate || innerData.html))
},
toRecipients: [{
emailAddress: {
address: innerData.to
}
}]
},
saveToSentItems: 'false'
};
if (innerData.mailAttachments && innerData.mailAttachments.length) {
mailBody.message.attachments = innerData.mailAttachments.map(attachementData => {
return {
'@odata.type': '#microsoft.graph.fileAttachment',
name: attachementData.filename,
contentType: attachementData.type,
contentBytes: attachementData.content
};
});
}
return {
id: idx,
url: `/users/${config.mail.fromMailId}/sendMail`,
method: 'POST',
body: mailBody,
headers: {
'Content-Type': 'application/json'
}
};
});
const returnResponses = await retryMailTillSuccess(messages, 1);
return returnResponses;
}
return [];
} catch (error) {
return Promise.reject(error);
}
};
const sendSingleMail = async (toMailId, mailSubject, mailText, mailHtml, mailAttachments) => {
try {
if (typeof toMailId == 'string') {
toMailId = [toMailId];
}
const mailBody = {
message: {
subject: mailSubject,
body: {
contentType: (mailHtml ? 'HTML' : 'Text'),
content: (mailText || mailHtml)
},
toRecipients: toMailId.map(mailId => ({
emailAddress: {
address: mailId
}
}))
},
saveToSentItems: 'false'
};
if (mailAttachments && mailAttachments.length) {
mailBody.message.attachments = mailAttachments.map(attachementData => {
return {
'@odata.type': '#microsoft.graph.fileAttachment',
name: attachementData.filename,
contentType: attachementData.type,
contentBytes: attachementData.content
};
});
}
const outlookSendResp = await sendMail(mailBody);
return outlookSendResp;
} catch (error) {
console.log('\n mail send error...', error);
return Promise.reject(error);
}
};
回答如下:
更多推荐
Outlook graph V1.0 API 批量发送邮件时邮件在队列中等待
发布评论