- 
                Notifications
    
You must be signed in to change notification settings  - Fork 0
 
[refactor] 이메일 발송 비동기식으로 전환 #91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
          
     Merged
      
      
    
  
     Merged
                    Changes from 2 commits
      Commits
    
    
            Show all changes
          
          
            5 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      974bd32
              
                refactor: 이메일 전송 비동기 처리 (DASOMBE-13)
              
              
                hodoon 75608bf
              
                refactor: 이메일 전송 오류시 로그 저장 DB생성, 이메일 템플릿 분기처리 (DASOMBE-13)
              
              
                hodoon 937e5f5
              
                refactor: 이메일 로그 builder 패턴으로 인스턴스 초기화 완료 (DASOMBE-13)
              
              
                hodoon 51fd724
              
                refactor: 성공여부도 저장 가능하게 수정 (DASOMBE-13)
              
              
                hodoon 5562c21
              
                refactor: 빌더 패턴 EmailLog엔티티 안으로 이동, 에러메시지 저장 로직 try-catch문 밖으로 이동 (DA…
              
              
                hodoon File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
        
          
          
            41 changes: 41 additions & 0 deletions
          
          41 
        
  src/main/java/dmu/dasom/api/domain/google/entity/EmailLog.java
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package dmu.dasom.api.domain.google.entity; | ||
| 
     | 
||
| import dmu.dasom.api.domain.google.enums.MailSendStatus; | ||
| import jakarta.persistence.*; | ||
| import lombok.AccessLevel; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
| import org.hibernate.annotations.CreationTimestamp; | ||
| 
     | 
||
| import java.time.LocalDateTime; | ||
| 
     | 
||
| @Entity | ||
| @Getter | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| public class EmailLog { | ||
| 
     | 
||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| private Long id; | ||
| 
     | 
||
| @Column(nullable = false) | ||
| private String recipientEmail; | ||
| 
     | 
||
| @Enumerated(EnumType.STRING) | ||
| @Column(nullable = false) | ||
| private MailSendStatus status; | ||
| 
     | 
||
| private String errorMessage; | ||
| 
     | 
||
| @CreationTimestamp | ||
| private LocalDateTime sentAt; | ||
| 
     | 
||
| public static EmailLog of(String recipientEmail, MailSendStatus status, String errorMessage) { | ||
| EmailLog emailLog = new EmailLog(); | ||
| emailLog.recipientEmail = recipientEmail; | ||
| emailLog.status = status; | ||
| emailLog.errorMessage = errorMessage; | ||
| return emailLog; | ||
| } | ||
| 
     | 
||
| } | ||
        
          
          
            6 changes: 6 additions & 0 deletions
          
          6 
        
  src/main/java/dmu/dasom/api/domain/google/enums/MailSendStatus.java
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package dmu.dasom.api.domain.google.enums; | ||
| 
     | 
||
| public enum MailSendStatus { | ||
| SUCCESS, | ||
| FAILURE | ||
| } | 
        
          
          
            26 changes: 26 additions & 0 deletions
          
          26 
        
  src/main/java/dmu/dasom/api/domain/google/enums/MailTemplate.java
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package dmu.dasom.api.domain.google.enums; | ||
| 
     | 
||
| import dmu.dasom.api.domain.common.exception.CustomException; | ||
| import dmu.dasom.api.domain.common.exception.ErrorCode; | ||
| import lombok.Getter; | ||
| import lombok.RequiredArgsConstructor; | ||
| 
     | 
||
| import java.util.Arrays; | ||
| 
     | 
||
| @Getter | ||
| @RequiredArgsConstructor | ||
| public enum MailTemplate { | ||
| DOCUMENT_RESULT(MailType.DOCUMENT_RESULT, "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 서류 결과 안내", "document-result-email"), | ||
| FINAL_RESULT(MailType.FINAL_RESULT, "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 최종 면접 결과 안내", "final-result-email"); | ||
| 
     | 
||
| private final MailType mailType; | ||
| private final String subject; | ||
| private final String templateName; | ||
| 
     | 
||
| public static MailTemplate getMailType(MailType mailType) { | ||
| return Arrays.stream(values()) | ||
| .filter(template -> template.getMailType() == mailType) | ||
| .findFirst() | ||
| .orElseThrow(() -> new CustomException(ErrorCode.MAIL_TYPE_NOT_VALID)); | ||
| } | ||
| } | 
        
          
          
            7 changes: 7 additions & 0 deletions
          
          7 
        
  src/main/java/dmu/dasom/api/domain/google/repository/EmailLogRepository.java
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package dmu.dasom.api.domain.google.repository; | ||
| 
     | 
||
| import dmu.dasom.api.domain.google.entity.EmailLog; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
| 
     | 
||
| public interface EmailLogRepository extends JpaRepository<EmailLog, Long> { | ||
| } | 
        
          
          
            21 changes: 21 additions & 0 deletions
          
          21 
        
  src/main/java/dmu/dasom/api/domain/google/service/EmailLogService.java
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package dmu.dasom.api.domain.google.service; | ||
| 
     | 
||
| import dmu.dasom.api.domain.google.entity.EmailLog; | ||
| import dmu.dasom.api.domain.google.enums.MailSendStatus; | ||
| import dmu.dasom.api.domain.google.repository.EmailLogRepository; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.scheduling.annotation.Async; | ||
| import org.springframework.stereotype.Service; | ||
| 
     | 
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class EmailLogService { | ||
| 
     | 
||
| private final EmailLogRepository emailLogRepository; | ||
| 
     | 
||
| @Async | ||
| public void logEmailSending(String recipientEmail, MailSendStatus status, String errorMessage) { | ||
| EmailLog emailLog = EmailLog.of(recipientEmail, status, errorMessage); | ||
| emailLogRepository.save(emailLog); | ||
| } | ||
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| 
          
            
          
           | 
    @@ -2,79 +2,73 @@ | |
| 
     | 
||
| import dmu.dasom.api.domain.common.exception.CustomException; | ||
| import dmu.dasom.api.domain.common.exception.ErrorCode; | ||
| import dmu.dasom.api.domain.google.enums.MailSendStatus; | ||
| import dmu.dasom.api.domain.google.enums.MailTemplate; | ||
| import dmu.dasom.api.domain.google.enums.MailType; | ||
| import jakarta.mail.MessagingException; | ||
| import jakarta.mail.internet.MimeMessage; | ||
| import lombok.RequiredArgsConstructor; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.mail.javamail.JavaMailSender; | ||
| import org.springframework.mail.javamail.MimeMessageHelper; | ||
| import org.springframework.scheduling.annotation.Async; | ||
| import org.springframework.stereotype.Service; | ||
| import org.thymeleaf.TemplateEngine; | ||
| import org.thymeleaf.context.Context; | ||
| 
     | 
||
| @Slf4j | ||
| @RequiredArgsConstructor | ||
| @Service | ||
| public class EmailService { | ||
| 
     | 
||
| private final TemplateEngine templateEngine; | ||
| private final JavaMailSender javaMailSender; | ||
| private final EmailLogService emailLogService; | ||
| 
     | 
||
| @Value("${spring.mail.username}") | ||
| private String from; | ||
| 
     | 
||
| public void sendEmail(String to, String name, MailType mailType) throws MessagingException { | ||
| if (mailType == null){ | ||
| throw new CustomException(ErrorCode.MAIL_TYPE_NOT_VALID); | ||
| } | ||
| @Async | ||
| public void sendEmail(String to, String name, MailType mailType) { | ||
| try { | ||
| if (mailType == null) { | ||
| throw new CustomException(ErrorCode.MAIL_TYPE_NOT_VALID); | ||
| } | ||
| 
     | 
||
| // 메일 제목 및 템플릿 설정 | ||
| String subject; | ||
| String emailContent; | ||
| String buttonUrl = "https://dmu-dasom.or.kr/recruit/result"; | ||
| String buttonText; | ||
| // 메일 템플릿 조회 | ||
| MailTemplate mailTemplate = MailTemplate.getMailType(mailType); | ||
| String buttonUrl = "https://dmu-dasom.or.kr/recruit/result"; | ||
| 
     | 
||
| switch (mailType) { | ||
| case DOCUMENT_RESULT -> { | ||
| subject = "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 서류 결과 안내"; | ||
| emailContent = "먼저 다솜 34기에 많은 관심을 두고 지원해 주셔서 감사드리며,<br>" + | ||
| "내부 서류 평가 결과 및 추후 일정에 관해 안내해드리고자 이메일을 발송하게 되었습니다.<br>" + | ||
| "서류 전형 결과는 아래 버튼 혹은 홈페이지를 통해 확인이 가능합니다."; | ||
| buttonText = "서류 결과 확인하기"; | ||
| } | ||
| case FINAL_RESULT -> { | ||
| subject = "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 최종 면접 결과 안내"; | ||
| emailContent = "먼저 다솜 34기에 많은 관심을 두고 지원해 주셔서 감사드리며,<br>" + | ||
| "최종 면접 결과 및 추후 일정에 관해 안내해드리고자 이메일을 발송하게 되었습니다.<br>" + | ||
| "최종 면접 결과는 아래 버튼 혹은 홈페이지를 통해 확인이 가능합니다."; | ||
| buttonText = "최종 결과 확인하기"; | ||
| } | ||
| default -> throw new IllegalStateException("Unexpected value: " + mailType); | ||
| } | ||
| // HTML 템플릿에 전달할 데이터 설정 | ||
| Context context = new Context(); | ||
| context.setVariable("name", name); // 지원자 이름 전달 | ||
| context.setVariable("buttonUrl", buttonUrl); // 버튼 링크 전달 | ||
| 
     | 
||
| // HTML 템플릿에 전달할 데이터 설정 | ||
| Context context = new Context(); | ||
| context.setVariable("name", name); // 지원자 이름 전달 | ||
| context.setVariable("emailContent", emailContent); // 이메일 내용 전달 | ||
| context.setVariable("buttonUrl", buttonUrl); // 버튼 링크 전달 | ||
| context.setVariable("buttonText", buttonText); | ||
| 
     | 
||
| // HTML 템플릿 처리 | ||
| String htmlBody = templateEngine.process("email-template", context); | ||
| // HTML 템플릿 처리 | ||
| String htmlBody = templateEngine.process(mailTemplate.getTemplateName(), context); | ||
| 
     | 
||
| // 이메일 생성 및 전송 | ||
| MimeMessage message = javaMailSender.createMimeMessage(); | ||
| MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); | ||
| // 이메일 생성 및 전송 | ||
| MimeMessage message = javaMailSender.createMimeMessage(); | ||
| MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); | ||
| 
     | 
||
| helper.setTo(to); | ||
| helper.setSubject(subject); | ||
| helper.setText(htmlBody, true); | ||
| helper.setFrom((from != null && !from.isEmpty()) ? from : "[email protected]"); | ||
| helper.setTo(to); | ||
| helper.setSubject(mailTemplate.getSubject()); | ||
| helper.setText(htmlBody, true); | ||
| helper.setFrom((from != null && !from.isEmpty()) ? from : "[email protected]"); | ||
| 
     | 
||
| // Content-Type을 명시적으로 설정 | ||
| message.setContent(htmlBody, "text/html; charset=utf-8"); | ||
| // Content-Type을 명시적으로 설정 | ||
| message.setContent(htmlBody, "text/html; charset=utf-8"); | ||
| 
     | 
||
| javaMailSender.send(message); | ||
| javaMailSender.send(message); | ||
| log.info("Email sent successfull {}", to); | ||
| } catch (MessagingException e) { | ||
| log.error("Failed to send email to {}: {}", to, e.getMessage()); | ||
| emailLogService.logEmailSending(to, MailSendStatus.FAILURE, e.getMessage()); | ||
| } catch (CustomException e) { | ||
| log.error("Email sending error for {}: {}", to, e.getMessage()); | ||
| emailLogService.logEmailSending(to, MailSendStatus.FAILURE, e.getMessage()); | ||
| } | ||
| } | ||
| 
     | 
||
| } | ||
        
          
          
            122 changes: 122 additions & 0 deletions
          
          122 
        
  src/main/resources/templates/document-result-email.html
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="ko"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| <meta name="color-scheme" content="light dark"> | ||
| <meta name="supported-color-schemes" content="light dark"> | ||
| <title>이메일 안내</title> | ||
| </head> | ||
| <body style=" | ||
| background-color: #17171B; | ||
| color: white !important; | ||
| font-family: 'Pretendard', sans-serif; | ||
| display: flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| height: 100vh; | ||
| margin: 0;"> | ||
| <div style=" | ||
| width: 740px; | ||
| height: 680px; | ||
| background: #17171B; | ||
| padding: 30px; | ||
| position: relative;"> | ||
| <div style=" | ||
| display: flex; | ||
| justify-content: center; | ||
| position: relative; | ||
| margin-bottom: 20px;"> | ||
| <div style=" | ||
| width: 100%; | ||
| display: flex; | ||
| justify-content: space-between; | ||
| align-items: center;"> | ||
| <div style=" | ||
| flex: 1; | ||
| border-top: 1px solid #00B493; | ||
| margin: 0 10px;"> | ||
| 
     | 
||
| </div> | ||
| <img src="https://dmu-dasom.or.kr/static/media/dasomLogo.c82d220d8093c3cb8d7fc0b148cafcd1.svg" alt="로고" style=" | ||
| width: 21px; | ||
| height: 24px; | ||
| border-radius: 3px;"> | ||
| <div style=" | ||
| flex: 1; | ||
| border-top: 1px solid #00B493; | ||
| margin: 0 10px;"> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| 
     | 
||
| <div style=" | ||
| font-size: 48px; | ||
| font-weight: 900; | ||
| color: #00B493; | ||
| margin-bottom: 30px;"> | ||
| DASOM | ||
| </div> | ||
| <div style=" | ||
| font-size: 20px; | ||
| font-weight: 600; | ||
| margin-bottom: 5px; | ||
| color: white !important;" | ||
| th:text="${name} + '님 안녕하세요.'"> | ||
| </div> | ||
| <div style=" | ||
| font-size: 20px; | ||
| font-weight: 600; | ||
| margin-bottom: 5px; | ||
| color: white !important;"> | ||
| 컴퓨터공학부 전공동아리 다솜입니다. | ||
| </div> | ||
| 
     | 
||
| <div style=" | ||
| font-size: 16px; | ||
| font-weight: 400; | ||
| line-height: 2.5; | ||
| text-align: right; | ||
| margin-bottom: 40px; | ||
| color: white !important;"> | ||
| 먼저 다솜 35기에 많은 관심을 두고 지원해 주셔서 감사드리며,<br> | ||
| 내부 서류 평가 결과 및 추후 일정에 관해 안내해드리고자 이메일을 발송하게 되었습니다.<br> | ||
| 서류 전형 결과는 아래 버튼 혹은 홈페이지를 통해 확인이 가능합니다. | ||
| </div> | ||
| 
     | 
||
| <div style="display: flex; | ||
| justify-content: flex-end; | ||
| margin-bottom: 40px;"> | ||
| <a th:href="${buttonUrl}" | ||
| style=" | ||
| background: #00B493; | ||
| color: white !important; | ||
| font-size: 16px; | ||
| font-weight: 400; | ||
| padding: 10px 20px; | ||
| border-radius: 5px; | ||
| display: flex; | ||
| align-items: center; | ||
| text-decoration: none;"> | ||
| <span>서류 결과 확인하기</span> | ||
| <span style=" | ||
| border: solid white; | ||
| border-width: 0 2px 2px 0; | ||
| display: inline-block; | ||
| padding: 5px; | ||
| transform: rotate(-45deg); | ||
| margin-left: 10px;"> | ||
| </span> | ||
| </a> | ||
| </div> | ||
| 
     | 
||
| <div style="font-size: 16px; | ||
| font-weight: 400; | ||
| line-height: 1.5; | ||
| color: white !important;"> | ||
| 또한, 문의 사항은 본 메일에 회신 또는 아래 번호로 편하게 연락 부탁드립니다.<br> | ||
| 010-6361-3481 | ||
| </div> | ||
| </div> | ||
| </body> | ||
| </html> | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
      
      Oops, something went wrong.
        
    
  
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.