diff --git a/build.gradle b/build.gradle index 6e138896..4043f622 100644 --- a/build.gradle +++ b/build.gradle @@ -139,6 +139,9 @@ dependencies { // Mail Service implementation 'org.springframework.boot:spring-boot-starter-mail' + // Thymeleaf (이메일 템플릿) + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + // Spring Security implementation 'org.springframework.boot:spring-boot-starter-security' testImplementation 'org.springframework.security:spring-security-test' diff --git a/src/main/java/ku_rum/backend/domain/common/mail/application/MailSenderService.java b/src/main/java/ku_rum/backend/domain/common/mail/application/MailSenderService.java index 2fa413ae..c693c2d1 100644 --- a/src/main/java/ku_rum/backend/domain/common/mail/application/MailSenderService.java +++ b/src/main/java/ku_rum/backend/domain/common/mail/application/MailSenderService.java @@ -1,9 +1,11 @@ package ku_rum.backend.domain.common.mail.application; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; import ku_rum.backend.global.exception.user.MailSendException; import lombok.RequiredArgsConstructor; -import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; import static ku_rum.backend.global.support.status.BaseExceptionResponseStatus.MAIL_SEND_EXCEPTION; @@ -13,19 +15,18 @@ public class MailSenderService { private final JavaMailSender emailSender; - public void send(String toEmail, String title, String text) { + public void sendHtml(String toEmail, String title, String htmlContent) { try { - emailSender.send(createEmailForm(toEmail, title, text)); - } catch (RuntimeException e) { + MimeMessage mimeMessage = emailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8"); + + helper.setTo(toEmail); + helper.setSubject(title); + helper.setText(htmlContent, true); + + emailSender.send(mimeMessage); + } catch (MessagingException e) { throw new MailSendException(MAIL_SEND_EXCEPTION); } } - - private SimpleMailMessage createEmailForm(String toEmail, String title, String text) { - SimpleMailMessage message = new SimpleMailMessage(); - message.setTo(toEmail); - message.setSubject(title); - message.setText(text); - return message; - } -} +} \ No newline at end of file diff --git a/src/main/java/ku_rum/backend/domain/common/mail/application/MailService.java b/src/main/java/ku_rum/backend/domain/common/mail/application/MailService.java index 11967961..5942db7d 100644 --- a/src/main/java/ku_rum/backend/domain/common/mail/application/MailService.java +++ b/src/main/java/ku_rum/backend/domain/common/mail/application/MailService.java @@ -4,13 +4,14 @@ import ku_rum.backend.domain.common.mail.domain.repository.MailAuthRepository; import ku_rum.backend.domain.common.mail.dto.request.MailSendRequest; import ku_rum.backend.domain.common.mail.dto.request.MailVerificationRequest; -import ku_rum.backend.domain.common.mail.dto.response.MailVerificationResponse; import ku_rum.backend.global.exception.user.MailSendException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.thymeleaf.context.Context; +import org.thymeleaf.spring6.SpringTemplateEngine; import java.time.Duration; @@ -24,6 +25,7 @@ public class MailService { private final MailSenderService mailSenderService; private final MailAuthRepository mailAuthRepository; + private final SpringTemplateEngine templateEngine; @Async @Transactional @@ -34,10 +36,17 @@ public void sendCodeToEmail(final MailSendRequest request) { request.email(), MAIL_SEND_INFO.getCODE_LENGTH()); - mailSenderService.send(request.email(), MAIL_SEND_INFO.getTITLE(), mailAuth.getAuthCode()); + String htmlContent = createEmailContent(mailAuth.getAuthCode()); + mailSenderService.sendHtml(request.email(), MAIL_SEND_INFO.getTITLE(), htmlContent); mailAuthRepository.save(mailAuth, Duration.ofMillis(MAIL_SEND_INFO.getAUTH_EXPIRED_MILLS())); } + private String createEmailContent(String code) { + Context context = new Context(); + context.setVariable("code", code); + return templateEngine.process("email_template", context); + } + private void deleteByEmail(MailSendRequest request) { mailAuthRepository.findByEmail(request.email()) .ifPresent(existingMailAuth -> { diff --git a/src/main/resources/templates/email_template.html b/src/main/resources/templates/email_template.html new file mode 100644 index 00000000..be9cdf91 --- /dev/null +++ b/src/main/resources/templates/email_template.html @@ -0,0 +1,92 @@ + + + + + + + Kuroom 인증 메일 + + + + + +
+ +
+ + + + + + +
+

KUROOM

+
+
+ +
+
+ +
+

+ 이메일 인증 +

+

+ 건국대학교 학생들을 위한 서비스, 쿠룸 +

+

+ 안녕하세요. 쿠룸입니다.
+ 앱으로 돌아가서 아래 인증 코드를 입력해주세요.
+ 해당 인증코드는 3분간 유효합니다. +

+ +

+ 123456 +

+
+
+ +

+ Copyright © 2026 Kuroom. All rights reserved. +

+
+
+
+
+ + diff --git a/src/test/java/ku_rum/backend/domain/common/mail/application/MailServiceTest.java b/src/test/java/ku_rum/backend/domain/common/mail/application/MailServiceTest.java index 0f0b0e25..5f742c36 100644 --- a/src/test/java/ku_rum/backend/domain/common/mail/application/MailServiceTest.java +++ b/src/test/java/ku_rum/backend/domain/common/mail/application/MailServiceTest.java @@ -1,5 +1,16 @@ package ku_rum.backend.domain.common.mail.application; +import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.time.Duration; +import java.util.Optional; import ku_rum.backend.domain.common.mail.domain.MailAuth; import ku_rum.backend.domain.common.mail.domain.repository.MailAuthRepository; import ku_rum.backend.domain.common.mail.dto.request.MailSendRequest; @@ -11,31 +22,21 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.test.context.ActiveProfiles; - -import java.time.Duration; -import java.util.Optional; +import org.thymeleaf.context.Context; +import org.thymeleaf.spring6.SpringTemplateEngine; -import static org.junit.Assert.assertThrows; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.*; - -@ActiveProfiles("test") @ExtendWith(MockitoExtension.class) class MailServiceTest { - @Mock - private JavaMailSender emailSender; - @Mock private MailSenderService mailSenderService; @Mock private MailAuthRepository mailAuthRepository; + @Mock + private SpringTemplateEngine templateEngine; + @InjectMocks private MailService mailService; @@ -44,13 +45,16 @@ class MailServiceTest { void sendCodeToEmail_success() { // given MailSendRequest request = new MailSendRequest("test@example.com"); - MailAuth mailAuth = MailAuth.create(request.email(), 6); + String htmlContent = "테스트"; + + given(templateEngine.process(eq("email_template"), any(Context.class))).willReturn(htmlContent); // when mailService.sendCodeToEmail(request); // then - verify(mailSenderService, times(1)).send(eq(request.email()), anyString(), anyString()); + verify(templateEngine, times(1)).process(eq("email_template"), any(Context.class)); + verify(mailSenderService, times(1)).sendHtml(eq(request.email()), anyString(), eq(htmlContent)); verify(mailAuthRepository, times(1)).save(any(MailAuth.class), any(Duration.class)); }