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 인증 메일
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 이메일 인증
+
+
+ 건국대학교 학생들을 위한 서비스, 쿠룸
+
+
+ 안녕하세요. 쿠룸입니다.
+ 앱으로 돌아가서 아래 인증 코드를 입력해주세요.
+ 해당 인증코드는 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));
}