[Node.js] 이메일 인증 구현하기 - 인증번호 / 인증 링크 (verify Email)

‍정진철·2023년 4월 6일
1

Nodemailer

  • Emoji를 포함한 Unicode를 지원
  • Plain text는 물론이고, HTML content를 사용
  • SMTP 를 포함한 다양한 전송 방식을 지원
  • OAuth2 인증방식을 지원
  • 그 외 자세한 정보는 공식 사이트 (https://nodemailer.com/about/)

nodemailer 는 Node.js 에서 사용할 수 있는 메일 전송이 가능토록 도와주는 메일 전송 모듈이다.

회원 비밀번호 찾기, 가입 인증 등 다양한 방면으로 활용 가능하다

G-mail 사용시에는 최대 500통 까지의 지원이 가능하다고 한다.


인증 코드 방식

step1

npm 모듈 설치하기

npm i nodemailer

step 2

네이버 STMP 서버 허용

  • Google의 경우 2022년 5월부터 낮은 수준의 이메일 인증을 허용하지 않는다고 하여 네이버로 적용시켰다.

step 3

config 폴더 내 email.js 생성

SMTP (이메일 서버) 서버에 대한 환경 설정 부분

위의 파일은 .gitignore에 심던가 auth 부분에 user,pass 부분은 .env를 활용해 접근한다.

nodemailer로 메일을 발송하기 위해, createTransport( transport [, defaults] ) 메서드를 호출하여 메일 발송 객체를 생성합니다.

createTransport() 메서드의 첫 번째 매개변수인 transport는 transporter 객체에 대한 환경설정 내용을 객체로 받습니다

  • service: 네이버를 이용하기에 naver로 설정해주고
  • SMTP 서버명, 포트번호 입력

step 4

인증번호 생성 및 메일 발신 코드

랜덤 인증번호 생성 코드

메일 발신 코드


export const emailAuth = async(req,res) => {
    const number = generateRandomNumber(111111, 999999)

    const { email } = req.body; //사용자가 입력한 이메일

    const mailOptions = {
        from : "bik1111@naver.com ", // 발신자 이메일 주소.
        to : email, //사용자가 입력한 이메일 -> 목적지 주소 이메일
        subject : " 인증 관련 메일 입니다. ",
        html : '<h1>인증번호를 입력해주세요 \n\n\n\n\n\n</h1>' + number
    }
    smtpTransport.sendMail(mailOptions, (err, response) => {
        console.log("response", response);
        //첫번째 인자는 위에서 설정한 mailOption을 넣어주고 두번째 인자로는 콜백함수.
        if(err) {
            res.json({ok : false , msg : ' 메일 전송에 실패하였습니다. '})
            smtpTransport.close() //전송종료
            return
        } else {
            res.json({ok: true, msg: ' 메일 전송에 성공하였습니다. ', authNum : number})
            smtpTransport.close() //전송종료
            return 

        }
    })
}

사용자가 email을 입력하면 mailOptions에서 해당 이메일을 "to"로 받아 해당 위에서 작성한 email.js의 객체인 smtpTrnasport를 활용해 sendMail 사용하는 것이다.

이메일 전송 ejs 파일

              <form action="/verify-email" method="POST">
                <div class="mb-3">
                  <label class="form-label" for="email">Email</label>
                  <input
                    class="form-control"
                    type="email"
                    id="email"
                    name="email"
                    required
                  />
                  <input type="submit" value="인증 하기" />
                </div>
              </form>

              <form
                action="/register"
                method="POST"
                class="validated-form"
                novalidate
              >
                <div class="mb-3">
                  <label class="form-label" for="username">Username</label>
                  <input
                    class="form-control"
                    type="text"
                    id="username"
                    name="username"
                    autofocus
                    required
                  />
                </div>
                <div class="mb-3">
                  <label class="form-label" for="password">Password</label>
                  <input
                    class="form-control"
                    type="password"
                    id="password"
                    name="password"
                    required
                  />
                </div>
                <button class="btn btn-success btn-block">Register</button>
              </form>

step 5

결과


인증 링크 방식

인증 링크 방식 역시 크게 다르지 않다.

발급 되는 링크에 메일 주소를 추가한 이유는 DB에서 회원가입 승인 상태를 바꾸기 위해 key가 필요하기 때문이고, token은 올바른 경로로 전달이 되었는지 확인하는 용도이다.

토큰 발급 코드

인증 링크 발급 코드

export const emailLinkauth = (req,res) => {

    const result = generateEmailVerificationToken();

    const { email } = req.body;
    const mailOptions = {
        from : "bik1111@naver.com ", // 발신자 이메일 주소.
        to : email, //사용자가 입력한 이메일 -> 목적지 주소 이메일
        subject : 'Verify your email address',
        html: `<p>Please click the following link to verify your email address:</p>
        <p> <a href="http://localhost:3000/verify-email/?email=${email}?token=${result.token}">Verify email</a></p>
        <p>This link will expire on ${result.expires}.</p>`
    }

        smtpTransport.sendMail(mailOptions, (err, response) => {
            console.log(response);
            //첫번째 인자는 위에서 설정한 mailOption을 넣어주고 두번째 인자로는 콜백함수.
            if(err) {
                res.json({ok : false , msg : ' 메일 전송에 실패하였습니다. '})
                smtpTransport.close() //전송종료
                return
            } else {
                res.json({ok: true, msg: ' 메일 전송에 성공하였습니다. ', authNum : number})
                smtpTransport.close() //전송종료
                return 
    
            }
        })
    
    
    }
    

결과


verify email 클릭 시 받는 사람의 이메일 주소와 토큰값이 쿼리 스트링으로 따라온 걸 확인할 수 있다.

따라서 해당 링크에 대한 회원가입 승인 여부에 대한 함수를 만들 수 있게된다.

Ex

router.get("verify-email" , async(req,res) => {
	const email = req.query.email
	const token = req.query.token
    
    const verifyToken = await verifyUser(token)
    
    if (verifyToken or verifyToken.length > 0) { ... }
    
    ..... (생략)


})

ref : https://victorydntmd.tistory.com/113
ref : https://velog.io/@neity16/NodeJs-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EC%9D%B8%EC%A6%9D-%EA%B5%AC%ED%98%84nodemailer


profile
WILL is ALL

0개의 댓글