[Spring email]Intellij Spring 이메일 보내기 :: 회원가입 SMTP 인증 메일 전송

2019. 10. 19. 02:52Spring

웹개발을 할때 , 메일을 자동으로 전송해주는 기능이 필요할 때가 있다.

오늘은 본인이 회원가입 시 Google SMPT를 이용한 메일을 보내는 글을 올리겠다.

우선 나는 Intellij를 이용해 Spring  MVC환경에서 구축하는 전제하에 시작하겠다.


1. pom.xml

우선 maven 설정을 해줘야 한다. 아래와 같은 라이브러리를 다운받아주자.

<!-- Mail -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.6.1</version>
        </dependency>

Maven을 Import 시켜준 후 lib폴더에 해당다운받은 라이브러리를 추가시켜준다.

 

2. applicationContext.xml

스프링 설정 xml에 메일과 관련된 빈을 추가해줘야 한다. 본인은 applicationContext라는 스프링설정 xml이지만 이클립스를 사용하는 유저일 경우 이름이 다를 수 있으므로 안심하고 스프링 설정 xml에 추가해주면 된다.

<util:properties id="emailConfig" location="classpath:/config/emailConfig.xml"/>

<!-- Mail 인증 관련 -->
    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="#{emailConfig['mail.host']}" />
        <property name="port" value="#{emailConfig['mail.port']}" />
        <property name="username" value="#{emailConfig['mail.manager']}" />
        <property name="password" value="#{emailConfig['mail.password']} " />
        <property name="javaMailProperties">
            <props>
                <prop key="mail.transport.protocol">smtp</prop>
                <prop key="mail.smtp.auth">true</prop>
                <prop key="mail.smtp.starttls.enable">true</prop>
                <prop key="mail.debug">true</prop>
            </props>
        </property>
    </bean>

 value값에 "#{emailConfig['mail.host']} 등등 알수없는 문자들을 보고 이것이 무엇인지 코드를 보면 의문점이 들것이다. 

이것은 메일과 관련된 정보를 코드에 직접 포함시키지 않고 xml로 따로 저장해 둔  후, util:properties를 이용해 context파일에 프로퍼티를 등록해서 사용하기 위함이다.

내 개인정보를 보호하는 목적도 있지만, GITHUB같은 공유사이트에 개인정보파일은 제외하고 코드를 공유하기위한 목적도 있다.

DB연결도 이러한 식으로 연결하는 습관을 들이는것을 추천한다.

<?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd" >
<properties>
<entry key="mail.host">smtp.gmail.com</entry>
<entry key="mail.port">587</entry>
<entry key="mail.manager">1111@gmail.com</entry>
<entry key="mail.password">1111</entry>
</properties>

위의 코드는 상단에 <util:properties id="emailConfig" location="classpath:/config/emailConfig.xml"/>로 등록했던 emailConfig.xml의 원본코드이다. location의 위치와 같은 곳에 생성해야 xml을 인식할 수 있으므로 정확히 작성해야한다.

3. DB설계

우선은 큰 틀로 4가지를 생각해줘야 한다.

1)회원관련 테이블에 권한키(authKey), 권한상태(authstatus) 가 필요하다.

2) 회원가입 시,  임의의 코드를 조합해  권한키(authKey)를 생성, 권한상태(authstatus)는 default값인 0으로 설정한다.

3) 사용자에게 권한키(authKey)를 담은 메일을 전송, db에 전송한 권한키를 update한다.

4)  사용자가 메일 인증을 누른 후, 권한키를 db에 select해 해당 정보의 권한상태를 1로 update해준다.

우선 이를 위해 db를 설계해야 하는데 본인은 아래와 같은 user테이블을 만들어 줬다.

 

4. 코드

[Controller.java]

//회원 가입
@RequestMapping(value="joinPost", method=RequestMethod.POST)
    public String joinPost(@ModelAttribute("uVO") UserVO uVO) throws Exception {
        logger.info("statement join member: " + uVO.toString());
        userService.createByUser(uVO);
        return "user/joinPost";
    }

Controller를 살펴보저면 먼저 회원가입 버튼을 클릭시 유저의 정보를 create해줍니다.

[ServiceImpl.java]

@Service
public class UserServiceImpl implements UserService {
  @Autowired
  private JavaMailSender mailSender;


