ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] SpringBoot 프로젝트 : 회원가입 기능 구현 - 이메일 본인인증 이메일 전송(Naver메일 설정, JavaMailSender, MIME, SMTP)
    프로젝트/기능 정리 2023. 7. 8. 23:49

    목적

    • 게시판 형식 웹사이트 개발 시 회원가입 기능 구현 정리
    • 아이디 중복확인, 비밀번호 확인, 이메일 인증번호 등 세부 기능 정리

     

    이번 글에서는 이메일을 전달 받은 서버에서 인증번호를 생성하고 메일을 보내는 과정을 알아보자.

     

    [데이터 흐름도]

    데이터 흐름도는 다음과 같다.

     

    회원가입 데이터 흐름도

     

    [이메일 설정]

    먼저 SpringBoot를 기반으로 하고 있기에 dependency 추가와 설정을 해줘야 한다.

     

    먼저 pom.xml에 dependency를 먼저 추가해보자.

     

    이메일 의존성 추가

     

    다음은 application.yml에 설정을 해줘야 한다. 여기서는 네이버 메일을 사용했으므로 아래와 같다.

     

    yml 설정

     

    username에는 발신 메일 주소(ex. test@naver.com)이 들어가고 password에는 해당 계정의 비밀번호가 들어가면 된다.

     

    노출되면 안되므로 환경변수 설정을 통해 넣어줬다.

     

    메일을 보내는 계정도 설정을 해줘야하는데 간단하다. 메일에 들어가서 환경설정에 들어가면 아래와 같은 화면이 나온다.

     

    네이버 메일 환경설정

     

    POP3/IMAP 설정을 눌러주자.

     

    IMAP/SMTP 설정

     

    기본적으로 IMAP/SMTP 사용 안 함으로 되어 있을텐데, 메일을 보내려면 사용함으로 바꿔야 한다.

     

    계정 정보

     

    위 정보를 기반으로 yml 설정을 해둔 것이니 참고하면 된다.

     

     

    이제 메일 전송과정을 보자.

     

    이전 글에서 Ajax 전송 코드는 아래와 같았다.

                const email = $('#mem_email').val();
                const checkInput = $('.mail-check-input');
    
                $.ajax({
                    type : 'get',
                    url : '../mailCheck?email='+email,
                    success : function (data) {
                        checkInput.attr('disabled',false);
                        code = data;
                        alert('인증번호가 전송되었습니다.');
                    }			
                });
            }
        });

    회원이 입력한 이메일 주소를 GET방식으로 전달하는데, /mailCheck라는 주소에 요청을 보내고 있다.

     

    해당 매핑이 된 컨트롤러를 보자.

     

    [MailController]

    메일 처리를 하는 컨트롤러를 따로 만들어서 사용했다.

    @Controller
    public class MailController {
    
        @Autowired
        private MailService mailService;
    
        @Autowired
        private MailVO mailVO;
    
        @GetMapping("/mailCheck")
        @ResponseBody
        public String mailCheck(String email) throws Exception{
            String key = createKey();
    
            mailVO.setAddress(email);
            mailVO.setTitle("4or Dog 인증번호 안내");
            mailVO.setMessage("인증번호는 " + key + "입니다.");
    
            mailService.mailSend(mailVO);
    
            return key;
        }
        //이하 코드 생략

    컨트롤러에서의 작업만으로도 전송이 가능하지만, MailService를 따로 만들어 이메일 전송 과정을 처리한 듯 하다.

     

    내용은 간단하다. 순서대로 보면,

     

    1. key라는 변수에 createKey메소드를 통해 생성한 인증번호를 담아준다.
    2. mailVO에 파라미터로 전달받은 이메일 주소, 이메일 제목, 이메일 내용을 담아준다.
    3. 주입 받은 mailService에 mailVO를 전달한다.
    4. 생성한 인증번호인 key를 Ajax의 결과로 리턴한다.

    의 과정이 되겠다.

     

    mailVO는 아래와 같다.

    @Component
    public class MailVO {
        private String address;
        private String title;
        private String message;
    
        public String getAddress() {
            return address;
        }
        public void setAddress(String address) {
            this.address = address;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
        public String getMessage() {
            return message;
        }
        public void setMessage(String message) {
            this.message = message;
        }
    }

    간단하게 모두 String타입으로 이메일 주소, 제목, 내용을 담기 위해 만들었다.

     

    다음은 key를 생성하는 메소드인 createKey를 보자.

        public String createKey() {
            StringBuffer key = new StringBuffer();
            Random rand = new Random();
    
            for(int i = 0; i < 6; i++) {
                key.append((rand.nextInt(10)));
            }
    
            return key.toString();
        }
    }

    버퍼를 생성한 뒤 랜덤하게 0~9까지 숫자를 뽑아서 버퍼에 하나씩 담아 6자리의 인증번호를 만든 과정이다.

     

    [mailService]

    이제 서비스쪽 코드를 보자.

    @Component
    public class MailService {
    
        @Autowired
        private JavaMailSender mailSender;
    
        private static final String FROM_ADDRESS = "4ordog@naver.com";
    
        public void mailSend(MailVO mail) throws Exception{
            MimeMessage message = mailSender.createMimeMessage();
            try {
                message.setFrom(MailService.FROM_ADDRESS);
                message.setSubject(mail.getTitle());
                message.setText(mail.getMessage());
                message.setRecipients(MimeMessage.RecipientType.TO , InternetAddress.parse(mail.getAddress()));
            }catch(MessagingException e) {
                System.out.println("MessagingException");
            }
    
            try {
                mailSender.send(message);
            }catch(MailException e) {
                System.out.println("MailException");
                e.printStackTrace();
            }
        }
    }

    우선 메일을 보내기 위해 JavaMailSender 인터페이스를 사용했다.

     

    설명을 보면 아래와 같다(자세한 내용은 여기서).

     

    JavaMailSender 설명 일부

     

    JavaMail을 위한 확장 MailSender 인터페이스라는데, 보통 JavaMail MimeMessage를 편하게 생성하기 위해 MimeMessageHelper 클래스랑 같이 사용된다고 한다.

     

    뭔말인지 잘 모르겠지만 아무튼 Java에서 MIME 형태 메시지를 생성하고 전송하는데 도움을 주는 인터페이스라고 생각하면 될 것 같다.

     

    [MIME]

     

    여기서 MIME은 Multipurpose Internet Mail Extensions의 약자로, 전자 우편을 위한 인터넷 표준 포맷이다(출처 : 위키백과).

     

    설명을 보니 전자 우편은 7비트 ASCII문자를 사용해서 전송되는데, 8비트 이상의 코드를 사용하는 문자나 이진 파일들은 MIME 포맷으로 변환되어 SMTP로 전송된다고 한다.

     

    좀 더 설명하면  문자 인코딩(설명은 여기서..)을 이용해서 ASCII에 없는, 즉 영어가 아닌 다른 언어 등도 전자 우편을 통해 보낼 수 있도록 해주는게 MIME이라고 보면 되겠다.

     

    [SMTP]

     

    SMTP는 Simple Mail Transfer Protocol의 약자로, 인터넷에서 이메일을 보내기 위해 이용되는 프로토콜이라고 한다(출처 : 위키백과).

     

    이 SMTP을 이용하기 위해서는 모든 문자가 7비트의 ASCII코드로 되어있어야 한다고 한다.

     

    만약 8비트 이상의 코드를 사용하는 언어나 기타 이진 데이터는 MIME 포맷으로(7비트) 변환되어 전달된다고 한다.

     

     

    정리하면 인터넷에서 이메일을 보내기 위해 SMTP를 이용하는데, 이때 데이터가 7비트의 ASCII 문자가 아니어도 전송할수 있도록 포맷을 정의한 것이 MIME이라고 할 수 있겠다.

     

    사실 이메일 전송 기능만을 생각한다면 굳이 이런 개념을 알 필요는 없을 수 있겠으나 겉핥기 식으로라도 알아두면 쓸모가 있을지 모르니.. 짧게라도 정리해봤다.

     

     

    우선 전송하는 이메일 주소는 고정이므로 아래와 같이 final로 선언해줬다.

    private static final String FROM_ADDRESS = "4ordog@naver.com";

    다음으로는 이메일 주소, 전달할 메시지, 제목 등을 담아줄 MimeMessage 객체를 하나 만들었다.

    MimeMessage message = mailSender.createMimeMessage();

    message에 전달하는 송신 메일 주소, 제목, 내용, 수신인 순으로 아래와 같이 담아줬다.

    message.setFrom(MailService.FROM_ADDRESS);
    message.setSubject(mail.getTitle());
    message.setText(mail.getMessage());
    message.setRecipients(MimeMessage.RecipientType.TO , InternetAddress.parse(mail.getAddress()));

    송신 메일 주소는 final로 선언해둔 값을 넣어줬고, 제목, 내용은 전달 받은 mailVO의 값을 꺼내서 넣었다.

     

    마지막 수신 정보는 setRecipients라는 메소드에 인자 두 개를 전달해서 세팅하고 있는데, 첫 번째는 이메일 전송 시 수신과 참조를 설정하는 부분이다.

     

    세 가지가 있는데 아래와 같다.

     

    • TO: 수신인, 즉 받는 사람을 넣는 부분
    • CC(Carbon Copy): 참조, 즉 직접 메일을 받는 사람은 아니지만 메일 내용을 참고해야할 사람을 넣는 부분
    • BCC(Blind Carbon Copy): 숨은참조, CC와 유사하지만 수신인이 누구인지 숨기고 싶을 때 해당 사람들 넣는 부분

     

    잘 몰랐는데 찾아보니 이런 개념인 것 같다(참고).

     

    정리하면 메일을 보낼 때 위 세 가지 요소에 받는 사람들의 메일 주소를 넣을 수 있는데,

     

    네이버 메일 쓰기

     

    TO는 수신인 자체를, CC는 메일 내용과 상관은 없을 수 있지만 메일 내용을 알아두면 좋을(?)사람을 넣는 것 같다.

     

    이렇게 메일을 수신한 사람은 메일을 누가 수신했는지, 참조된 사람은 누군지 알 수 있게되는데, 누가 수신했는지 감추기 위해 BCC를 사용하는 것 같다.

     

    두 번째는 이메일 수신인의 메일 주소를 넣어주면 된다.

     

    배열을 이용해서 여러 사람에게도 보낼 수 있다.

    InternetAddress.parse(mail.getAddress())

    여기서는 인증번호 요청을 보낸 이메일 하나에 대해서만 진행하므로 위와 같다.

     

    미리 InternetAddress 클래스를 이용해 전달 받은 문자열을 파싱하고 있는데, 이 클래스에 대한 설명은 아래와 같다.

     

    InternetAddress 클래스 설명

     

    RFC822 문법을 사용하는 인터넷 이메일 주소를 표현하는 클래스라는데, 정확히 뭘 하는 건지는 잘 모르겠다..

     

    setRecipients의 두 번째 인자로 넣을 때 파싱을 해서 넣어야되는 것인줄 알았는데 아래와 같이 그냥 문자열 자체를 넣어도 된다.

    message.setRecipients(MimeMessage.RecipientType.TO , mail.getAddress());

    그 이유는 setRecipients 내부 코드를 보면 알 수 있는데 아래와 같이 값이 있으면 알아서 파싱해준다.

     

    setRecipients 코드

     

    이렇게 해서 message에 필요한 값들을 세팅했고 마지막으로 mailSender.send를 통해 message를 전송하면 끝이다.

    try {
        mailSender.send(message);
    }catch(MailException e) {
        System.out.println("MailException");
        e.printStackTrace();
    }

     

     

    오류 없이 위 과정이 진행된다면 메일이 전송되고, 그 결과는 다음과 같다.

     

    이메일 전송 결과

     

    이렇게 서버측에 전달된 메일 주소로 이메일을 전송하는 방법을 정리했다.

     

    다음 글에서는 마지막으로 인증번호를 확인하는 절차만 간단하게 보고 이메일 전송 과정을 마무리하도록 하겠다.

Designed by Tistory.