🤔 준비물
Google 계정
Gmail SMTP 설정
💻 버전 관리
2023 . 11. 27 일 기준
Spring Boot 2.5.6 V
JDK 11
Maven
실제로 실무에서는 다른 메일 서버를 사용하겠지만(Gmail은 일일 2000개로 한정이기 때문), 학부생 입장에서 ToyProject 진행 시 인증번호 인증 후 회원가입에 필요한 Gmail SMTP 설정에 대한 내용이에요.
SMTP(Simple Mail Transfer Protocal)은 인터넷을 통해 이메일을 보내고 받는데 사용되는 통신 프로토콜이에요.
25/TCP 또는 587/TCP를 사용합니다.
SMTPS는 SMTP에 SSL(보안 소켓 계층) 또는 TLS(전송 계층 보안)와 같은 암호화 프로토콜을 사용해서 메일내용을 암호화 하여 전송하는 거에요.
465/TCP를 사용합니다!
이러한 이유로 SMTP보다는 SMTPS 프로토콜을 사용하는 것이 기밀성과 무결성을 보장하고 일반적으로 사용해요 😃
1) 클라이언트에서 SpringBoot 서버로 POST 메서드로 본인 email을 전송
2) SpringBoot 서버에서 송신 이메일 : {}, 수신 이메일 : {}, 내용 Body 값 : {}, 인증번호(6자리 난수) : {} 를 세팅
3) 2)에서 세팅한 내용을 갖고 Gmail SMTP 465/TCP를 이용하여 수신 이메일로 메일 내용 전송
4) if 다시 클라이언트에서 입력한 인증번호 내용이 서버에서 가지고 있는 인증번호와 일치하면? 회원가입 성공
else 회원가입 실패
Gmail SMTP를 사용하려면 Google 계정이 필요해요!
또한, 일반적인 경우 인증번호는 사용자가 송신자에게 추가적인 메일을 보낼 일이 없겠죠?
이러한 이유로 no-reply 또는 noreply @ domain 으로 계정을 생성하는게 일반적입니다!
이런식으로 말이죠.🤓
만약 새로 구글 계정을 생성해야 한다면?
Google 계정 새로 생성! 이 내용을 참고하세요.
구글 계정을 선택했다면 SMTP 설정을 할 수 있어요!
Gmail 페이지로 이동 후 오른쪽 상단 톱니바퀴 클릭
모든 설정 보기 클릭
[전달 및 POP/IMAP]탭 -> IMAP 액세스 사용 체크 -> 저장
POP vs IMAP
POP -> 메일 서버에서 메일을 받아오는 프로토콜 중 하나로, 메일이 PC 로컬 저장소에 저장됩니다. 즉, 로컬 PC 저장소에 저장된 후에 메일 서버에선 사라집니다.(메일 서버의 용량이 적을 때)
IMAP -> 동일하게 메일을 받아오는 프로토콜이지만, 메일 서버와 동기화가 이뤄지기 때문에 모든 장치에서 동일한 이메일을 확인 할 수 있습니다.(메일 서버의 용량이 많을 때)
Google 계정 보안 설정 페이지로 이동
왼쪽 보안 탭 -> 2단계 인증을 해줍니다. (저는 이거 쓰느라고 중지 한거에요 🥲)
각 단계를 거치면?
다시 인증 페이지로 들어가준다.
앱 비밀번호 발급
사용 용도에 적당한 이름으로 작성 후 만들기
앱 비밀번호가 생성됐습니다! (비밀번호는 다시 볼 수 없으니 메모장에 적어두어야 합니다‼️)
저는 Spring-Boot-Starter-Mail을 사용하였습니다.
maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
gradle
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-mail'
# SMTP port setting(필수)
spring.mail.host=smtp.gmail.com
spring.mail.port=465
spring.mail.username= 송신자 이메일
spring.mail.password= 앱 비밀번호
spring.mail.properties.mail.smtp.auth=true
spring.mail.protocol=smtps
# SMTP sending time setting(timeou과 관련된 세팅으로 필수적이지 않음)
spring.mail.properties.mail.smtp.timeout=20000
spring.mail.properties.mail.smtp.connectiontimeout=20000
spring.mail.properties.mail.smtp.writetimeout=20000
밑에 timeout 관련 세팅은 메일 내용과 서버의 속도에 따라 입맛에 맞추어 사용하시면 좋아요!😃
저 같은 경우는 mail의 body 값이 생각보다 무거워서 TimeException이 발생해서 2초로 여유 간격을 주었습니다 :)
private static String number;
public static void createNumber(){
Random random = new Random();
StringBuffer key = new StringBuffer();
for(int i=0; i<8; i++) { // 총 8자리 인증 번호 생성
int idx = random.nextInt(3); // 0~2 사이의 값을 랜덤하게 받아와 idx에 집어넣습니다
// 0,1,2 값을 switchcase를 통해 꼬아버립니다.
// 숫자와 ASCII 코드를 이용합니다.
switch (idx) {
case 0 :
// 0일 때, a~z 까지 랜덤 생성 후 key에 추가
key.append((char) (random.nextInt(26) + 97));
break;
case 1:
// 1일 때, A~Z 까지 랜덤 생성 후 key에 추가
key.append((char) (random.nextInt(26) + 65));
break;
case 2:
// 2일 때, 0~9 까지 랜덤 생성 후 key에 추가
key.append(random.nextInt(9));
break;
}
}
number = key.toString();
}
- MailSender : 이메일을 보내는데 사용되는 클래스들의 최상위 클래스
- JavaMailSender : MailSender의 하위 인터페이스이고, MIME 메세지(우리가 생각하는 메일 내용)를 생성하고 보낼 수 있습니다.
- MimeMessageHelper : MIME 메세지를 생성을 위해 사용되는 클래스인데, Helper를 사용하면, 이미지파일, 텍스트, 파일 등 html 형식으로 작성할 수 있습니다.
public MimeMessage createMessage(String email){
createNumber();
log.info("Number : {}",number);
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
try{
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true); // Helper 사용
messageHelper.setFrom(senderEmail);
messageHelper.setTo(email);
messageHelper.setSubject("[Challengers] 이메일 인증 번호 발송");
String body = "<html><body style='background-color: #000000 !important; margin: 0 auto; max-width: 600px; word-break: break-all; padding-top: 50px; color: #ffffff;'>";
body += "<img class='logo' src='cid:image'>";
body += "<h1 style='padding-top: 50px; font-size: 30px;'>이메일 주소 인증</h1>";
body += "<p style='padding-top: 20px; font-size: 18px; opacity: 0.6; line-height: 30px; font-weight: 400;'>안녕하세요? Challengers 관리자 입니다.<br />";
body += "Challengers 서비스 사용을 위해 회원가입시 고객님께서 입력하신 이메일 주소의 인증이 필요합니다.<br />";
body += "하단의 인증 번호로 이메일 인증을 완료하시면, 정상적으로 Challengers 서비스를 이용하실 수 있습니다.<br />";
body += "항상 최선의 노력을 다하는 Challengers가 되겠습니다.<br />";
body += "감사합니다.</p>";
body += "<div class='code-box' style='margin-top: 50px; padding-top: 20px; color: #000000; padding-bottom: 20px; font-size: 25px; text-align: center; background-color: #f4f4f4; border-radius: 10px;'>" + number + "</div>";
body += "</body></html>";
messageHelper.setText(body, true);
ClassPathResource image = new ClassPathResource("img/challengers.png");
messageHelper.addInline("image", image);
}catch (MessagingException e){
e.printStackTrace();
}
return mimeMessage;
}
public String sendMail(String email) {
MimeMessage mimeMessage = createMessage(email);
log.info("[Mail 전송 시작]");
javaMailSender.send(mimeMessage);
log.info("[Mail 전송 완료]");
return number;
}
@PostMapping(value = "/request-sign-up")
public ResponseEntity<?> requestSignUp(@RequestBody SignUpRequestDto signUpRequestDto){
return ResponseEntity.ok(signService.sendCode(signUpRequestDto));
}
성공!✌️