본문 바로가기

개발 이야기/java

[Java][Spring]SMTP를 이용한 이메일 인증 기능

개인적으로 만들고 있는 프로젝트의 회원가입 페이지에 이메일 인증이 필요하여 SMTP를 이용하여 이메일로 인증번호를 보내고 보낸 인증번호를 확인하는 이메일 인증 기능을 만들어보았다. 

SMTP

 - 간이 전자 우편 전송 프로토콜(Simple Mail Transfer Protocol)

 

필요 라이브러리

먼저 필자는 gradle을 사용하기에 gradle에 필요한 라이브러리를 넣어준다.

필요한 라이브러리는 spring-context-support와 javax.mail 두 가지이다.

※ spring-context-support는 프로젝트에 쓰고 있는 스프링과 같은 버전을 사용하여야 한다.

compile group: 'javax.mail', name: 'mail', version: '1.4'
compile group: 'org.springframework', name: 'spring-context-support', version: '4.2.5.RELEASE'

 

설정 및 소스 코드

MailService 인터페이스 생성

package src.service;

public interface MailService {
    boolean send(String subject, String text, String from, String to);
}

 

MailService 인터페이스 구현 (MailServiceImpl)

package src.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

@Service
public class MailServiceImpl implements MailService {

    private final JavaMailSender javaMailSender;

    @Autowired
    public MailServiceImpl(JavaMailSender javaMailSender) {
        this.javaMailSender = javaMailSender;
    }

    @Override
    public boolean send(String subject, String text, String from, String to){
        MimeMessage message = javaMailSender.createMimeMessage();

        try {
            MimeMessageHelper helper = new MimeMessageHelper(message,true,"UTF-8");
            helper.setSubject(subject);
            helper.setText(text);
            helper.setFrom(from);
            helper.setTo(to);

            javaMailSender.send(message);
            return true;
        }catch (MessagingException e){
            e.printStackTrace();
        }
        return false;
    }
}

 

 

DispatcherServle xml 에 bean 등록
<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="smtp.gmail.com" />
        <property name="port" value="587" />
        <property name="username" value="본인아이디@gmail.com" />
        <property name="password" value="비밀번호" />
        <property name="javaMailProperties">
            <props>
                <prop key="mail.smtp.ssl.trust">smtp.gmail.com</prop>
                <prop key="mail.smtp.starttls.enable">true</prop>
                <prop key="mail.smtp.auth">true</prop>
            </props>
        </property>
 </bean>
 <bean id="mailService" class="src.service.MailServiceImpl">
 </bean>

 

controller 부분

필자는 기존에 있던 회원가입 컨트롤러에 view페이지에서 버튼을 누르면 메일을 보내는 함수를 추가

@Controller
public class JoinMembership {
    private Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();

    @Resource(name = "userDAO")
    private UserDAO userDAO;

    @Autowired
    private MailService mailService;

    @RequestMapping(value = "/checkMail/", produces = "application/text; charset=utf8")
    @ResponseBody
    private String checkMail(@RequestParam String email) {
        User user = userDAO.findOneByEmail(email);
        return gson.toJson(user);
    }

    @RequestMapping(value = "/sendMail/", method = RequestMethod.POST, produces = "application/json")
    @ResponseBody
    private boolean sendMail(HttpSession session, @RequestParam String email) {
        int randomCode = new Random().nextInt(10000) + 1000;
        String joinCode = String.valueOf(randomCode);
        session.setAttribute("joinCode", joinCode);

        String subject = "회원가입 승인 번호 입니다.";
        StringBuilder sb = new StringBuilder();
        sb.append("회원가입 승인번호는 ").append(joinCode).append(" 입니다.");
        return mailService.send(subject, sb.toString(), "본인아이디@gmail.com", email);
        }
}

 

DispatcherServle xml에 controller 등록

//src.controller는 컨트롤러가 위치한 경로로 해당 경로의 모든 컨트롤러가 등록됨
<context:component-scan base-package="src.controller"/>


View 페이지

<table class="table table-striped" style="width: 600px" align="center">
                <tr>
                    <th>이메일(아이디)</th>
                    <td>
                        <input type='email' name="email" id="email" class="form-control"
                               style="margin-right: 10px; width: 300px"
                               aria-describedby="emailHelp" placeholder="Enter email"/>
                        <input type="button" value="인증" class="btn btn-primary btn-sm"
                               onclick="checkMail()">
                    </td>
                </tr>
                <tr id="joincode">
                    <th>인증번호</th>
                    <td>
                        <input type='number' name="inputCode" id="inputCode" class="form-control"
                               style="margin-right: 10px; width: 300px" placeholder="Enter code"/>
                        <input type="button" value="확인" class="btn btn-primary btn-sm"
                               onclick="checkJoinCode()">
                    </td>
                </tr>

                <tr>
                    <th>닉네임</th>
                    <td>
                        <input type='text' name="nickName" id="nickName" class="form-control"
                               style="margin-right: 10px;" placeholder="Enter NickName"/>
                        <input type="button" value="중복체크" class="btn btn-primary btn-sm"
                               onclick="checkNick()">
                    </td>
                </tr>
                <tr>
                    <th>비밀 번호</th>
                    <td>
                        <input type="password" maxlength="40" name="pw" id="pw" class="form-control"
                               placeholder="Password">
                    </td>

                </tr>
                <tr>
                    <th>비밀 번호 확인</th>
                    <td>
                        <input type="password" maxlength="40" name="pwCheck" id="pwCheck" class="form-control"
                               placeholder="Password">
                    </td>
                </tr>
            </table>
<script>
    function checkMail() {
        var email = document.getElementById("email").value;

        if (email == "") {
            alert("메일을 입력해 주세요.")
            return false;
        }

        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
            if (xhttp.readyState == 4) {
                var data = JSON.parse(xhttp.responseText);
                if (data != null) {
                    alert("이미 가입한 메일 입니다.");
                    $("#joincode").css("display", "none");
                } else {
                    sendMail(email);
                    $("#joincode").css("display", "");
                }
            }
        };
        xhttp.open("POST", 'checkMail/', true);
        xhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
        xhttp.send('email=' + email);
        return false;
    }

    function sendMail(email) {
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
            if (xhttp.readyState == 4) {
                if (xhttp.status == 200)
                    alert("메일을 정상적으로 보냇습니다.");
                else
                    alert("올바른 메일 형식이 아닙니다.");
            }
        };
        xhttp.open("POST", 'sendMail/', true);
        xhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
        xhttp.send('email=' + email);
        return false;
    }
</script>
 
동작 순서는 view  페이지에서 인증 버튼을 누르면 checkMail이라는 자바스크립트 함수로 넘어가고 Ajax를 통하여 컨트롤러단의 checkMail 함수를 통하여 유저 테이블을 조회해서 이메일 존재 여부를 확인한다. 만약 테이블에 이메일이 없으면 checkMail에서 sendMail 함수로 이메일을 넘긴후 똑같이 Ajax를 통하여 컨트롤러 단의 sendMail 함수로 넘어가게 된다.
필자 프로젝트에는 메일로 넘긴 인증 번호를 view 페이지에 입력하고 동일한 인증번호 인지 확인하는 로직도 있으나 그 부분은생략하였다.
 
만약 이메일을 보내는 과정에서 오류가 발생한다면 DispatcherServle xml 에 등록한 메일 계정을 확인해 보고 
https://myaccount.google.com/lesssecureapps?pli=1 에서 보안 수준이 낮은 앱 허용을 사용으로 바꿔주면 된다.