2017-02-04 2 views
1

저는 NodeJS/Express 서버에서 메일을 보내려 할 때 Nodemailer을 사용하고 있습니다. 직접 메일을 보내는 대신 메일을 보내기 전에 20 분을 기다리고 싶습니다. 나는 이것이 개인적으로 느끼고 메일을 직접 보내는 것 같다고 생각한다.NodeJS가 지연된 전자 메일을 보내고 있습니다.

그러나 어떻게해야하는지 잘 모릅니다. 나는이 NodeCron 패키지처럼 NodeJS cronjob과 같은 것이 필요하지 않다고 생각하니?

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

저는 CharlieBrown의 대답이 정확하다고 생각합니다. 질문을 읽는 동안 내 마음 속에 두 가지 답이 있었기 때문에, 그의 대답을 단순화 해 주신 것에 대해 감사드립니다.

setTimeout 실제로는 좋은 생각이지만 서버 코드를 중지 할 이유가있는 경우 (서버 다시 시작, 모듈 설치, 파일 관리 등)에는 단점이 있습니다.) setTimeout의 시간 매개 변수 끝에 예약 된 콜백이 실행되지 않고 일부 사용자는 전자 메일을받지 못합니다.

위의 문제가 심각하다면 예약 된 이메일을 데이터베이스 또는 Redis에 저장하고 cron 작업을 사용하여 이메일 세트를 정기적으로 확인하고 이메일이있는 경우 이메일을 보내도록 할 수 있습니다.

본인의 취향과 필요에 따라이 대답이나 CharlieBrown 's가 충분하다고 생각합니다.

+0

안녕하세요 Lajos, 당신도 내 마음을 읽고, 나는 같은 우려를 포함하도록 내 대답을 업데이 트했습니다 :) – CharlieBrown

+0

@CharlieBrown 네, 그것은 우리 모두 비슷하게 생각하는 것 같습니다 :) –

+0

@CharlieBrown과 함께 이것을 지적 해 주셔서 고맙습니다! 나는이 해결책을 찾아 가서 표식을 받아 들였다. – ronnyrr

3

글쎄, 사람들이 여기 와서 외부 대기열 시스템과 bla bla를 사용하라고 말할 수도 있습니다 ...하지만 여러분은 간단하게 일반 오래된 자바 스크립트를 사용하여 앞으로 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) POST 처리기 안에 transport을 새로 만들 필요가 없습니다. 외부에서 만들고 재사용 할 수 있습니다.

2) 언급 된 문제 외에도 서버가 손상된 경우 이메일을 보내지 않습니다.

3)이 노드에 대한 모든 요청에 ​​대해 전자 메일을 예약하지 않고 단일 Node.js 응용 프로그램에서 계속 수행하려는 경우 전자 메일 데이터 (from, subject, body)를 저장하는 것이 좋습니다.) 어딘가에서을 선택하고 20 분마다 모든 보류중인 전자 메일을 수신하고 하나씩 보내고 20 분 후에 다시 실행되도록 일정을 조정하는 기능을 예약합니다. 이렇게하면 메모리 사용량이 적게 유지됩니다. 서버 충돌로 인해 여전히 모든 이메일이 손실되지만, REDIS를 믹스에 추가하면 앱이 시작될 때 REDIS의 모든 보류중인 이메일을 간단히 가져올 수 있습니다.

아마도 대답이 너무 많아서 필요하지 않은 경우 미안 해요! :)

+0

답장을 보내 주셔서 감사합니다. 이것은 꽤 심각한 프로젝트이기 때문에'setTimeout'은 솔리드 옵션이 아니라고 생각합니다. 나는 외부 데이터를 저장하고 cronjob을 사용하여 매 20 분마다 점검 할 것이다. Redis를 지적 해 주셔서 고맙습니다. 그러나 MongoDB가 나를 위해 조금 더 잘 작동 할 것이라고 생각합니다. :) 추신 : 귀하의 편집 팁 주셔서 감사합니다. 1)이 다루어지면, 이것은 단순화되었다. 다른 것은 주요 쟁점과 관련이 있지만 어쨌든 감사합니다. – ronnyrr

관련 문제