
저번 포스팅에서 간단하게 이메일 동작원리에 대해서 알아보았습니다. 저는 프로젝트를 하면서 이메일인증을 구현할 때, 기본적인 동작원리와 용어들을 모르고 개발하는 것과 어느정도 이해하고 개발하는 것은 매우 다르다고 생각했습니다.
이제 본격적으로 이메일 구현을 할 것입니다. 그 이전에 이메일인증을 구현하기 위해서는 메일 설정을 해야합니다. 저는 네이버 메일을 이용하여 메일 설정을 하도록 하겠습니다.
저는 회원가입 전에 이메일 인증을 하고 인증이 완료된 사용자만 회원가입을 이어서 진행할 수 있도록 구현할 것입니다.
이메일 설정이나 환경설정을 제외한 코드 작성은 각자 스타일이 있기 때문에 참고만 부탁드립니다.
저는 2가지의 API로 이메일 인증을 구현할 것입니다.
1. 이메일 보내기(랜덤 숫자 발송)
2. 랜덤 숫자 인증 -> 인증완료가 된다면 이어서 회원가입 진행



저는 프로젝트를 Maven으로 진행하였습니다.
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.6.2</version>
</dependency>
다음 정보들을 입력합니다.
mail.host=
mail.port=
mail.username=
mail.password=
mail.auth=
mail.starttls.enable=
mail.timeout=
@Configuration
public class EmailConfig {
@Value("${mail.host}")
private String host;
@Value("${mail.port}")
private int port;
@Value("${mail.username}")
private String username;
@Value("${mail.password}")
private String password;
@Value("${mail.auth}")
private boolean auth;
@Value("${mail.starttls.enable}")
private boolean starttlsEnable;
@Value("${mail.timeout}")
private int timeout;
@Bean
public JavaMailSender javaMailSender(){
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(host);
mailSender.setPort(port);
mailSender.setUsername(username);
mailSender.setPassword(password);
mailSender.setDefaultEncoding("UTF-8");
mailSender.setJavaMailProperties(getMailProperties());
return mailSender;
}
private Properties getMailProperties(){
Properties properties = new Properties();
//"mail.smtp.auth": 이메일 서버가 사용자 인증을 필요로 하는지 여부를 설정 변수 auth의 값에 따라 true 또는 false가 될 수 있음.
properties.put("mail.smtp.auth", auth);
properties.put("mail.host",host);
properties.put("mail.username",username);
properties.put("mail.password",password);
//"mail.smtp.starttls.enable": SMTP 서버가 STARTTLS 명령을 사용하여 보안 연결을 시작할 수 있는지 여부를 설정.. 변수 starttlsEnable에 의해 결정.
properties.put("mail.enable", starttlsEnable);
//"mail.smtp.timeout": 메일 서버로부터 응답을 기다리는 타임아웃 시간(밀리초 단위)을 설정. 변수 timeout에 지정된 값으로 설정.
properties.put("mail.timeout", timeout);
return properties;
}
}
저는 이메일 인증은 회원가입의 과정이기 때문에 SignController안에서 컨트롤러를 만들었습니다.
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/sign")
public class SignController {
private final SignService signService;
@PostMapping("/send-mail")
public ResponseEntity<Map<String, String>> sendSimpleMessage(@RequestParam String email, HttpServletRequest request) throws Exception {
return ResponseEntity.status(HttpStatus.OK).body(signService.sendSimpleMessage(email,request));
}
@PostMapping("/verified")
public ResponseEntity<?> verifyEmail(String confirmationCode, HttpServletRequest request){
Map<String,String> verified = signService.verifyEmail(@RequestParam confirmationCode,request);
return ResponseEntity.status(HttpStatus.OK).body(verified);
}
// 나머지 회원가입/로그인 컨트롤러 생략
}
로직은 간단합니다.
1. 이메일로 인증번호 발송
2. 인증번호 검증 -> 검증되면 유저의 Verified가 true로 바뀜.
3. 이어서 회원가입 진행.
-SignService-
public interface SignService {
Map<String,String> sendSimpleMessage(String to, HttpServletRequest request) throws Exception;
Map<String,String> verifyEmail(String confirmationCode, HttpServletRequest request);
// 회원가입/로그인 부분은 생략
}
-SignServiceImpl-
@Service
@Slf4j
@RequiredArgsConstructor
public class SignServiceImpl implements SignService {
private final JavaMailSender javaMailSender;
private Logger logger = LoggerFactory.getLogger(SignServiceImpl.class);
private final JwtProvider jwtProvider;
private final SignDao signDao;
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final ResultStatusService resultStatusService;
// 이메일 보내기
@Override
public Map<String, String> sendSimpleMessage(String email, HttpServletRequest request) throws Exception {
String ePw = createKey();
request.getSession().setAttribute("email",email);
MimeMessage message = createMessage(email,ePw);
try{
javaMailSender.send(message);
}catch (MailException e){
e.printStackTrace();
throw new IllegalArgumentException();
}
Map<String,String>response = new HashMap<>();
response.put("Confirmation : ", ePw);
return response;
}
// 인증번호 검증
@Override
public Map<String,String> verifyEmail(String confirmationCode, HttpServletRequest request) {
String email = (String) request.getSession().getAttribute("email");
User user = new User();
Map<String,String> response = new HashMap<>();
if(email != null){
user.setEmail(email);
user.setVerified(true);
request.getSession().setAttribute("user",user);
response.put("Verified : ", "true");
return response;
}
response.put("Verified : ", "false");
return response;
}
// 이메일 메시지 폼 제작
private MimeMessage createMessage(String to, String ePw) throws Exception {
MimeMessage message = javaMailSender.createMimeMessage();
message.addRecipients(Message.RecipientType.TO, to);
message.setSubject("이메일 인증");
String msgg = "";
msgg += "<div style='margin:20px;'>";
msgg += "<h1> OVER-DOSE </h1>";
msgg += "<br>";
msgg += "<p>인증번호 입니다.</p>";
msgg += "<br>";
msgg += "<br>";
msgg += "<div align='center' style='border:1px solid black; font-family:verdana';>";
msgg += "<h3 style='color:blue;'>회원가입 인증 코드입니다.</h3>";
msgg += "<div style='font-size:130%'>";
msgg += "CODE : <strong>";
msgg += ePw + "</strong><div><br/> ";
msgg += "</div>";
message.setText(msgg, "utf-8", "html");//내용
message.setFrom(new InternetAddress("nankys0510@naver.com", "OverDose"));//보내는 사람
return message;
}
//인증번호 제작
public static String createKey(){
int number = (int)(Math.random()*90000)+100000;
return String.valueOf(number);
}
// 회원가입/로그인 부분은 생략
}
중심이 되는 메서드 두 개만 알아보겠습니다.
저는 다음과 같은 로직으로 개발하였습니다.
이메일 입력

이메일확인 - 인증번호 전송 및 확인

3.인증번호 검증

이렇게 true가 나온것을 볼 수 있습니다.
저는 프론트에 넘겨주기 위하여 Map<String,String>을 사용하였습니다.
이렇게 회원가입을 위한 이메일 인증을 구현해보았습니다. 개발하는 사람마다 로직이 다를수도 있고, 코딩 스타일도 다를 수 있지만 전체적인 흐름은 비슷하다고 생각하기 때문에 다양한 방법으로도 구현해 볼 예정입니다.