[SpringBoot] Thymeleaf를 이용한 이메일 전송

애이용·2021년 6월 15일
1

springboot

목록 보기
13/20
post-thumbnail
post-custom-banner

이전 포스팅에서는 html 형식으로 이메일 내용을 작성할 때 StringBuilder를 이용해서 추가하는 식으로 html 코드를 작성했다.

하지만 더 깔끔하게 적용할 수 있는 방법은 없을까 생각하다가 Thymeleaf 템플릿을 이용한 방법을 알아냈다.
(세팅도 업데이트 되었으니 이 글 참고 바람)

Thymeleaf 템플릿을 적용하지 않은 코드

    private MimeMessage sendEmailMessage(String email, String code) throws Exception {
        MimeMessage message = emailSender.createMimeMessage();
        String code = createKey();
        message.addRecipients(MimeMessage.RecipientType.TO, email);
        message.setSubject("[인증 코드]" + code);
        message.setText(createHtml(code), "utf-8", "html");
        emailSender.send(message);
    }
    private String createHtml(String code) {
        sb.append("<div align=\"center\" style=\"font-size: 15px\">");
        sb.append("<br/><img src=\"").append("~").append("\"/>");
        sb.append("<br/><br/>~");
        sb.append("<br/><br/>인증번호를 입력해 주세요.<br/><br/>");
        sb.append("~");
        return sb.toString();
    }

이제 템플릿 언어를 적용하면 코드가 얼마나 깔끔해는지 살펴 보자

📄 다루는 파일

  • build.gradle
  • application.yml
  • EmailService
  • EmailServiceTest
  • mail.html

✔️ 의존성 추가

// 이메일 전송
implementation group: 'com.sun.mail', name: 'javax.mail', version: '1.6.2'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-mail', version: '2.5.1'

// 타임리프(이메일 내용 화면)
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

✔️ application.yml 설정

spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: [이메일 계정]
    password: [계정 비밀번호]
    properties:
      mail:
        smtp:
          auth: true
          starttls: # 추가 안하면 SMTPSendFailedException
            enalble: true
            required: true  

타임리프는 따로 설정하지 않아도 된다.

이때 먼저, gmail 계정 보안을 낮춰야 메일 전송이 가능하다
해당 링크에 들어가 설정하고 진행하자!

✔️ EmailService

@Slf4j
@RequiredArgsConstructor
@Service
public class EmailService {

    private final JavaMailSender emailSender;
    private final SpringTemplateEngine templateEngine;


    public void sendEmailMessage(String email) throws Exception {
        String code = createCode(); // 인증코드 생성
        MimeMessage message = emailSender.createMimeMessage();

        message.addRecipients(MimeMessage.RecipientType.TO, email); // 보낼 이메일 설정
        message.setSubject("[인증 코드] " + code); // 이메일 제목
        message.setText(setContext(code), "utf-8", "html"); // 내용 설정(Template Process)
        
        // 보낼 때 이름 설정하고 싶은 경우
        // message.setFrom(new InternetAddress([이메일 계정], [설정할 이름]));
        
        emailSender.send(message); // 이메일 전송
    }

    private String setContext(String code) { // 타임리프 설정하는 코드
        Context context = new Context();
        context.setVariable("code", code); // Template에 전달할 데이터 설정
        return templateEngine.process("mail", context); // mail.html 
    }
}
    
    private String createCode() {
        // 인증 코드 생성 
    }
}

✔️ Thymeleaf 템플릿 적용 [resources/templates/mail.html]

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en">
<body>
    <div align="center" style="font-size: 15px">
        <img src="https://media.vlpt.us/images/ayoung0073/post/090c55bf-79cb-4724-b081-a843a0c3d0c7/springboot.jpeg" width="400" alt=""/>
        <br><br>
        <span style="border: 1px solid; padding: 8px;font-size: 20px;" th:text="${code}"></span>
    </div>
</body>
</html>

✔️ 테스트 코드 작성

@SpringBootTest
class EmailServiceTest {

    @Autowired
    private EmailService emailService;

    @Test
    void sendMail() throws Exception {
        emailService.sendEmailMessage([보낼 이메일 계정]);
    }
}

성공!

다시 한 번 Thymeleaf 적용 여부 차이를 보자!

  • Thymeleaf 템플릿을 적용하지 않은 코드
    private MimeMessage sendEmailMessage(String email, String code) throws Exception {
        MimeMessage message = emailSender.createMimeMessage();
        String code = createKey();
        message.addRecipients(MimeMessage.RecipientType.TO, email);
        message.setSubject("[인증 코드]" + code);
        message.setText(createHtml(code), "utf-8", "html");
        emailSender.send(message);
    }
    private String createHtml(String code) {
        sb.append("<div align=\"center\" style=\"font-size: 15px\">");
        sb.append("<br/><img src=\"").append("~").append("\"/>");
        sb.append("<br/><br/>~");
        sb.append("<br/><br/>인증번호를 입력해 주세요.<br/><br/>");
        sb.append("~");
        return sb.toString();
    }
  • Thymeleaf 템플릿을 적용한 코드
    public void sendEmailMessage(String email) throws Exception {
        String code = createCode();
        MimeMessage message = emailSender.createMimeMessage();
        message.addRecipients(MimeMessage.RecipientType.TO, email);
        message.setSubject("[인증 코드] " + code); 
        message.setText(setContext(code), "utf-8", "html"); 
        emailSender.send(message);
    }
    private String setContext(String code) {
        Context context = new Context();
        context.setVariable("code", code);
        return templateEngine.process("mail", context);
    }
}

이렇게 html 코드 쓰는 파일을 따로 생성하는 것이 보기에도 깔끔해보이고, 이메일 화면 수정할 때도 훨씬 편할 듯하다


참고) 인증 코드 생성 코드

    private String createCode() {
        StringBuilder code = new StringBuilder();
        Random rnd = new Random();
        for (int i = 0; i < 7; i++) {
            int rIndex = rnd.nextInt(3);
            switch (rIndex) {
                case 0:
                    code.append((char) (rnd.nextInt(26) + 97));
                    break;
                case 1:
                    code.append((char) (rnd.nextInt(26) + 65));
                    break;
                case 2:
                    code.append((rnd.nextInt(10)));
                    break;
            }
        }
        return code.toString();
    }

  • 인증 코드 검증은 따로 포스팅 할 예정이다.
    • 내용 : Redis 캐시 적용, 검증 로직
profile
로그를 남기자 〰️
post-custom-banner

0개의 댓글