Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/java/dmu/dasom/api/ApiApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableJpaAuditing
@SpringBootApplication
@EnableAsync
public class ApiApplication {

public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,7 @@ public void sendEmailsToApplicants(MailType mailType) {
}

for (Applicant applicant : applicants) {
try {
emailService.sendEmail(applicant.getEmail(), applicant.getName(), mailType);
} catch (MessagingException e) {
System.err.println("Failed to send email to: " + applicant.getEmail());
}
emailService.sendEmail(applicant.getEmail(), applicant.getName(), mailType);
}
}

Expand Down
119 changes: 76 additions & 43 deletions src/main/java/dmu/dasom/api/domain/google/service/EmailService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
Expand All @@ -19,62 +22,92 @@ public class EmailService {

private final TemplateEngine templateEngine;
private final JavaMailSender javaMailSender;
private static final Logger log = LoggerFactory.getLogger(EmailService.class);

@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 = getSubject(mailType);
String emailContent = getEmailContent(mailType);
String buttonText = getButtonText(mailType);
String buttonUrl = "https://dmu-dasom.or.kr/recruit/result";

// 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);

// 이메일 생성 및 전송
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]");

// Content-Type을 명시적으로 설정
message.setContent(htmlBody, "text/html; charset=utf-8");

javaMailSender.send(message);
log.info("Email sent successfull {}", to);
} catch (MessagingException e) {
log.error("Failed to send email to {}: {}", to, e.getMessage());
} catch (CustomException e) {
log.error("Email sending error for {}: {}", to, e.getMessage());
}
}

// 메일 제목 및 템플릿 설정
String subject;
String emailContent;
String buttonUrl = "https://dmu-dasom.or.kr/recruit/result";
String buttonText;
// 메일 유형에 맞는 제목 반환
private String getSubject(MailType mailType){
switch (mailType){
case DOCUMENT_RESULT:
return "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 서류 결과 안내";
case FINAL_RESULT:
return "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 최종 면접 결과 안내";
default:
throw new CustomException(ErrorCode.MAIL_TYPE_NOT_VALID);
}
}

// 메일 유형에 맞는 본문 반환
private String getEmailContent(MailType mailType){
switch (mailType) {
case DOCUMENT_RESULT -> {
subject = "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 서류 결과 안내";
emailContent = "먼저 다솜 34기에 많은 관심을 두고 지원해 주셔서 감사드리며,<br>" +
case DOCUMENT_RESULT:
return "먼저 다솜 34기에 많은 관심을 두고 지원해 주셔서 감사드리며,<br>" +
"내부 서류 평가 결과 및 추후 일정에 관해 안내해드리고자 이메일을 발송하게 되었습니다.<br>" +
"서류 전형 결과는 아래 버튼 혹은 홈페이지를 통해 확인이 가능합니다.";
buttonText = "서류 결과 확인하기";
}
case FINAL_RESULT -> {
subject = "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 최종 면접 결과 안내";
emailContent = "먼저 다솜 34기에 많은 관심을 두고 지원해 주셔서 감사드리며,<br>" +
case FINAL_RESULT:
return "먼저 다솜 34기에 많은 관심을 두고 지원해 주셔서 감사드리며,<br>" +
"최종 면접 결과 및 추후 일정에 관해 안내해드리고자 이메일을 발송하게 되었습니다.<br>" +
"최종 면접 결과는 아래 버튼 혹은 홈페이지를 통해 확인이 가능합니다.";
buttonText = "최종 결과 확인하기";
}
default -> throw new IllegalStateException("Unexpected value: " + mailType);
default:
throw new CustomException(ErrorCode.MAIL_TYPE_NOT_VALID);
}

// 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);

// 이메일 생성 및 전송
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]");

// Content-Type을 명시적으로 설정
message.setContent(htmlBody, "text/html; charset=utf-8");

javaMailSender.send(message);
}

// 메일 유형에 맞는 버튼 텍스트 반환
private String getButtonText(MailType mailType) {
switch (mailType) {
case DOCUMENT_RESULT:
return "서류 결과 확인하기";
case FINAL_RESULT:
return "최종 결과 확인하기";
default:
throw new CustomException(ErrorCode.MAIL_TYPE_NOT_VALID);
}
}
}
91 changes: 47 additions & 44 deletions src/test/java/dmu/dasom/api/domain/email/EmailServiceTest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dmu.dasom.api.domain.email;

import dmu.dasom.api.domain.common.exception.CustomException;
import dmu.dasom.api.domain.common.exception.ErrorCode;

import dmu.dasom.api.domain.google.enums.MailType;
import dmu.dasom.api.domain.google.service.EmailService;
import jakarta.mail.MessagingException;
Expand All @@ -18,92 +17,96 @@
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;

