2017-02-04 69 views
1

Я использую Nodemailer для отправки рассылок на моем сервере NodeJS/Express. Вместо прямой отправки почты я хочу подождать 20 минут, прежде чем отправлять почту. Я думаю, что это кажется более личным, чем отправка почты напрямую.NodeJS отправка электронной почты с задержкой

Но я не знаю, как этого добиться. Думаю, мне не нужно что-то вроде NodeJS cronjob вроде этого NodeCron, или я?

router.post('/', (req, res) => { 
    const transporter = nodemailer.createTransport(smtpTransport({ 
     host: 'smtp.gmail.com', 
     port: 465, 
     auth: { 
      user: '[email protected]', 
      pass: 'pass123' 
     } 
    })); 

    const mailOptions = { 
     from: `"${req.body.name}" <${req.body.email}>`, 
     to: '[email protected]', 
     subject: 'Form send', 
     html: `Content` 
    }; 

    transporter.sendMail(mailOptions, (error, info) => { 
     if (error) res.status(500).json({ responseText: error }); 
     res.status(200).json({ responseText: 'Message send!' }); 
    }); 
    } 
}); 

Мой маршрутизатор выглядит, как показано выше. Поэтому, если сообщение вызвано, я хочу, чтобы этот запрос подождал 20 минут. Вместо того, чтобы с помощью cronjob я хочу выполнить пост только один раз, но с небольшой задержкой. Любые предложения о том, как это сделать?

ответ

2

Я думаю, что ответ Чарли Бруна верен, и, поскольку у меня было два ответа, когда я читал вопрос, я благодарю его за то, что он упростил мой ответ, чтобы стать его альтернативой.

setTimeout на самом деле хорошая идея, но имеет недостаток: в случае, когда есть какие-либо причины для остановки кода сервера (перезагрузка сервера, установка модуля, управление файлами и т. Д.) ваши обратные вызовы, запланированные в конце параметра времени setTimeout, не будут выполнены, и некоторые пользователи не получат электронные письма.

Если проблема выше достаточно серьезная, тогда вы можете захотеть сохранить запланированные электронные письма для отправки в базе данных или в Redis и использовать задание cron для периодической проверки набора электронной почты и отправки электронных писем, если они есть.

Я думаю, что для ответа на этот вопрос или для CharlieBrown вам достаточно, в зависимости от ваших предпочтений и потребностей.

+0

Эй, Лайош, ты тоже прочитал мой разум, я только что обновил свой ответ, чтобы включить те же проблемы :) – CharlieBrown

+0

@CharlieBrown да, кажется, мы здесь похожи друг на друга :) –

+0

Большое спасибо за указание на это вместе с @CharlieBrown! Я пойду за этим решением и отметю как мой принятый ответ. – ronnyrr

3

Ну, некоторые люди могут приехать сюда и сказать вам использовать внешнюю систему очередей и бла-бла ... Но вы могли бы просто использовать простой старый Javascript, чтобы запланировать отправку 20 * 60 * 1000 миллисекунд в будущее, чтобы начать все , :)

Существует, однако, проблема с вашим кодом: вы ожидаете, что почтовая программа будет успешной, прежде чем отправлять ответ 200 - «Сообщение отправлено» пользователю. Назовите меня сумасшедшим, но я уверен, что пользователь не будет смотреть на окно браузера в течение 20 минут, так что вам, вероятно, придется ответить как можно скорее, а затем запланировать почту. Изменение вашего кода:

router.post('/', (req, res) => { 
    const DELAY = 20*60*1000 // min * secs * milliseconds 
    const transporter = nodemailer.createTransport(smtpTransport({ 
     host: 'smtp.gmail.com', 
     port: 465, 
     auth: { 
      user: '[email protected]', 
      pass: 'pass123' 
     } 
    })); 

    const mailOptions = { 
     from: `"${req.body.name}" <${req.body.email}>`, 
     to: '[email protected]', 
     subject: 'Form send', 
     html: `Content` 
    }; 

    res.status(200).json({ responseText: 'Message queued for delivery' }); 

    setTimeout(function(){ 
     transporter.sendMail(mailOptions, (error, info) => { 
     if (error) 
      console.log('Mail failed!! :(') 
     else 
      console.log('Mail sent to ' + mailOptions.to) 
     }), 
     DELAY 
    ); 
    } 
}); 

Существует множество возможных недостатков этого решения. Если вы ожидаете большой трафик на этой конечной точке, вы можете получить много запланированных обратных вызовов, которые будут потреблять стек. Кроме того, если что-то не удается, пользователь, конечно, не сможет это знать.

Если это большой/серьезный проект, подумайте об использовании этого пакета cronjob или использовании внешнего механизма хранения, где вы можете поставить в очередь эти «ожидающие» сообщения (Redis будет делать, и это невероятно просто) и выполнять разные задачи чтения процесса оттуда и выполнить отправку электронной почты.

РЕДАКТИРОВАТЬ: еще что-то увидели на вашем коде.

1) Вам, вероятно, не нужно создавать новый transport внутри вашего обработчика POST, создавать его снаружи и повторно использовать.

2) В дополнение к указанным проблемам, если ваш сервер разбился, никакое электронное письмо никогда не будет отправлено.

3) Если вы все еще хотите сделать это в одном приложении Node.js, вместо того, чтобы планировать электронную почту по каждому запросу этой конечной точке, вам лучше хранить данные электронной почты (от, до, темы, тела) где-то и планировать каждые 20 минут функцию, которая будет получать все ожидающие сообщения электронной почты, отправлять их по одному, а затем перенести на повторный запуск через 20 минут. Это позволит вам снизить потребление памяти. Сбой сервера все еще потерял все электронные письма, но если вы добавите REDIS в микс, вы можете просто захватить все ожидающие сообщения от REDIS, когда начнется ваше приложение.

Возможно, слишком много для ответа, извините, если не было необходимости! :)

+0

Спасибо за ваш полный ответ. Поскольку это довольно серьезный проект, я думаю, что 'setTimeout' не является надежным вариантом. Я поеду для внешнего сохранения данных и использования cronjob, чтобы проверить его каждые 20 минут или около того. Спасибо, что указал на Redis, но я думаю, что MongoDB будет работать лучше для меня :). PS: спасибо за советы по редактированию. 1), это было упрощено. Другие связаны с основной проблемой, но в любом случае спасибо. – ronnyrr