Отправить почту используя setTimeout - PullRequest
1 голос
/ 16 марта 2020

Я хотел бы отправлять электронные письма каждые 200 мс, но кажется, что они не работают с обещаниями:

Моя функция:

SendMail.send = function(from, to, subject, body, name, logo) {
  var transporter, html,
      contactparam = _.find(options.blocks, { name: 'contactparam' }).params,
      smtpUsername = _.find(contactparam, { name: 'smtp_username' }),
      smtpPassword = _.find(contactparam, { name: 'smtp_password' }),
      smtpHost = _.find(contactparam, { name: 'smtp_host' }),
      smtpPort = _.find(contactparam, { name: 'smtp_port' }),
      compagny = _.find(contactparam, { name: 'compagny' }),
      firstname = _.find(contactparam, { name: 'firstname' }),
      facebookUrl = _.find(_.find(options.blocks, { name: 'socialparam' }).params, { name: 'facebook' }).value,
      twitterUrl = _.find(_.find(options.blocks, { name: 'socialparam' }).params, { name: 'twitter' }).value,
      linkedinUrl = _.find(_.find(options.blocks, { name: 'socialparam' }).params, { name: 'linkedin' }).value,
      secondaryColor = _.find(_.find(options.blocks, { name: 'themeparam' }).params, { name: 'secondary_color' }).value,
      loadedLogo = logo || _.find(_.find(options.blocks, { name: 'logoparam' }).params, { name: 'logo' }).value,
      websiteUrl = _.find(_.find(options.blocks, { name: 'mainparam' }).params, { name: 'url' }).value,
      templateFile = fs.readFileSync('./app/views/0-templates/' + options.template + '/mail.ejs', 'utf-8'),
      loadedName = name || (compagny && compagny.value) || (firstname && name && firstname.value + ' ' + name.value),
      ejsTemplate = ejs.compile(templateFile);

  html = ejsTemplate({
    logo: loadedLogo || '/images/LOGO.png',
    websiteUrl: websiteUrl,
    body: body,
    title: subject,
    facebookUrl: facebookUrl,
    twitterUrl: twitterUrl,
    linkedinUrl: linkedinUrl,
    secondaryColor: secondaryColor || '#1c1c1c'
  });

  if ((smtpUsername && smtpUsername.value !== '') && (smtpPassword && smtpPassword.value !== '') && (smtpHost && smtpHost.value !== '') && (smtpPort && smtpPort.value !== '')) {
    transporter = nodemailer.createTransport({
      host: smtpHost.value,
      pool: true,
      port: parseInt(smtpPort.value, 10),
      auth: {
        user: smtpUsername.value,
        pass: smtpPassword.value
      }
    });
  } else {
    transporter = nodemailer.createTransport({
      sendmail: true,
      newline: 'unix',
      path: '/usr/sbin/sendmail'
    });
  }

  return transporter.sendMail({
    from: loadedName + ' <' + from + '>',
    replyTo: from,
    to: to,
    subject: subject,
    html: html
  });
};

SendMail.arraySend = function(array) {
  var promises = [];
  promises = array.map(function (emailObj, index) {
    return new Promise(function () {
      setTimeout(function () {
        return sendMailHelper.send(emailObj.from, emailObj.to, emailObj.title, emailObj.htmlMessage);
      }, 200 * index);
    });
  });
  return promises;
};

Использование моего функция:

Promise.all(sendMailHelper.arraySend(emailsArray)).then( function() {
  request.flash('success', 'Emails sent !');
  response.redirect('/');
});

emailsArray:

emailsArray.push({
  from: from,
  to: registration.cfc_user.email,
  title: 'Finale : ' + newTournament.name,
  htmlMessage: htmlMessage
});

Проблема: электронные письма не отправляются.

Ответы [ 2 ]

0 голосов
/ 16 марта 2020

Вы не можете return из функции, вызванной по таймауту. Кроме того, не стоит называть такое количество Обещаний хорошей идеей.

Лучший способ - сгруппировать все ваши электронные письма в одном Обещании, возвращая объект отправленных электронных писем и сообщений с ошибками:

SendMail.arraySend = array => {
    return new Promise(resolve => {
        let sent = [];
        let errors = [];

        const finalise = () => {
            if ((sent.length + errors.length) >= array.length) {
                resolve({ sent, errors });
            }
        };

        array.forEach((emailObj, index) => {
            setTimeout(function () {
                sendMailHelper.send(emailObj.from, emailObj.to, emailObj.title, emailObj.htmlMessage)
                .then(() => {
                    sent.push(emailObj);
                    finalise();
                });
                .catch(() => {
                    errors.push(emailObj);
                    finalise();
                })
            }, 200 * index);
        });
    });
};
0 голосов
/ 16 марта 2020

Прежде всего, вам нужно разрешить обещания, которые вы создаете. Без разрешения (или отклонения) их, Promise.all будет ждать вечно.

Кроме того, .sendMail() возвращает Обещание при вызове, так что это можно использовать, чтобы убедиться, что отложенное Обещание разрешить только после фактической отправки:

SendMail.arraySend = function(array) {
  var promises = array.map(function (emailObj, index) {
    return new Promise(function (resolve, reject) { //<-- add the resolve/reject parameters
      setTimeout(function () {
        sendMailHelper
          .send(emailObj.from, emailObj.to, emailObj.title, emailObj.htmlMessage)
          .then(resolve)  // <-- resolve the Promise once execution is done
          .catch(reject); // <-- reject on failure
      }, 200 * index);
    });
  });
  return promises;
};

Это запустит все Обещания сразу, но каждое сработает в пределах 200 мс друг от друга. Фактической отправке может потребоваться некоторое время, но в конечном итоге все будет сделано.

В качестве альтернативы, вы можете настроить его так, чтобы после выполнения каждого обещания вы подождали 200 мс, а затем запустили еще одно. Это будет означать, что в конце вы получите один объект Promise, а не массив, но гарантируется, что сообщения отправляются последовательно. Это легко сделать, используя Array#reduce

//helper function that converts email objects to be sent into Promises
const delayedSend = (emailObj, delay) => () => {
  return new Promise((resolve, reject) => {
    setTimeout(
      () => sendMailHelper.send(emailObj.from, emailObj.to, emailObj.title, emailObj.htmlMessage)
        .then(resolve)
        .catch(reject);
      }, 
      delay
    )
  })
}

SendMail.arraySend = function(array) {
  var promises = array.reduce(function (sequence, emailObj) {
//                     ^^^^^^ reduce to convert to a single Promise
    return sequence.then(delayedSend(emailObj, 200)); // <-- chain .then() and delay each following execution
  }, Promise.resolve());
//   ^^^^^^^^^^^^^^^^^ initial value is a simple resolved Promise.  
  return promises;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...