Claude Code로 기사를 만들어 S3에 올리면, 매주 정해진 시각에 SES가 구독자 전원에게 보낸다. 서버는 한 대도 켜두지 않는다.
notes/2026-W38/에 쌓는다.-test 파일로 내 주소에 먼저 발송해 Gmail·네이버·아이폰에서 확인.s3://…/issues/2026-09-21.html로 업로드. 여기까지가 내 일.pending 상태로 저장하고 SES로 확인 메일 발송.active로 전환 (더블 옵트인).unsubscribed로 전환. 같은 Lambda가 처리.issues/에서 오늘 날짜 파일을 찾는다. 없으면 나에게 알림 후 종료.active 구독자를 읽고, 구독자별 수신거부 URL을 치환.sent#2026-09-21 마커를 기록해 중복 발송을 막는다.| 역할 | 서비스 | 왜 이걸로 | 월 비용 (구독자 1만 명 기준) |
|---|---|---|---|
| 구독 페이지 | S3 + CloudFront | GitHub Pages와 같은 정적 호스팅. 1TB 전송·1천만 요청 상시 무료 | $0 |
| 구독·수신거부 API | API Gateway (HTTP) + Lambda | 요청 있을 때만 실행. 월 100만 요청 무료 | $0 |
| 구독자 저장 | DynamoDB (on-demand) | 25GB 상시 무료. 서버 없음, 관리 없음. RDS는 유휴 비용이 나와 부적합 | $0 |
| 기사 보관 | S3 (issues/) | HTML 파일 수백 개여도 GB 미만 | $0 |
| 주간 트리거 | EventBridge Scheduler | cron 한 줄 | $0 |
| 발송 | SES | 1,000통당 $0.10. 43,333통/월 | $4.33 |
| 바운스·신고 처리 | SNS + Lambda | SES 계정 정지를 막는 필수 장치 | $0 |
| 도메인·DNS·SSL | Route 53 + ACM | 호스팅 존 $0.50/월. 인증서 무료. 도메인 등록비 연 $13~15 별도 | $0.50 |
| 알람 | CloudWatch | 10개 알람 무료 | $0 |
| 합계 | 구독자 1,000명이면 $1 미만, 5만 명이면 약 $25 | ≈ $5 + 도메인 연 $15 |
신규 계정은 6개월간 최대 $200 크레딧을 받으므로 첫 반년은 실질 0원에 가깝습니다. 2023년 이전의 "SES 월 6.2만 통 무료"는 폐지되었으니 옛 글은 참고만 하세요.
구독자 수와 트래픽을 바꿔 보면서 통당·방문당 비용이 어떻게 비례하는지 확인할 수 있습니다. SES는 HTML 본문 크기와 무관하게 통 수로만 과금되고, 본문 안 이미지는 구독자가 메일을 열 때 CloudFront 트래픽으로 잡힙니다.
| 항목 | 산정 근거 | 월 비용 |
|---|
월 트래픽: 이메일 이미지 — + 홈페이지 — = — · 요청 —
| 구독자 | 월 발송 통수 | 월 총비용 ($) | 월 총비용 (원) | 1통당 | 구독자 1명당 월 |
|---|
단가는 2026년 9월 서울 리전 공개 요금 기준: SES $0.10/천 통 · CloudFront $0.12/GB, $0.012/만 요청 · Lambda $0.20/백만 요청 + $0.0000167/GB-초 · API Gateway $1.20/백만 요청 · DynamoDB 쓰기 $1.43/백만, 읽기 $0.29/백만 · CloudWatch Logs $0.76/GB. 발송 Lambda는 통당 60ms·512MB로 가정. 12개월 한정 무료는 제외했고, DynamoDB 온디맨드 무료 요청 구간은 계정 조건에 따라 다를 수 있습니다.
홈페이지와 이메일 주소에 도메인을 각각 사야 한다고 생각하셨는데, 도메인 하나로 둘 다 처리됩니다. 같은 Route 53 호스팅 존에 레코드만 나눠 등록하면 됩니다.
mydomain.com → CloudFront (홈페이지)
api.mydomain.com → API Gateway (구독 API)
mail.mydomain.com → SES 발송 도메인 ([email protected])
발송은 서브도메인으로 분리해 두는 걸 권합니다. 만약 스팸 신고가 쌓여 발송 도메인 평판이 나빠져도 홈페이지 도메인은 영향을 받지 않습니다. 회신 받을 곳은 Reply-To에 기존 Gmail을 넣으면 비용 0입니다.
이메일 주소만 저장한다고 하셨지만, 상태와 토큰 두 가지는 함께 있어야 수신거부·더블 옵트인·바운스 처리가 됩니다. 테이블은 하나로 충분합니다.
테이블: newsletter (파티션 키 pk, 정렬 키 sk) pk sk 속성 sub#[email protected] meta status=active | pending | unsubscribed | bounced token=8f3a…(수신거부·확인용 랜덤 값) created_at, confirmed_at sent#2026-09-21 meta count=10432, finished_at ← 중복 발송 방지 마커 GSI: status-index (status) → 발송 Lambda가 active만 빠르게 조회
신규 계정은 인증된 주소로만 발송됩니다. 콘솔에서 프로덕션 전환을 요청하면 1~3 영업일 소요. 용도와 수신거부 처리 방식을 적어 제출하세요.
SES가 알려주는 DNS 레코드를 Route 53에 등록. 이게 없으면 Gmail·네이버가 스팸함으로 보냅니다.
확인 메일을 거쳐야 active가 되게 합니다. 오타 주소·봇 가입으로 바운스율이 오르는 걸 막습니다.
모든 메일 하단에 원클릭 수신거부 링크, 발신자 이름·주소·연락처를 넣습니다. 정보통신망법 요건이자 SES 이용 조건입니다. List-Unsubscribe 헤더도 함께.
SES → SNS → Lambda로 해당 주소를 즉시 비활성화. 바운스율 5%, 신고율 0.1%를 넘으면 SES가 발송을 정지시킵니다.
이메일을 수집하는 순간 필요합니다. 수집 항목(이메일), 목적(뉴스레터 발송), 보관 기간, 위탁(AWS) 정도를 적은 정적 페이지 하나.
실제 구독자에게 나가기 전에 내 주소로만 보내는 경로. 발송 Lambda에 dry_run 인자 하나로 해결됩니다.
CloudWatch Billing Alarm을 $5에 하나 걸어두세요. 실수로 무한 루프가 돌아도 메일로 먼저 알게 됩니다.
폭 600px, 테이블 레이아웃, CSS 인라인, 이미지는 첨부 대신 S3/CloudFront URL. MJML로 쓰고 컴파일하면 이 규칙이 자동으로 지켜집니다.
SES 기본 한도는 초당 14통 안팎. 구독자 5만 명을 넘으면 Lambda 15분 제한에 걸리므로 그때 SQS 큐를 앞에 두고 나눠 보냅니다. 처음엔 필요 없습니다.
로컬 저장소 하나에 노트·템플릿·발행물을 함께 두고, Claude Code가 빌드와 업로드까지 맡게 하면 매주 명령 한 줄로 끝납니다.
newsletter/
├── notes/
│ └── 2026-W38/ ← 주중에 Claude 앱으로 받은 요약을 여기에 저장
│ ├── mon-ai-chips.md
│ └── wed-fed-rate.md
├── templates/
│ └── issue.mjml ← 헤더·푸터·{{unsubscribe_url}} 자리 고정
├── dist/
│ └── 2026-09-21.html ← 빌드 결과물
├── scripts/
│ ├── build.sh ← mjml 컴파일 + 인라인 CSS 검증
│ └── publish.sh ← aws s3 cp dist/2026-09-21.html s3://…/issues/
└── CLAUDE.md ← "notes/현재주차를 읽어 issue.mjml로 기사 작성, 톤·길이 규칙…"
매주 하는 일: claude → "이번 주 기사 만들어서 테스트 발송해줘" → 확인 → "발행해"
Claude 앱(remote)에서 던진 요약은 Claude Code가 접근할 수 있는 곳에 남아야 합니다. 가장 단순한 방법은 노트를 GitHub 저장소에 커밋하는 것이고, 그러면 git push에 GitHub Actions를 붙여 S3 업로드까지 자동화할 수도 있습니다.
api.mydomain.com 연결. curl로 먼저 검증.mydomain.com 연결. 폼이 API를 호출하는지 확인.dry_run으로 한 번, 실제 스케줄로 한 번.