이메일 서비스 (Email Service)
문서 정보
- 작성일: 2026-03-29
- 최종 업데이트: 2026-03-29
- 버전: v1.0.0
TL;DR
회원가입 환영 이메일과 Trial 만료 알림 이메일을 자동으로 발송하는 시스템입니다. 현재 Resend를 사용하며, 향후 AWS SES로 전환 예정입니다.
목차
핵심 개념
| 용어 | 설명 |
|---|---|
| Resend | 트랜잭셔널 이메일 발송 서비스 (현재 사용 중) |
| AWS SES | Amazon Simple Email Service (V2 전환 예정) |
| best-effort | 이메일 발송 실패 시 로그만 기록하고 핵심 로직에 영향 없음 |
| shouldShowTrialExpiredNotice | Trial 만료 팝업 표시 여부 플래그 |
발송되는 이메일
1. 회원가입 환영 이메일
| 항목 | 내용 |
|---|---|
| 트리거 | 회원가입 완료 시 |
| 발신자 | Spoclip <noreply@spoclip.ai> |
| 제목 | [Spoclip] 가입을 환영합니다! 14일 PRO 체험을 시작하세요 |
| 내용 | PRO 체험 혜택 안내 (4K UHD, 콕 디바이스 연동, 광고 제거 등) |
| CTA | 앱에서 확인하기 → https://spoclip.ai |
| 발송 방식 | best-effort (실패해도 회원가입 성공) |
2. Trial 만료 이메일
| 항목 | 내용 |
|---|---|
| 트리거 | Trial 만료 스케줄러 (매일 03:00 KST) |
| 발신자 | Spoclip <noreply@spoclip.ai> |
| 제목 | [Spoclip] 체험 기간이 만료되었어요 |
| 내용 | 잃어버린 혜택 목록 + 멤버십 가입 유도 |
| CTA | 멤버십 시작하기 → https://spoclip.ai/ticket |
| 발송 방식 | best-effort (실패 시 로그 기록) |
아키텍처
┌──────────────────────────────────────────────────┐
│ 소비자 코드 │
│ │
│ MemberAuthService ExpireEntitlementScheduler
│ (회원가입 시) (Trial 만료 시) │
└──────┬──────────────────────────┬─────────────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────────┐
│ ResendInfraService │
│ (@Global, Injection Token) │
│ │
│ sendEmail({ to, subject, html }) │
└───── ─────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ Resend API │
│ (spoclip.ai 도메인 인증) │
└──────────────────────────────────────────────────┘
모듈 구조
src/infra/resend/
├── constants/resend-infra.constant.ts # Injection Token
├── interfaces/resend-infra.service.interface.ts
├── types/resend-infra.type.ts # ISendEmailParams, ISendEmailResult
├── templates/
│ ├── signup-welcome.template.ts # 회원가입 환영 HTML
│ └── trial-expired.template.ts # Trial 만료 HTML
├── resend-infra.service.ts # Resend API 호출
├── resend-infra.module.ts # @Global() 모듈
└── index.ts
환경 설정
# .env
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxx
RESEND_FROM_EMAIL=Spoclip <noreply@spoclip.ai>
| 변수 | 설명 |
|---|---|
RESEND_API_KEY | Resend API 키 |
RESEND_FROM_EMAIL | 발신자 이름 + 이메일 |
도메인 인증
spoclip.ai 도메인이 Resend에 인증되어 있습니다 (Cloudflare DNS에 SPF/DKIM 레코드 추가).
이메일 템플릿
두 템플릿 모두 앱 내 UI 디자인과 통일된 다크 테마를 적용합니다.
| 요소 | 값 |
|---|---|
| 배경색 | #1a1a1a |
| 카드 배경 | #2a2a2e |
| CTA 버튼 | #6B8AFF |
| 혜택 박스 | #333338 |
| 카드 라운딩 | 20px |
템플릿은 순수 HTML 함수로 구현되어 있어 외부 의존성이 없습니다.
Trial 만료 팝업 연동
이메일과 별 도로, 앱 진입 시 Trial 만료 팝업을 표시하는 기능이 함께 구현되어 있습니다.
클라이언트 Flow
앱 진입 → GET /users/me
↓
shouldShowTrialExpiredNotice === true?
↓ YES
팝업 표시
↓
PATCH /marketing-policy/trial/expired-notice (204)
↓
다음 진입 시 shouldShowTrialExpiredNotice === false
API 응답 예시
// 팝업 표시 필요
{
"entitlement": {
"activePlan": "FREE",
"trial": null,
"subscription": null,
"shouldShowTrialExpiredNotice": true
}
}
// 팝업 불필요 (이미 확인 또는 Trial 없음)
{
"entitlement": {
"activePlan": "FREE",
"trial": null,
"subscription": null,
"shouldShowTrialExpiredNotice": false
}
}
설계 포인트
trial객체는 Trial ACTIVE 상태일 때만 반환- 만료된 Trial 정보는 팝업에 불필요하므로
trial: null - 팝업 확인 완료 시 DB 쿼리 자체를 스킵하여 비용 절감
V2 SES 전환 계획
Resend 무료 한도(3,000통/월)를 초과할 경우 AWS SES로 전환 예정입니다.
| 항목 | 현재 (V1) | 예정 (V2) |
|---|---|---|
| Provider | Resend | AWS SES |
| 무료 한도 | 3,000통/월 | 62,000통/월 (EC2) |
| 인증 방식 | API Key | IAM Role |
| 도메인 | spoclip.ai (Resend 인증) | spoclip.ai (SES 인증 필요) |
전환 전략
- 범용
IEmailInfraService인터페이스로 리팩토링 EMAIL_PROVIDER=ses|resend환경변수로 런타임 provider 선택- 개발 환경은 Resend 유지, 프로덕션만 SES
- 상세 계획:
.omc/plans/v2-resend-to-ses-migration.md
선행 조건
- AWS SES sandbox 해제 승인
- SES에서 spoclip.ai 도메인 DKIM/SPF 인증
FAQ
Q: 이메일 발송이 실패하면 어떻게 되나요?
A: 모든 이메일 발송은 best-effort입니다. 실패해도 회원가입이나 Trial 만료 처리에 영향 없으며, 서버 로그에 경고만 기록됩니다.
Q: 사용자가 이메일을 등록하지 않았으면?
A: 소셜 로그인 시 이메일이 없는 경우(userInfo.email = null) 이메일 발송을 건너뜁니다. DB에 저장된 이메일은 암호화되어 있어 발송 시 복호화 후 사용합니다.
Q: Resend 무료 한도가 초과되면?
A: Resend는 한도 초과 시 발송이 차단됩니다. 에러 로그가 기록되며, SES 전환(V2)을 통해 해결 예정입니다.