diff --git a/back/.env.default b/back/.env.default index 56fb874d..08978a25 100644 --- a/back/.env.default +++ b/back/.env.default @@ -1,3 +1,5 @@ CUSTOM__JWT__SECRET_KEY=NEED_TO_SET DB_USERNAME=NEED_TO_SET DB_PASSWORD=NEED_TO_SET +MAIL_USERNAME=NEED_TO_SET +MAIL_PASSWORD=NEED_TO_SET diff --git a/back/build.gradle.kts b/back/build.gradle.kts index 82c3392e..728deb73 100644 --- a/back/build.gradle.kts +++ b/back/build.gradle.kts @@ -39,6 +39,7 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-web") implementation ("org.springframework.boot:spring-boot-starter-data-redis") + implementation("org.springframework.boot:spring-boot-starter-mail") // QueryDSL implementation("com.querydsl:querydsl-jpa:5.0.0:jakarta") diff --git a/back/src/main/java/com/back/domain/member/member/email/EmailService.java b/back/src/main/java/com/back/domain/member/member/email/EmailService.java new file mode 100644 index 00000000..71ec02a7 --- /dev/null +++ b/back/src/main/java/com/back/domain/member/member/email/EmailService.java @@ -0,0 +1,116 @@ +package com.back.domain.member.member.email; + +import com.back.global.exception.ServiceException; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Service; + +import java.io.UnsupportedEncodingException; + +@Slf4j +@Service +@RequiredArgsConstructor +public class EmailService { + private final JavaMailSender mailSender; + + /** + * 간단한 텍스트 이메일 발송 + */ + public void sendSimpleEmail(String to, String subject, String text) { + try { + MimeMessage message = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); + + helper.setFrom("snake20011600@gmail.com", "JobMate"); + helper.setTo(to); + helper.setSubject(subject); + helper.setText(text, false); // false = plain text + + mailSender.send(message); + log.info("텍스트 이메일 발송 성공: {}", to); + } catch (MessagingException | UnsupportedEncodingException e) { + log.error("텍스트 이메일 발송 실패: {}", to, e); + throw new ServiceException("500-1", "텍스트 이메일 발송에 실패했습니다."); + } + } + + /** + * HTML 이메일 발송 + */ + public void sendHtmlEmail(String to, String subject, String htmlContent) { + try { + MimeMessage message = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); + + helper.setFrom("snake20011600@gmail.com", "JobMate"); + helper.setTo(to); + helper.setSubject(subject); + helper.setText(htmlContent, true); // true = HTML + + mailSender.send(message); + log.info("HTML 이메일 발송 성공: {}", to); + } catch (MessagingException | UnsupportedEncodingException e) { + log.error("HTML 이메일 발송 실패: {}", to, e); + throw new ServiceException("500-2", "HTML 이메일 발송에 실패했습니다."); + } + } + + /** + * 인증번호 이메일 발송 (멘토 회원가입용) + */ + public void sendVerificationCode(String to, String verificationCode) { + String subject = "[FiveLogic] 멘토 회원가입 인증번호"; + String htmlContent = buildVerificationEmailHtml(verificationCode); + sendHtmlEmail(to, subject, htmlContent); + } + + /** + * 인증번호 이메일 HTML 템플릿 + */ + private String buildVerificationEmailHtml(String verificationCode) { + return """ + + + + + + + +
+
+

JobMate 멘토 회원가입

+
+
+

인증번호 확인

+

안녕하세요. FiveLogic입니다.

+

멘토 회원가입을 위한 인증번호를 안내드립니다.

+

아래 인증번호를 입력하여 회원가입을 완료해주세요.

+ +
+
%s
+
+ +

※ 인증번호는 5분간 유효합니다.

+

본인이 요청하지 않은 경우, 이 메일을 무시하셔도 됩니다.

+
+ +
+ + + """.formatted(verificationCode); + } +} diff --git a/back/src/main/java/com/back/domain/member/member/verification/EmailVerificationService.java b/back/src/main/java/com/back/domain/member/member/verification/EmailVerificationService.java index ce98c1d4..874e3203 100644 --- a/back/src/main/java/com/back/domain/member/member/verification/EmailVerificationService.java +++ b/back/src/main/java/com/back/domain/member/member/verification/EmailVerificationService.java @@ -1,5 +1,6 @@ package com.back.domain.member.member.verification; +import com.back.domain.member.member.email.EmailService; import com.back.global.exception.ServiceException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -14,6 +15,7 @@ @Slf4j public class EmailVerificationService { private final VerificationCodeStore codeStore; + private final EmailService emailService; private static final Duration CODE_TTL = Duration.ofMinutes(5); private static final SecureRandom random = new SecureRandom(); @@ -24,8 +26,9 @@ public String generateAndSendCode(String email) { // 저장 codeStore.saveCode(email, code, CODE_TTL); - // TODO: 실제 이메일 발송 로직 추가 (JavaMailSender) - log.info("Generated verification code for {}: {}", email, code); + // 이메일 발송 + emailService.sendVerificationCode(email, code); + log.info("Generated and sent verification code for {}: {}", email, code); return code; // 테스트용으로 반환 (실제로는 이메일로만 전송) } diff --git a/back/src/main/resources/application.yml b/back/src/main/resources/application.yml index d4c25cf4..d684b274 100644 --- a/back/src/main/resources/application.yml +++ b/back/src/main/resources/application.yml @@ -42,6 +42,21 @@ spring: use_sql_comments: true default_batch_fetch_size: 100 open-in-view: false + mail: + host: smtp.gmail.com + port: 587 + username: ${MAIL_USERNAME} + password: ${MAIL_PASSWORD} + properties: + mail: + smtp: + auth: true + starttls: + enable: true + required: true + connectiontimeout: 5000 + timeout: 5000 + writetimeout: 5000 springdoc: #Swagger ?? default-produces-media-type: application/json;charset=UTF-8