개발일지
개발일지 46일차
index.ys
2023. 5. 6. 23:52
Nodemailer로 이메일 인증기능 구현
- 회원가입시 body 입력 받은 이메일에 인증코드를 전송하고 전송받은 코드를 input에 입력시 회원가입이 가능하게 하는 코드 구현
ejs, dotenv, nodemailer 패키지 설치
npm install dotenv nodemailer ejs
모듈 require
const nodemailer = require('nodemailer');
const ejs = require('ejs');
메일에 ejs를 첨부하여 전송코드 작성
let emailTemplete;
ejs.renderFile(appDir + '/template/authMail.ejs', { authCode: authNum }, function (err, data) {
if (err) { console.log(err) }
emailTemplete = data;
});
createTransport 메소드로 발신자 정보 설정
- service: 구글이나 네이버 등 서비스명 기입 ex) Naver, Gmail
- user: 보내는 사람의 이메일 설정 ex) sdnfie@naver.com으로 설정하면 보내는 사람의 이메일로 설정 여기서는 환경변수로 이메일을 설정, 실제 네이버에 가입된 이메일로 작성해야함
- password: 보내는 사람의 비밀번호 설정, 실제 네이버에 가입된 비밀번호로 작성
let transporter = nodemailer.createTransport({ // 보내는사람 메일 설정입니다.
service: 'Naver', // 보낼 메일서비스명
auth: {
user: process.env.NODEMAILER_USER, // 사용자의 아이디
pass: process.env.NODEMAILER_PASS, // 사용자의 패스워드
}
});
받는 사람의 메일 설정
- from: 보내는 사람의 이메일 주소 설정, 환경변수로 설정함
- to: 받는 사람의 이메일 주소 설정, body로 받아온 nickname인자에 할당된 이메일로 인증 메일 발송
- subject: "메일의 제목부분을 작성"
- html: 메일 발송시 ejs파일에 작성된 html전송
let mailOptions = { // 받는사람 메일 설정입니다.
from: process.env.NODEMAILER_USER, // 발송 메일 주소
to: nickname, // 받는사람 이메일
subject: '회원가입을 위한 인증번호를 입력해주세요.',
html: emailTemplete,
}
sendMail 메소드로 메일 전송
- sendMail메소드의 첫번째 인자로 전송할 메일의 설정을 전달 여기서는 변수 mailOpions에 할당, 두번째 인자로 전송완료시메세지 출력
transporter.sendMail(mailOptions, (error, info) => { // 이메일 발송
res.status(200).json({ "message": `${nickname}이메일 발송 성공` }).console.log('이메일 발송에 성공했습니다: ' + info.response); // 성공
})
발생한 오류
- 네이버에 가입되지 않은 이메일을 발신자로 설정하였을때 메일 발송 불가
- router를 분리하지 않고 signup 라우터에 발송부터, 회원가입까지 입력했을때 회원가입이 불가능 => signup라우터와 authMail 라우터를 분리하여 authMail 라우터에 post요청 후 발송된 인증코드를 signup라우터에서 처리 할수 있도록 분리
authMail 라우터
6자리 랜덤 인증코드 생성
- authMail로 post 요청시 인증 코드 생성
let authNum = Math.random().toString().substr(2, 6);
생성된 인증코드
- 535303
router.post('/authMail', async (req, res) => {
const { nickname } = req.body
try {
let emailTemplete;
ejs.renderFile(appDir + '/template/authMail.ejs', { authCode: authNum }, function (err, data) {
if (err) { console.log(err) }
emailTemplete = data;
});
let transporter = nodemailer.createTransport({ // 보내는사람 메일 설정입니다.
service: 'Naver', // 보낼 메일서비스명
port: 587,
secure: false,
auth: {
user: process.env.NODEMAILER_USER, // 사용자의 아이디
pass: process.env.NODEMAILER_PASS, // 사용자의 패스워드
}
});
let mailOptions = {
from: process.env.NODEMAILER_USER,
to: nickname,
subject: '회원가입을 위한 인증번호를 입력해주세요.',
html: emailTemplete,
}
transporter.sendMail(mailOptions, (error, info) => { // 이메일 발송
res.status(200).json({ "message": `${nickname}이메일 발송 성공` }).console.log('이메일 발송에 성공했습니다: ' + info.response); // 성공
transporter.close()
})
} catch (error) {
console.error(`${req.method} ${req.originalUrl} : ${error.message}`);
}
})
전송된 이메일
signup 라우터
- authMail 라우터에서 인증코드를 발급 받은 후, 사용자에게 입력받은 인증번호를 authcode에 할당하고 생성된 인증코드와 비교하여 true일때 에러처리 실행
// 회원 가입 API
router.post('/signup', async (req, res) => {
const { nickname, password, confirm, authcode } = req.body
console.log(nickname, password, confirm, authcode)
console.log(authcode, authNum)
try {
if (authcode === authNum) {
const isExistuser = await UserSchema.findOne({ nickname });
if (isExistuser) {
res.status(412).json({
errorMessage: "중복된 닉네임입니다."
})
return
};
// 닉네임 최소 3글자 이상, 알파벳 대소문자, 숫자 외 에러메세지
if ((!/^[a-zA-Z0-9@]+$/.test(nickname)) || (nickname.length < 4)) {
res.status(412).json({
errorMessage: "닉네임의 형식이 일치하지 않습니다."
})
return
};
// 패스워드, 확인패스워드 일치 검증
if (password !== confirm) {
res.status(412).json({
errorMessage: "패스워드가 일치하지 않습니다."
})
return // 패스워드 검증이 실패하면 뒤에는 실행시키지 않도록 return으로 브레이크
};
// 패스워드 닉네임을 포함시키면 에러메세지
if (password.includes(nickname)) {
res.status(412).json({
errorMessage: "패스워드에 닉네임이 포함되어 있습니다."
})
return
};
// 패스워드 4글자 이하이면 에러메세지
if (password.length <= 4) {
res.status(412).json({
errorMessage: "패스워드 형식이 일치하지 않습니다."
})
return
}
}
console.log(authcode, authNum)
if (authcode !== authNum) {
res.status(412).json({
errorMessage: "인증코드가 일치하지 않습니다"
})
return
};
// 닉네임 DB 중복 검증
const user = new UserSchema({ nickname, password });
await user.save();
return res.status(201).json({ message: "회원 가입에 성공하였습니다." });
} catch (error) {
console.error(`${req.method} ${req.originalUrl} : ${error.message}`);
res.status(400).json({ "message": "이메일 발송 실패" })
}
});
수정할 수 있는 부분
- authMail 라우터에서 transporter 변수를 모듈파일로 따로 빼고 require로 불러오기
- 이메일 유효성검사 정규표현식 수정 => @가 포함되게
- 입력된 authcode와 생성된 authNum이 같을떄 작성한 조건문 삼항 연산자로 수정하기
- 에러처리 부분 수정하기