지난 프로젝트에서는,
nodemailer 인증코드 전송 후 홈페이지에서 확인 방식이였는데
이번 프로젝트는,
메일로 회원가입 인증메일 전송 ->
메일에 걸려있는 링크 클릭 시 다시 홈페이지로 이동 후 회원가입인증이 완료
되는 방식으로 진행하기로 하였다.
프로젝트에서 front
를 담당하였으나,
이전 프로젝트에서 회원가입기능을 구현 한적이 없었고
nodemailer를 사용해보고자 메일인증 기능은 back과 front를 전부 담당하여서 진행하게 되었다.
노드메일러 사용 시 그 외 필요한 내용
(1) 노드메일러 발송 시 전달 될 HTML 템플릿이 필요하였다
찾아보니 템플릿을 만들어주는 사이트가 있어 사이트에서 템플릿을 만든 뒤
코드만 받아와서 적용 시킬 수 있었다.(사이트는 아래 링크에)
//App.js
<Route path='/verify-email/:token' component={VerifyEmail} />
//VerifyEmail.js
function VerifyEmail({ match }) {
const { token } = match.params
const signUpUpdate = async () => {
await axios.patch(`${process.env.REACT_APP_SERVER_API}/user/email-verification`, { token })
.then((res) => {
console.log(res, 'client/verifyEmail')
if (!res.data.data) {
setCompleted(false)
}
})
.catch((err) => {
console.log(err)
})
}
useEffect(() => {
signUpUpdate()
}, [])
useEffect로 페이지가 마운트 됐을 때
props 로 받아온 {match} 값 안에 포함되어있는 params로 token 값을 추출한 뒤에
인증확인 컬럼의 값을 0에서 1로 업데이트 시켜주는 aixos 요청을 보낸다
(1) 템플릿에 주소로 이미지 적용하기
<img src="https://i.imgur.com/0royLEy.jpg" />
HTML 템플릿을 만든 다음에 적용한 뒤 메일을 발송했는데 이미지가 적용이 안되는 에러가 발생하였다
기존 태그는'./img/~'
와 같이 상대경로로 지정해주는 코드로 작성이 되어있었는데
적용이 되지 않아 여러가지 방법으로 시도를 하였지만(..) 되지않았다
절대경로로 이미지를 전달해주고자
이미지업로드사이트에 사진을 업로드 한 뒤 절대경로 로 이미지를 띄워주었다
(2) client 접속 시 경로 연결해주기
<a href="http://localhost:3000/verify-email/${token}"></a>`
client에 아래와 같이 분기를 나누어주었고 링크로 접속하게 되면
<Route path='/verify-email/:token' component={VerifyEmail} />
params로 생성한 Token을 전달 해 주었다
(3) nodemailer 메일 발송 시 스팸메일함으로 수신되는 부분 해결
let transporter = nodemailer.createTransport({ ..., auth: { ... }, from: `메일 발신자 주소` // 추가 });
메일 발송이 완료가 되면 스팸메일함으로 메일이 전달 되었는데
메일 발신자 이메일 주소를 from 값으로 추가해주면
스팸메일함으로 전달 되지 않는다
const jwt = require("jsonwebtoken");
const { User } = require("../../models");
const nodemailer = require('nodemailer');
module.exports = async (req, res) => {
try {
const { email } = req.body;
const userEmail = await User.findOne({ where: { email }, attributes: ["email"] });
if (userEmail) {
const email2 = userEmail.dataValues
const token = jwt.sign(email2, process.env.ACCESS_SECRET, { expiresIn: "1h" })
//email로 찾은 유저 정보로 token 생성
let transporter = nodemailer.createTransport({
//smtp객체 생성하는 명령어
service: 'gmail',
host: 'smtp.gmail.com',
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: process.env.ACCOUNT_USER,
pass: process.env.ACCOUNT_PASS,
},
from: process.env.ACCOUNT_USER // 스팸메일로 안가도록 설정
//환경변수로 비밀번호와 메일주소 설정
});
transporter.verify(function (error, success) {
if (error) console.log(error);
else {
console.log('Server is ready to take our messages');
}
});
const message = {
from: process.env.ACCOUNT_USER, // sender address
to: `${email}`, // list of receivers
subject: 'Shall We Helath 회원가입 인증메일 입니다🏋🏻♀️', // Subject line
text: 'Shall We Helath 회원가입 인증메일 입니다', // plain text body
html: // 템플릿 HTML 코드
` ...,
<img src="https://i.imgur.com/0royLEy.jpg" />
<a href="http://localhost:3000/verify-email/${token}"></a>
...
`
let send = await transporter.sendMail(message);
//메일 발송하기
return res.status(200).json({ data: token, message: '메시지가 전송되었습니다' })
} else {
return res.status(400).json({
data: null,
error: {
"path": "/users/email-verification",
"message:": "Insufficient body data",
}
})
}
}
catch (err) {
console.log(err);
}
};
const jwt = require("jsonwebtoken");
const { User, sequelize } = require("../../models");
const { QueryTypes } = require("sequelize");
module.exports = async (req, res) => {
try {
const { token } = req.body
const verified = jwt.verify(token, process.env.ACCESS_SECRET, (err, decoded) => {
if (err) return null;
return decoded;
});
//토큰해독
//1. 토큰을 해독했는데 유효하지 않았을 때
//2. 유효한데 db에 저장된 이메일이 없을때
if (!verified) {
/* 토큰 해독이 안될 떄*/
return res.status(404).json({
data: null,
error: {
path: "/user/email-verification",
message: "token fail verfied",
},
});
} else {
//해독된거로 DB찾기
const { email } = verified
const userEmail = await User.findOne({ where: { email }, attributes: ["email"] });
if (!userEmail) {
/* DB에 유저 정보가 없을 때*/
return res.status(404).json({
data: null,
error: {
path: "/user/email-verification",
message: "token not found userInfo",
},
});
} else {
const sql = `update users set isEmailVerified = 1 where email = "${email}";`
const rows = await sequelize.query(sql, { type: QueryTypes.UPDATE });
//시퀄라이즈에서 mysql 문법 사용 (UPDATE)
//제대로 되었을 시에 데이터 담김
if (rows) {
return res.status(200).json({ data: true });
} else {
return res.status(404).json({
data: null,
error: {
path: "/user/email-verification",
message: "page not found",
},
})
}
}
}
} catch (err) {
console.log(err)
throw err;
}
};