Skip to content

[FEATURE] 메일 발송 로직 및 템플릿 이관 - #4

Merged
fervovita merged 5 commits into
devfrom
feat/#3-mail-sending
Jul 14, 2026
Merged

[FEATURE] 메일 발송 로직 및 템플릿 이관#4
fervovita merged 5 commits into
devfrom
feat/#3-mail-sending

Conversation

@fervovita

@fervovita fervovita commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

🚀 Related issue

Closes #3

#️⃣ Summary

  • RabbitMQ로 수신한 메시지를 메일로 발송하는 기능 구현 및 메일 템플릿 이관

🔧 Changes

  • RabbitMQ로 수신한 메시지를 알림 타입에 맞는 메일로 발송하는 로직 구현
  • 발송 실패 시 재시도 후 DLQ로 라우팅되도록 예외 처리
  • 로그에 남는 이메일 주소 마스킹 처리
  • 메일 템플릿 및 로고 이관

💬 Reviewer Notes

  • 리뷰어나 같이 작업하는 사람들에게 남길 코멘트

Summary by CodeRabbit

  • 새로운 기능

    • 외주 진행, 시안 제출·선택, 수정 요청, 환불 및 인증번호 등 다양한 상황에 대한 이메일 알림을 제공합니다.
    • 수신자와 외주 정보를 반영한 HTML 이메일과 대시보드 바로가기 링크를 지원합니다.
    • 이메일 주소는 로그에 마스킹되어 표시됩니다.
  • 개선 사항

    • 메일 발송에 필요한 환경 변수 누락을 배포 전에 확인합니다.
    • 메일 발송 실패를 명확히 처리하고, RabbitMQ 재시도 횟수를 조정했습니다.

@fervovita fervovita self-assigned this Jul 14, 2026
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@fervovita, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 14 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: cd6964ce-b514-4ec5-9d6f-b2d36780c3d5

📥 Commits

Reviewing files that changed from the base of the PR and between ce6ede3 and 17b18b0.

📒 Files selected for processing (7)
  • src/main/java/ditda/notification/mail/EmailSender.java
  • src/main/resources/templates/email/admin-payout-request.html
  • src/main/resources/templates/email/admin-refund-request.html
  • src/main/resources/templates/email/commission-shortfall-instructor.html
  • src/main/resources/templates/email/deposit-notification.html
  • src/main/resources/templates/email/first-draft-shortfall-instructor.html
  • src/main/resources/templates/email/first-draft-zero-instructor.html
📝 Walkthrough

Walkthrough

메일 환경 설정과 알림 유형 매핑을 추가하고, RabbitMQ 메시지를 Thymeleaf 기반 HTML 메일로 렌더링해 SMTP로 전송하는 기능을 구현했습니다. 외주 상태·관리자 알림·인증 코드용 이메일 템플릿도 추가했습니다.

Changes

메일 발송 기능

Layer / File(s) Summary
메일 계약 및 환경 설정
.env.example, scripts/deploy.sh, src/main/resources/application.yaml, src/test/resources/application-test.yaml, src/main/java/ditda/notification/mail/NotificationType.java
메일 환경 변수와 SMTP 설정, 필수 변수 검증, 알림 유형별 제목·템플릿 매핑을 추가하고 RabbitMQ 재시도 횟수를 변경했습니다.
메일 수신 및 전송 흐름
src/main/java/ditda/notification/mail/EmailSender.java, src/main/java/ditda/notification/mail/MailListener.java, src/main/java/ditda/notification/mail/MailMasker.java
수신 메시지의 유형과 변수를 사용해 Thymeleaf 본문과 CID 로고를 구성하고 메일을 전송하며, 로그 수신자를 마스킹합니다.
관리자 알림 템플릿
src/main/resources/templates/email/admin-*.html
정산 요청과 환불 요청 정보를 표시하는 관리자용 이메일 템플릿을 추가했습니다.
외주 상태 알림 템플릿
src/main/resources/templates/email/commission-*.html, src/main/resources/templates/email/final-*.html, src/main/resources/templates/email/deposit-notification.html, src/main/resources/templates/email/designer-signup-notification.html
매칭, 취소, 시안 제출, 최종 확정, 입금 확인, 디자이너 가입 검토 알림용 템플릿을 추가했습니다.
시안·수정·인증 템플릿
src/main/resources/templates/email/first-draft-*.html, src/main/resources/templates/email/revision-*.html, src/main/resources/templates/email/verification-code.html
1차 시안 상태, 수정 요청·제출, 이메일 인증 코드용 Thymeleaf 템플릿을 추가했습니다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MailListener
  participant NotificationType
  participant EmailSender
  participant SpringTemplateEngine
  participant JavaMailSender

  MailListener->>NotificationType: 메시지 유형 변환
  MailListener->>EmailSender: 수신자·유형·변수 전달
  EmailSender->>SpringTemplateEngine: 템플릿 렌더링
  EmailSender->>JavaMailSender: MIME 메일 전송
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 메일 발송 로직과 템플릿 이관이라는 핵심 변경을 간결하게 반영합니다.
Linked Issues check ✅ Passed 메일 발송 로직, 메시지 기반 발송, 템플릿 추가 및 설정 반영이 모두 요건과 일치합니다.
Out of Scope Changes check ✅ Passed 요약된 변경은 환경설정, 발송 코드, 템플릿 추가로만 보이며, 별도 무관한 변경은 보이지 않습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#3-mail-sending

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (4)
src/main/resources/templates/email/admin-payout-request.html (1)