    @Override
    public void createByUser(UserVO userVO) throws Exception {
        uDAO.createByUser(userVO);

        String authKey = new TempKey().getKey(8, false);
        userVO.setAuthkey(authKey);
        uDAO.updateAuthKey(userVO);

        // mail 작성 관련기능
        MailUtils sendMail = new MailUtils(mailSender);

        sendMail.setSubject("[Jihye's CRUD] 회원가입 이메일 인증");
        sendMail.setText(new StringBuffer().append("<h1>[이메일 인증]</h1>")
                .append("<p>아래 링크를 클릭하시면 이메일 인증이 완료됩니다.</p>")
                .append("<a href='http://localhost:8090/user/joinConfirm?uid=")
                .append(userVO.getUid())
                .append("&email=")
                .append(userVO.getEmail())
                .append("&authkey=")
                .append(authKey)
                .append("' target='_blenk'>이메일 인증 확인</a>")
                .toString());
        sendMail.setFrom("altjd815@gmail.com ", "Lee Ji-Hye");
        sendMail.setTo(userVO.getEmail());
        sendMail.send();

     }
    }

 

우선, 눈에뜨는게 바로 TempKey()라는 클래스인데요. 이것은 임의의 인증번호를 생성하기위해 만든 클래스입니다. TempKey클래스의 getKey메서드를 통해 인증번호 자리수와  대문자소문자여부를 전달값으로 넣어주면 해당조건에 맞춰 임시인증번호가 생성됩니다.

[ TempKey.java ]

public class TempKey {
    private int size;
    private boolean lowerCheck;
    
    public String getKey(int size, boolean lowerCheck) {
        this.size = size;
        this.lowerCheck = lowerCheck;
        return init();
    }

    private String init() {
        Random random = new Random();
        StringBuffer str = new StringBuffer();
        int num = 0;

        do {
            num = random.nextInt(75) + 48;
            if (isAbleRandom(num)){
                str.append((char)num);
            } else {
                continue;
            }
        } while (str.length() < size);

        if(lowerCheck)
            return str.toString().toLowerCase();
        return str.toString();
    }

    private boolean isAbleRandom(int random) {
        return (random >= 48 && random <= 57) || (random >= 65 && random <= 90) || (random >= 97 && random <= 122);
    }
}

[ mailUtils.java ]

public class MailUtils {

    private JavaMailSender mailSender;
    private MimeMessage message;
    private MimeMessageHelper messageHelper;

    public MailUtils(JavaMailSender mailSender) throws MessagingException {
        this.mailSender = mailSender;
        message = this.mailSender.createMimeMessage();
        messageHelper = new MimeMessageHelper(message,true,"UTF-8");
    }

    public void setSubject(String subject) throws MessagingException {
        messageHelper.setSubject(subject);
    }

    public void setText(String htmlContent) throws MessagingException {
        messageHelper.setText(htmlContent, true);
    }

    public void setFrom(String email, String name) throws UnsupportedEncodingException, MessagingException {
        messageHelper.setFrom(email, name);
    }

    public void setTo(String email) throws MessagingException {
        messageHelper.setTo(email);
    }

    public void addInline(String contentId, DataSource dataSource) throws MessagingException {
        messageHelper.addInline(contentId, dataSource);
    }

    public void send() {
        mailSender.send(message);
    }


}

 

위의 mailUtils는 mail의 구성요소를 (수신자,발신자,제목,첨부파일 등등의 메서드들)선언 하는 클래스입니다.  여기까지가 메일의 설정의 끝입니다. 

이제 상단의 service에서 이메일인증 링크의 설정을 마무리지어야 합니다.

[Controller.java]

// email 인증
    @RequestMapping(value="joinConfirm", method=RequestMethod.GET)
    public String emailConfirm(@ModelAttribute("uVO") UserVO uVO, Model model) throws Exception {
        logger.info(uVO.getEmail() + ": auth confirmed");
        uVO.setAuthstatus(1);
        userService.updateAuthStatus(uVO);
        model.addAttribute("auth_check", 1);
        return "user/joinPost";
    }

링크를 클릭시, 권한상태를 1로 업데이트 해주면 메일 인증이 완료됩니다.

 

하지만.... 이것은 완벽히 마무리된 코드가 아닙니다.

혹시 메일이 전송되는 도중 오류가 나서 메일이 전송되지 않았을때 어떻게 될까요????

회원가입시 기입햇던 아이디나 이메일이 insert되지 않아야 하지만 위와같은 코드를 기입하고 실행했을시

오류와 관계없이 정보들이 DB에 insert됩니다. 당연히 메일이 비전송됐을때 모든것이 취소되야 되는데도 말이지요.

이러한 단위별 실행을 트랜잭션이라 부릅니다. 다음게시물엔 메일전송에 대한 트랜젝션 처리를 포스팅하겠습니다. 

궁금한 점이 있으시면 댓글을 달아주시면 친절히 설명해드리겠습니다!