最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to synchronously send mails through nodemailer? - Stack Overflow

programmeradmin3浏览0评论

I'm creating an app using nodejs with the nodemailer module to send mails.

The process of my app is to read a list with names and emails, create png diploma files with jimp (based on each name and email) and store and send each one of them through nodemailer to each different mail addresses and after all this is done I want to delete each file but all this in a sync way, because the png diploma and sending the email takes some time:

The syntax of my list is:

const list = [
  [name1, [email protected]]
  [name2, [email protected]]
  [        ...           ]
  [namex, [email protected]]
]

Actually I want to wait for each mail to be sent because gmail seems to have a problem to handle sending multiple mails at time, after sending 13 or 15 mails it shows the next err:

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

So, in order to achieve this, I iterate over the list with a classic for loop (a foreach loop does it in an async way and doesn't let me to keep control over the diploma generation), I process each one of the positions of the

//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 mented this function because even it is declared in an async way it 
    // await utilities.remove(diplomaDir)
}

This is my sendMail function:

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

So in few words my problem is that nodemailer seems to launch all the mails at the same time after finishing the loop (I can confirm this because in my console the logs for "Processing address ..." appears before the ones from nodemailer, so I just want to make this process absolutely synchronous, could anybody help me please? :(

I'm creating an app using nodejs with the nodemailer module to send mails.

The process of my app is to read a list with names and emails, create png diploma files with jimp (based on each name and email) and store and send each one of them through nodemailer to each different mail addresses and after all this is done I want to delete each file but all this in a sync way, because the png diploma and sending the email takes some time:

The syntax of my list is:

const list = [
  [name1, [email protected]]
  [name2, [email protected]]
  [        ...           ]
  [namex, [email protected]]
]

Actually I want to wait for each mail to be sent because gmail seems to have a problem to handle sending multiple mails at time, after sending 13 or 15 mails it shows the next err:

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

So, in order to achieve this, I iterate over the list with a classic for loop (a foreach loop does it in an async way and doesn't let me to keep control over the diploma generation), I process each one of the positions of the

//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 mented this function because even it is declared in an async way it 
    // await utilities.remove(diplomaDir)
}

This is my sendMail function:

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

So in few words my problem is that nodemailer seems to launch all the mails at the same time after finishing the loop (I can confirm this because in my console the logs for "Processing address ..." appears before the ones from nodemailer, so I just want to make this process absolutely synchronous, could anybody help me please? :(

Share Improve this question asked Apr 28, 2019 at 18:05 Rodolfo BocaneGraRodolfo BocaneGra 3577 silver badges23 bronze badges 1
  • the code here has await without async, and async without await. can you please show more code to reduce the ambiguity? As for sending email, this is an asynchronous process as the response won't e back immediately, you will have to wait. How about using Promise.all() ? this will allow you to make several async requests and then deal with them once all have responded. – George Commented Apr 28, 2019 at 18:41
Add a ment  | 

1 Answer 1

Reset to default 7

Your sendMail function is not asynchronous in nature. It is kicking off an asynchronous function (ie. transporter.sendMail) then immediately returning undefined (as there is no return statement).

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);
         }
      });
   });

}

Now when you await mailer.sendMail(mailContent) a promise will be returned & there will actually be something to await. That is, the resolution or rejection of the promise.

Be sure to have a try/catch block enclosing any await operators.

发布评论

评论列表(0)

  1. 暂无评论