Как синхронно отправлять почту через nodemailer? - PullRequest
0 голосов
/ 28 апреля 2019

Я создаю приложение, используя nodejs с модулем nodemailer для отправки писем.

Процесс моего приложения заключается в чтении списка с именами и адресами электронной почты, создании файлов дипломов png с jimp (на основе каждого имени и адреса электронной почты), сохранении и отправке каждого из них через nodemailer каждому разные почтовые адреса, и после всего этого я хочу удалить каждый файл, но все это синхронно, потому что диплом png и отправка электронного письма занимают некоторое время:

Синтаксис моего списка:

const list = [
  [name1, email1@mail.com]
  [name2, email2@mail.com]
  [        ...           ]
  [namex, emailx@mail.com]
]

На самом деле я хочу дождаться отправки каждого письма, потому что в gmail, похоже, есть проблема с обработкой отправки нескольких писем за раз, после отправки 13 или 15 писем отображается следующая ошибка:

error:  { Error: Data command failed: 421 4.7.0 Temporary System Problem.  Try again later (10). x12sm4645987otk.1 - gsmtp

Итак, чтобы достичь этого, я перебираю список с классическим циклом for (цикл foreach делает это асинхронно и не позволяет мне контролировать генерацию диплома), я обрабатываю каждый из них из позиций

//Iterating over mails array
for (let i = 0; i < list.length; i++) {
    // Little msg to know what is going on
    console.log(`Processing address ${i} out of ${list.length}`)

    const element = list[i]
    // diplomaData is an object which contains data needed (such as name, course, etc) to create the diploma 
    diplomaData.name = element[0];
    // diplomaDir is the address in which each diploma gets stored, it is returned by the generateDiploma function  
    diplomaDir = await generator.generateDiploma(diplomaData)
    // So once the diploma is generated, I send its address to generateMailContentFunction
    // it returns an object which contains text like a greeting, congratulations and of course, the diploma address 
    mailContent = await mailer.generateMailContent(element, diplomaDir)
    // So the only thing pending is to send the email with the correspondent content
    await mailer.sendMail(mailContent)
    // I've commented this function because even it is declared in an async way it 
    // await utilities.remove(diplomaDir)
}

Это моя функция sendMail:

exports.sendMail = async (mailOptions) => {
    transporter.sendMail(mailOptions, (err, info) => {
        if (err) {
            console.log("error: ", err);
        } else {
            console.log(`Mail sent succesfully!`);
        }
    });
}

Итак, в двух словах моя проблема заключается в том, что nodemailer запускает все письма одновременно после завершения цикла (я могу это подтвердить, потому что в моей консоли журналы «Обработка адреса ...» отображаются перед журналами из nodemailer, так что я просто хочу сделать этот процесс абсолютно синхронным, кто-нибудь может мне помочь, пожалуйста?: (

1 Ответ

1 голос
/ 29 апреля 2019

Ваша функция sendMail не является асинхронной по своей природе. Он запускает асинхронную функцию (т. Е. transporter.sendMail), а затем немедленно возвращает undefined (так как нет оператора return).

exports.sendMail = function(mailOptions){

   return new Promise(function (resolve, reject){
      transporter.sendMail(mailOptions, (err, info) => {
         if (err) {
            console.log("error: ", err);
            reject(err);
         } else {
            console.log(`Mail sent successfully!`);
            resolve(info);
         }
      });
   });

}

Теперь, когда вы await mailer.sendMail(mailContent) вернете обещание, и на самом деле вам будет что ждать. То есть разрешение или отказ от обещания.

Убедитесь, что у вас есть блок try / catch, содержащий все операторы ожидания.

...