class EmailServiceTest {

@Mock
private JavaMailSender javaMailSender;

@Mock
private TemplateEngine templateEngine;

@InjectMocks
private EmailService emailService;

private MimeMessage mimeMessage;

@BeforeEach
void setUp() {
void setUp(){
MockitoAnnotations.openMocks(this);
mimeMessage = mock(MimeMessage.class);
when(javaMailSender.createMimeMessage()).thenReturn(mimeMessage);

// 테스트 환경에서 from 값을 설정
when(javaMailSender.createMimeMessage()).thenReturn(mock(MimeMessage.class));
ReflectionTestUtils.setField(emailService, "from", "[email protected]");
}

@Test
@DisplayName("서류 합격 메일 발송 테스트")
void sendEmail_documentResult() throws MessagingException {
@DisplayName("성공 - 서류 결과 메일 발송 테스트")
void sendDocumentResultMessage_Success() throws MessagingException {
// given
String to = "[email protected]";
String name = "지원자";
MailType mailType = MailType.DOCUMENT_RESULT;

String expectedTemplate = "email-template";
String expectedHtmlBody = "<html><body>Document Pass</body></html>";
when(templateEngine.process(eq(expectedTemplate), any(Context.class))).thenReturn(expectedHtmlBody);
String expectedHtmlBody = "<html><body>Test HTML</body></html>";
when(templateEngine.process(eq("email-template"), any(Context.class))).thenReturn(expectedHtmlBody);

// when
emailService.sendEmail(to, name, mailType);

// then
ArgumentCaptor<MimeMessage> messageCaptor = ArgumentCaptor.forClass(MimeMessage.class);
verify(javaMailSender).send(messageCaptor.capture());

MimeMessage sentMessage = messageCaptor.getValue();
assertNotNull(sentMessage);
verify(templateEngine).process(eq(expectedTemplate), any(Context.class));
//then
// 비동기 처리 확인
verify(javaMailSender, timeout(1000)).send(any(MimeMessage.class));
// 메일 전송 확인
ArgumentCaptor<Context> contextCaptor = ArgumentCaptor.forClass(Context.class);
verify(templateEngine).process(eq("email-template"), contextCaptor.capture());
Context capturedContext = contextCaptor.getValue();

// context 변수 확인
assertEquals(name, capturedContext.getVariable("name"));
assertEquals("서류 결과 확인하기", capturedContext.getVariable("buttonText"));
assertNotNull(capturedContext.getVariable("emailContent"));
}

@Test
@DisplayName("최종 합격 메일 발송 테스트")
void sendEmail_finalResult() throws MessagingException {
@DisplayName("성공 - 최종 결과 메일 발송 테스트")
void sendFinalResultMessage_Success() throws MessagingException {
// given
String to = "[email protected]";
String name = "지원자";
MailType mailType = MailType.FINAL_RESULT;

String expectedTemplate = "email-template";
String expectedHtmlBody = "<html><body>Final Pass</body></html>";
when(templateEngine.process(eq(expectedTemplate), any(Context.class))).thenReturn(expectedHtmlBody);
String expectedHtmlBody = "<html><body>Test HTML</body></html>";
when(templateEngine.process(eq("email-template"), any(Context.class))).thenReturn(expectedHtmlBody);

// when
emailService.sendEmail(to, name, mailType);

// then
ArgumentCaptor<MimeMessage> messageCaptor = ArgumentCaptor.forClass(MimeMessage.class);
verify(javaMailSender).send(messageCaptor.capture());

MimeMessage sentMessage = messageCaptor.getValue();
assertNotNull(sentMessage);
verify(templateEngine).process(eq(expectedTemplate), any(Context.class));
//then
// 비동기 처리 확인
verify(javaMailSender, timeout(1000)).send(any(MimeMessage.class));
// 메일 전송 확인
ArgumentCaptor<Context> contextCaptor = ArgumentCaptor.forClass(Context.class);
verify(templateEngine).process(eq("email-template"), contextCaptor.capture());
Context capturedContext = contextCaptor.getValue();

// context 변수 확인
assertEquals(name, capturedContext.getVariable("name"));
assertEquals("최종 결과 확인하기", capturedContext.getVariable("buttonText"));
assertNotNull(capturedContext.getVariable("emailContent"));
}

@Test
@DisplayName("잘못된 MailType 처리 테스트")
void sendEmail_invalidMailType() {
// given
@DisplayName("실패 - MailType이 null일 경우, 예외 발생 테스트")
void sendEmail_nullMailType_shouldNotSend() {
//given
String to = "[email protected]";
String name = "지원자";

// when & then
CustomException exception = assertThrows(CustomException.class, () -> {
emailService.sendEmail(to, name, null);
});
// when
emailService.sendEmail(to, name, null);

assertEquals(ErrorCode.MAIL_TYPE_NOT_VALID, exception.getErrorCode());
// then
verify(javaMailSender, never()).send(any(MimeMessage.class));
}


}
Loading