본문 바로가기

개인 프로젝트/남·여 매칭 서비스

이메일 발송 기능 refactoring

남·여 매칭 서비스 개발 중 학교 인증 기능을 위해 이메일 인증 기능을 도입하게 되었다. 

기능은 완성하였으나 유지보수·확장 면에서 부족한 부분이 있어 리팩토링을 하게 되었다.

 

@Service
@RequiredArgsConstructor
public class EmailService {

  private final JavaMailSender javaMailSender;

  public void sendEmail(String toEmail) {
    MimeMessage mimeMessage = javaMailSender.createMimeMessage();
    String verificationCode = createVerificationCode();

    try {
      MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");

      mimeMessageHelper.setSubject("MakeLover 인증코드 메일 💌");
      mimeMessageHelper.setFrom("makeloverwithus@naver.com");
      mimeMessageHelper.setTo(toEmail);

	String content = "<h2>MakeLover 인증코드입니다 <br> 서비스에 돌아가서 입력해 주세요</h2>\n"
      	+ "<h3>인증코드 : " + verificationCode + "</h3>"
      	+ "<img src=\"cid:love-image\" alt=\"대체 텍스트\">";
      
      mimeMessageHelper.setText(content, true);
      mimeMessageHelper.addInline("love-image", new ClassPathResource("static/love.png"));

      javaMailSender.send(mimeMessage);

    } catch (MessagingException e) {
      throw new RuntimeException(e);
    }
  }

  private String createVerificationCode() {
  	Random random = new Random();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 4; i++) {
      sb.append(random.nextInt(10));
    }
    return sb.toString();
  }

}

 

기존 코드에는 다음과 같은 문제점들이 존재했다

  • HTML base 의 이메일 content 에서 Java 코드와 HTML 이 뒤섞여있어 유지보수가 어렵다
  • 이메일을 보내는 작업이 여러 번 필요하다고 한다면 중복된 코드가 여러 번 발생하게 된다
    • 한 메서드에서 메일을 보내는 기능과 메일을 만드는 기능이 모두 있다

따라서 다음과 같은 리팩토링이 필요하였다

  1. view 화면과 데이터의 분리
  2. 함수가 1가지만 하도록 함수 나누기

또한 클린코드에서 말하듯이 함수 당 추상화 수준을 동일하게 하였다. (등록을 위한 이메일 발송 기능에서 이메일 만들기, 이메일 발송과 같은 동일한 추상화 수준을 사용하였다)

또한 내려가기 규칙을 활용하여 아래로 내려갈 수록 추상화 수준이 낮아지도록 하였다.

 

@Service
@RequiredArgsConstructor
public class EmailService {

  private final JavaMailSender javaMailSender;
  private final SpringTemplateEngine springTemplateEngine;

  /*
  동일한 추상화 수준으로 refactoring
  1. 이메일을 만드는 기능
  2. 이메일 발송 기능
  함수를 잘게 나눈 결과 이메일을 보내는 작업이 또 생기더라도 이메일을 만드는 메서드 하나만 추가하면 된다.
  핵심으로는 중복이 사라진다.
   */
   
  public void sendEmailForRegister(String toEmail) {
    MimeMessage mimeMessage = makeEmailForRegister(toEmail);
    sendEmail(mimeMessage);
  }

  private MimeMessage makeEmailForRegister(String toEmail)  {
    MimeMessage mimeMessage = javaMailSender.createMimeMessage();
    String verificationCode = createVerificationCode();

    try {
      MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");

      mimeMessageHelper.setSubject("MakeLover 인증코드 메일 💌");
      mimeMessageHelper.setFrom("makeloverwithus@naver.com");
      mimeMessageHelper.setTo(toEmail);

      Context context = new Context();
      context.setVariable("code", verificationCode);

      String emailContent = springTemplateEngine.process("mail.html", context);
      mimeMessageHelper.setText(emailContent, true);
      mimeMessageHelper.addInline("love-image", new ClassPathResource("static/love.png"));

    } catch (MessagingException e) {
      throw new EmailCreationFailedException(ErrorCode.EMAIL_CREATION_FAILED);
    }
    return mimeMessage;
  }

  private void sendEmail(MimeMessage mimeMessage) {
    try {
      javaMailSender.send(mimeMessage);
    } catch (MailException e) {
      throw new EmailSendFailedException(ErrorCode.EMAIL_SEND_FAILED);
    }
  }

  private String createVerificationCode() {
    Random random = new Random();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 4; i++) {
      sb.append(random.nextInt(10));
    }
    return sb.toString();
  }

}

 

다음은 static 폴더 밑에 있는 mail.html 

# mail.html
<!DOCTYPE html>
<html lang="ko">
<body>
<h2>학교별 남·여 매칭서비스 플랫폼 MakeLover 입니다 </h2>
<h2>인증코드를 알려드리오니 서비스에 돌아가서 입력해 주세요</h2>
<h2>인증 코드 : <span th:text="${code}"></span></h2>
<img src="cid:love-image" alt="대체 이미지"/>
</body>
</html>

 

결과