Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions src/main/kotlin/com/wafflestudio/team2server/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package com.wafflestudio.team2server

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.scheduling.annotation.EnableAsync
import org.springframework.scheduling.annotation.EnableScheduling

@EnableScheduling
@EnableAsync
@SpringBootApplication
class Application

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.wafflestudio.team2server.article.model.ArticleCreatedEvent
import com.wafflestudio.team2server.email.service.EmailService
import com.wafflestudio.team2server.email.service.MailService
import com.wafflestudio.team2server.inbox.service.InboxService
import org.slf4j.LoggerFactory
import org.springframework.context.event.EventListener
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional
Expand All @@ -14,17 +15,26 @@ class ArticleEventListener(
private val emailService: EmailService,
private val mailService: MailService,
) {
private val logger = LoggerFactory.getLogger(ArticleEventListener::class.java)

@EventListener
@Transactional
fun handleArticleCreated(event: ArticleCreatedEvent) {
val article = event.article
logger.info("게시글 생성 이벤트 수신: 게시글ID={}, 제목={}, 게시판ID={}", article.id, article.title, article.boardId)

val recipients = emailService.getSubscriberEmails(article.boardId)
logger.info("이메일 구독자 조회 완료: 게시판ID={}, 구독자 수={}", article.boardId, recipients.size)

inboxService.createInboxesForBoardSubscribers(article)

recipients.forEach { email ->
mailService.sendArticleNotification(email, article)
if (recipients.isEmpty()) {
logger.debug("이메일 발송할 구독자가 없습니다: 게시판ID={}", article.boardId)
} else {
logger.info("이메일 발송 시작: 게시판ID={}, 구독자 수={}", article.boardId, recipients.size)
recipients.forEach { email ->
mailService.sendArticleNotification(email, article)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.wafflestudio.team2server.email.service

import com.wafflestudio.team2server.article.model.Article
import jakarta.annotation.PostConstruct
import jakarta.mail.internet.MimeMessage
import org.slf4j.LoggerFactory
import org.springframework.core.env.Environment
import org.springframework.mail.javamail.JavaMailSender
import org.springframework.mail.javamail.MimeMessageHelper
import org.springframework.scheduling.annotation.Async
Expand All @@ -12,12 +15,36 @@ import java.time.format.DateTimeFormatter
@Service
class MailService(
private val javaMailSender: JavaMailSender,
private val environment: Environment,
) {
private val logger = LoggerFactory.getLogger(MailService::class.java)

@PostConstruct
fun logMailConfiguration() {
val host = environment.getProperty("spring.mail.host") ?: "not set"
val port = environment.getProperty("spring.mail.port") ?: "not set"
val username = environment.getProperty("spring.mail.username") ?: "not set"
val hasPassword = !environment.getProperty("spring.mail.password").isNullOrBlank()

logger.info(
"이메일 설정 초기화: host={}, port={}, username={}, password={}",
host,
port,
username,
if (hasPassword) "설정됨" else "설정되지 않음",
)

if (!hasPassword || username == "not set") {
logger.warn("이메일 설정이 완전하지 않습니다. MAIL_USERNAME과 MAIL_PASSWORD 환경 변수를 확인하세요.")
}
}

@Async
fun sendArticleNotification(
email: String,
article: Article,
) {
logger.info("이메일 발송 시작: 수신자={}, 제목={}, 게시글ID={}", email, article.title, article.id)
val subject = "[새 글 알림] ${article.title}"
val htmlBody = createHtmlBody(article)

Expand All @@ -30,15 +57,27 @@ class MailService(
htmlBody: String,
) {
try {
logger.debug("이메일 메시지 생성 시작: 수신자={}, 제목={}", to, subject)
val message: MimeMessage = javaMailSender.createMimeMessage()
val helper = MimeMessageHelper(message, true, "UTF-8")

helper.setTo(to)
helper.setSubject(subject)
helper.setText(htmlBody, true)

logger.debug("이메일 전송 시도: 수신자={}, 제목={}", to, subject)
javaMailSender.send(message)
logger.info("이메일 발송 성공: 수신자={}, 제목={}", to, subject)
} catch (e: jakarta.mail.AuthenticationFailedException) {
logger.error("이메일 인증 실패: 수신자={}, 제목={}, 오류={}", to, subject, e.message, e)
} catch (e: jakarta.mail.MessagingException) {
logger.error("이메일 메시징 오류: 수신자={}, 제목={}, 오류={}", to, subject, e.message, e)
} catch (e: java.net.SocketTimeoutException) {
logger.error("이메일 전송 타임아웃: 수신자={}, 제목={}, 오류={}", to, subject, e.message, e)
} catch (e: java.net.ConnectException) {
logger.error("이메일 서버 연결 실패: 수신자={}, 제목={}, 오류={}", to, subject, e.message, e)
} catch (e: Exception) {
logger.error("이메일 발송 실패: 수신자={}, 제목={}, 오류타입={}, 오류={}", to, subject, e.javaClass.simpleName, e.message, e)
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ spring:
starttls:
enable: true
required: true
connectiontimeout: 5000
timeout: 5000
writetimeout: 5000
connectiontimeout: 10000
timeout: 10000
writetimeout: 10000

# Google OAuth2
security:
Expand Down