89-92: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

환경별 Swagger URL 분리 고려 (선택 사항)

현재 Swagger URL이 운영 환경(https://api.ditda.kr...)으로 하드코딩되어 있습니다. 개발이나 스테이징 환경에서 발송된 메일을 확인할 때 운영 환경으로 잘못 연결되어 혼동을 줄 수 있습니다.

서버의 도메인을 변수로 주입받아 동적으로 URL을 구성하는 것을 고려해 보세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/templates/email/admin-payout-request.html` around lines 89
- 92, Update the Swagger link in the email template to use an injected
server-domain or environment-specific base URL instead of the hardcoded
production host, while preserving the existing Swagger path and link text.
src/main/resources/templates/email/first-draft-all-submitted-instructor.html (2)

34-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

환경(Environment)별 라우팅을 위한 URL 변수화 권장

이메일 템플릿 내에 도메인 URL이 하드코딩되어 있습니다. 개발(Dev)이나 테스트(Staging) 환경에서 발송된 이메일의 링크를 클릭할 경우에도 운영(Prod) 환경으로 강제 연결되는 문제가 발생할 수 있습니다. 서버 환경에 맞는 Base URL을 변수(예: th:href="@{${baseUrl} + '/instructor'}")로 주입받아 동적으로 구성하는 것을 권장합니다.

  • src/main/resources/templates/email/first-draft-all-submitted-instructor.html#L34-L38: 하드코딩된 https://ditda.kr/instructor를 변수를 활용한 동적 URL로 변경을 고려해 주세요.
  • src/main/resources/templates/email/first-draft-missed-designer.html#L14-L18: 하드코딩된 https://www.ditda.kr를 변수를 활용한 동적 URL로 변경을 고려해 주세요.
  • src/main/resources/templates/email/revision-submitted-instructor.html#L34-L38: 하드코딩된 https://ditda.kr/instructor를 변수를 활용한 동적 URL로 변경을 고려해 주세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/templates/email/first-draft-all-submitted-instructor.html`
around lines 34 - 38, Replace the hardcoded production links in
first-draft-all-submitted-instructor.html (lines 34-38),
first-draft-missed-designer.html (lines 14-18), and
revision-submitted-instructor.html (lines 34-38) with Thymeleaf URLs built from
the injected environment-specific baseUrl variable, preserving each template’s
existing destination path.

3-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

모바일 기기 호환성을 위한 뷰포트(Viewport) 메타 태그 누락

이메일 템플릿에 뷰포트 메타 태그가 누락되어 있어 모바일 이메일 클라이언트에서 내용이 지나치게 작게 표시되거나 화면 배율이 맞지 않을 수 있습니다. 모든 템플릿의 <head> 영역에 <meta name="viewport" content="width=device-width, initial-scale=1.0">를 추가하는 것을 권장합니다.

  • src/main/resources/templates/email/first-draft-all-submitted-instructor.html#L3-L5: <head> 내에 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 태그를 추가합니다.
  • src/main/resources/templates/email/first-draft-missed-designer.html#L3-L5: 동일하게 모바일 뷰포트 메타 태그를 추가합니다.
  • src/main/resources/templates/email/first-draft-rejected-designer.html#L3-L5: 동일하게 모바일 뷰포트 메타 태그를 추가합니다.
  • src/main/resources/templates/email/revision-submitted-instructor.html#L3-L5: 동일하게 모바일 뷰포트 메타 태그를 추가합니다.
  • src/main/resources/templates/email/verification-code.html#L3-L6: 동일하게 모바일 뷰포트 메타 태그를 추가합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/templates/email/first-draft-all-submitted-instructor.html`
around lines 3 - 5, 모든 이메일 템플릿의 <head> 영역에 모바일 뷰포트 메타 태그를 추가하세요:
src/main/resources/templates/email/first-draft-all-submitted-instructor.html
3-5, src/main/resources/templates/email/first-draft-missed-designer.html 3-5,
src/main/resources/templates/email/first-draft-rejected-designer.html 3-5,
src/main/resources/templates/email/revision-submitted-instructor.html 3-5,
src/main/resources/templates/email/verification-code.html 3-6. 각 파일의 기존 charset
메타 태그와 함께 동일한 viewport 설정을 배치하세요.
src/main/resources/templates/email/first-draft-selected-designer.html (1)

31-34: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

하드코딩된 프로덕션 URL을 환경 변수 기반으로 변경하는 것을 고려해 보세요.

세 곳의 템플릿 파일에서 https://ditda.kr과 같이 운영 환경의 도메인이 하드코딩되어 있습니다. 추후 로컬, 개발(dev), 스테이징 등 다양한 환경에서 원활하게 이메일 내 링크를 테스트할 수 있도록 백엔드에서 baseUrl 같은 변수를 주입받아 동적으로 사용하는 방식을 권장합니다.

  • src/main/resources/templates/email/first-draft-selected-designer.html#L31-L34: href="https://ditda.kr/designer" 경로 사용 중
  • src/main/resources/templates/email/first-draft-shortfall-instructor.html#L50-L53: href="https://ditda.kr/instructor" 경로 사용 중
  • src/main/resources/templates/email/revision-requested-designer.html#L34-L37: href="https://ditda.kr/designer" 경로 사용 중
💡 수정 예시 (타임리프 변수 활용)
<!-- Java 코드에서 variables.put("baseUrl", "https://ditda.kr"); 설정 후 -->
<a th:href="@{|${baseUrl}/designer|}"
   style="display: inline-block; padding: 12px 24px; background: `#874fff`; color: `#fff`; text-decoration: none; border-radius: 8px; font-weight: bold; font-size: 14px;">
    대시보드 바로가기
</a>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/templates/email/first-draft-selected-designer.html` around
lines 31 - 34, Replace the hardcoded https://ditda.kr links with an injected
baseUrl and construct each destination path dynamically. Update
first-draft-selected-designer.html:31-34 for /designer,
first-draft-shortfall-instructor.html:50-53 for /instructor, and
revision-requested-designer.html:34-37 for /designer; ensure the backend
populates baseUrl for every email template context.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/ditda/notification/mail/EmailSender.java`:
- Around line 57-61: Update renderTemplate to handle a null variables argument
before invoking variables.forEach; only populate the Context when variables is
non-null, while preserving templateEngine.process behavior for templates without
variables.

In `@src/main/resources/application.yaml`:
- Line 22: Update the spring.rabbitmq.listener.simple.retry configuration key
from max-retries to max-attempts while preserving the configured value of 2.

In `@src/main/resources/templates/email/admin-payout-request.html`:
- Around line 74-76: Update the formatInteger calls in
src/main/resources/templates/email/admin-payout-request.html at lines 74-76 and
82-84 to use minIntegerDigits 1 instead of 3, and update the call in
src/main/resources/templates/email/admin-refund-request.html at lines 42-44 to
use 1 instead of 0, preserving comma grouping and the existing 원 suffix.

In `@src/main/resources/templates/email/admin-refund-request.html`:
- Around line 36-39: Update the “마감 형태” section in admin-refund-request.html to
render the refund reason from the reason variable, matching the
notification-specific wording used by admin-payout-request.html. Remove the
hardcoded “지원자 0명” and “정원 미달” branches while preserving the existing styling
and layout.

In `@src/main/resources/templates/email/commission-shortfall-instructor.html`:
- Around line 44-45: 금액 포매팅의 최소 정수 자릿수를 1로 통일하세요.
src/main/resources/templates/email/commission-shortfall-instructor.html 44-45의
refundAmount 포매팅을 3에서 1로 변경하고,
src/main/resources/templates/email/deposit-notification.html 37-37의 amount 포매팅을
0에서 1로 변경하세요.

---

Nitpick comments:
In `@src/main/resources/templates/email/admin-payout-request.html`:
- Around line 89-92: Update the Swagger link in the email template to use an
injected server-domain or environment-specific base URL instead of the hardcoded
production host, while preserving the existing Swagger path and link text.

In
`@src/main/resources/templates/email/first-draft-all-submitted-instructor.html`:
- Around line 34-38: Replace the hardcoded production links in
first-draft-all-submitted-instructor.html (lines 34-38),
first-draft-missed-designer.html (lines 14-18), and
revision-submitted-instructor.html (lines 34-38) with Thymeleaf URLs built from
the injected environment-specific baseUrl variable, preserving each template’s
existing destination path.
- Around line 3-5: 모든 이메일 템플릿의 <head> 영역에 모바일 뷰포트 메타 태그를 추가하세요:
src/main/resources/templates/email/first-draft-all-submitted-instructor.html
3-5, src/main/resources/templates/email/first-draft-missed-designer.html 3-5,
src/main/resources/templates/email/first-draft-rejected-designer.html 3-5,
src/main/resources/templates/email/revision-submitted-instructor.html 3-5,
src/main/resources/templates/email/verification-code.html 3-6. 각 파일의 기존 charset
메타 태그와 함께 동일한 viewport 설정을 배치하세요.

In `@src/main/resources/templates/email/first-draft-selected-designer.html`:
- Around line 31-34: Replace the hardcoded https://ditda.kr links with an
injected baseUrl and construct each destination path dynamically. Update
first-draft-selected-designer.html:31-34 for /designer,
first-draft-shortfall-instructor.html:50-53 for /instructor, and
revision-requested-designer.html:34-37 for /designer; ensure the backend
populates baseUrl for every email template context.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 461fccae-124e-4b6b-8e90-4004ff273d1f

📥 Commits

Reviewing files that changed from the base of the PR and between 660fa3f and ce6ede3.

⛔ Files ignored due to path filters (1)
  • src/main/resources/email-images/logo.png is excluded by !**/*.png
📒 Files selected for processing (29)
  • .env.example
  • scripts/deploy.sh
  • src/main/java/ditda/notification/mail/EmailSender.java
  • src/main/java/ditda/notification/mail/MailListener.java
  • src/main/java/ditda/notification/mail/MailMasker.java
  • src/main/java/ditda/notification/mail/NotificationType.java
  • src/main/resources/application.yaml
  • src/main/resources/templates/email/admin-payout-request.html
  • src/main/resources/templates/email/admin-refund-request.html
  • src/main/resources/templates/email/commission-cancelled.html
  • src/main/resources/templates/email/commission-finalized-designer.html
  • src/main/resources/templates/email/commission-finalized-instructor.html
  • src/main/resources/templates/email/commission-matched-designer.html
  • src/main/resources/templates/email/commission-matched-instructor.html
  • src/main/resources/templates/email/commission-shortfall-instructor.html
  • src/main/resources/templates/email/deposit-notification.html
  • src/main/resources/templates/email/designer-signup-notification.html
  • src/main/resources/templates/email/final-cancelled-designer.html
  • src/main/resources/templates/email/final-cancelled-instructor.html
  • src/main/resources/templates/email/first-draft-all-submitted-instructor.html
  • src/main/resources/templates/email/first-draft-missed-designer.html
  • src/main/resources/templates/email/first-draft-rejected-designer.html
  • src/main/resources/templates/email/first-draft-selected-designer.html
  • src/main/resources/templates/email/first-draft-shortfall-instructor.html
  • src/main/resources/templates/email/first-draft-zero-instructor.html
  • src/main/resources/templates/email/revision-requested-designer.html
  • src/main/resources/templates/email/revision-submitted-instructor.html
  • src/main/resources/templates/email/verification-code.html
  • src/test/resources/application-test.yaml

Comment thread src/main/java/ditda/notification/mail/EmailSender.java
Comment thread src/main/resources/application.yaml
Comment thread src/main/resources/templates/email/admin-payout-request.html
Comment thread src/main/resources/templates/email/admin-refund-request.html
Comment thread src/main/resources/templates/email/commission-shortfall-instructor.html Outdated
@fervovita
fervovita merged commit bc4f00b into dev Jul 14, 2026
2 checks passed
@fervovita
fervovita deleted the feat/#3-mail-sending branch July 14, 2026 17:38
@fervovita fervovita mentioned this pull request Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] 메일 발송 로직 및 템플릿 이관

1 participant