Add 5 more runbooks
- aws-ses-setup.md: AWS SES email configuration - anvil-ses-final-setup.md: Anvil SES final setup - n8n-setup-guide.md: n8n workflow automation - gitea-setup.md: Gitea server installation - cloudflare-vault-integration.md: Cloudflare + Vault integration Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
271
aws-ses-setup.md
Normal file
271
aws-ses-setup.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# AWS SES 메일 발송 설정 가이드
|
||||
|
||||
> 작성일: 2026-01-12
|
||||
> 리전: ap-northeast-2 (서울)
|
||||
|
||||
## 개요
|
||||
|
||||
AWS SES(Simple Email Service)를 사용하여 서버에서 메일을 발송하기 위한 설정 가이드입니다.
|
||||
|
||||
---
|
||||
|
||||
## 계정 상태
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|-----|
|
||||
| 리전 | ap-northeast-2 (서울) |
|
||||
| 모드 | **프로덕션** (샌드박스 해제됨) |
|
||||
| 24시간 발송 한도 | 50,000통 |
|
||||
| 초당 발송률 | 14통/초 |
|
||||
|
||||
---
|
||||
|
||||
## 인증된 도메인
|
||||
|
||||
| 도메인 | 도메인 인증 | DKIM |
|
||||
|--------|------------|------|
|
||||
| `anvil.it.com` | ✅ Success | ✅ Success |
|
||||
| `ironclad.it.com` | ✅ Success | ✅ Success |
|
||||
|
||||
### 사용 가능한 발신자 주소
|
||||
|
||||
```
|
||||
*@anvil.it.com (예: noreply@anvil.it.com, support@anvil.it.com)
|
||||
*@ironclad.it.com (예: noreply@ironclad.it.com, admin@ironclad.it.com)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DNS 설정 (Cloudflare)
|
||||
|
||||
### anvil.it.com
|
||||
|
||||
**TXT 레코드 (도메인 소유권 확인)**
|
||||
| Type | Name | Content |
|
||||
|------|------|---------|
|
||||
| TXT | `_amazonses.anvil.it.com` | `0cuw9v32N+aeFiNlTh2Poxglgzf3BlmFRjVOjeLEdy4=` |
|
||||
|
||||
**CNAME 레코드 (DKIM)**
|
||||
| Type | Name | Target |
|
||||
|------|------|--------|
|
||||
| CNAME | `dgcehnldehfmfgpvrrbc6drwasiibhnp._domainkey` | `dgcehnldehfmfgpvrrbc6drwasiibhnp.dkim.amazonses.com` |
|
||||
| CNAME | `spopdscdt2sxngqzl5ir66k3ed6og7ut._domainkey` | `spopdscdt2sxngqzl5ir66k3ed6og7ut.dkim.amazonses.com` |
|
||||
| CNAME | `55l5wnmktvacgyfpt6sovcgb2rqexrpy._domainkey` | `55l5wnmktvacgyfpt6sovcgb2rqexrpy.dkim.amazonses.com` |
|
||||
|
||||
### ironclad.it.com
|
||||
|
||||
**TXT 레코드 (도메인 소유권 확인)**
|
||||
| Type | Name | Content |
|
||||
|------|------|---------|
|
||||
| TXT | `_amazonses.ironclad.it.com` | `C+RMHyLd/U2H5WSCu8L2avRn8NmuwEll0xxYjTyvoEY=` |
|
||||
|
||||
**CNAME 레코드 (DKIM)**
|
||||
| Type | Name | Target |
|
||||
|------|------|--------|
|
||||
| CNAME | `5sycmzu364y2rgefnqaloptgodymasct._domainkey` | `5sycmzu364y2rgefnqaloptgodymasct.dkim.amazonses.com` |
|
||||
| CNAME | `qm7d7qgkdikpcbrbgo7bmgqfmuulrbah._domainkey` | `qm7d7qgkdikpcbrbgo7bmgqfmuulrbah.dkim.amazonses.com` |
|
||||
| CNAME | `tu6oey5tktoqub753cxpayhhwrlzcskk._domainkey` | `tu6oey5tktoqub753cxpayhhwrlzcskk.dkim.amazonses.com` |
|
||||
|
||||
---
|
||||
|
||||
## IAM 권한 설정
|
||||
|
||||
### 최소 권한 정책 (권장)
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "SESSendEmail",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ses:SendEmail",
|
||||
"ses:SendRawEmail"
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 특정 발신자 제한 정책
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "SESSendFromVerified",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ses:SendEmail",
|
||||
"ses:SendRawEmail"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:ses:ap-northeast-2:*:identity/anvil.it.com",
|
||||
"arn:aws:ses:ap-northeast-2:*:identity/ironclad.it.com"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 사용 방법
|
||||
|
||||
### AWS CLI
|
||||
|
||||
```bash
|
||||
aws ses send-email \
|
||||
--from "noreply@anvil.it.com" \
|
||||
--to "recipient@example.com" \
|
||||
--subject "메일 제목" \
|
||||
--text "메일 본문" \
|
||||
--region ap-northeast-2
|
||||
```
|
||||
|
||||
### Python (boto3)
|
||||
|
||||
```python
|
||||
import boto3
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
def send_email(to_email: str, subject: str, body: str, sender: str = "noreply@anvil.it.com"):
|
||||
client = boto3.client('ses', region_name='ap-northeast-2')
|
||||
|
||||
try:
|
||||
response = client.send_email(
|
||||
Source=sender,
|
||||
Destination={'ToAddresses': [to_email]},
|
||||
Message={
|
||||
'Subject': {'Data': subject, 'Charset': 'UTF-8'},
|
||||
'Body': {
|
||||
'Text': {'Data': body, 'Charset': 'UTF-8'},
|
||||
# HTML 본문 사용 시:
|
||||
# 'Html': {'Data': '<h1>Hello</h1>', 'Charset': 'UTF-8'}
|
||||
}
|
||||
}
|
||||
)
|
||||
print(f"발송 완료: {response['MessageId']}")
|
||||
return response
|
||||
except ClientError as e:
|
||||
print(f"발송 실패: {e.response['Error']['Message']}")
|
||||
raise
|
||||
|
||||
# 사용 예시
|
||||
send_email(
|
||||
to_email='recipient@example.com',
|
||||
subject='테스트 메일',
|
||||
body='안녕하세요!'
|
||||
)
|
||||
```
|
||||
|
||||
### Python (HTML 메일)
|
||||
|
||||
```python
|
||||
def send_html_email(to_email: str, subject: str, html_body: str, text_body: str = None):
|
||||
client = boto3.client('ses', region_name='ap-northeast-2')
|
||||
|
||||
body = {'Html': {'Data': html_body, 'Charset': 'UTF-8'}}
|
||||
if text_body:
|
||||
body['Text'] = {'Data': text_body, 'Charset': 'UTF-8'}
|
||||
|
||||
response = client.send_email(
|
||||
Source='noreply@anvil.it.com',
|
||||
Destination={'ToAddresses': [to_email]},
|
||||
Message={
|
||||
'Subject': {'Data': subject, 'Charset': 'UTF-8'},
|
||||
'Body': body
|
||||
}
|
||||
)
|
||||
return response
|
||||
|
||||
# 사용 예시
|
||||
html = """
|
||||
<html>
|
||||
<body>
|
||||
<h1>안녕하세요!</h1>
|
||||
<p>AWS SES로 발송된 <strong>HTML 메일</strong>입니다.</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
send_html_email('recipient@example.com', '테스트', html)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 환경변수 설정 (컨테이너용)
|
||||
|
||||
```bash
|
||||
export AWS_ACCESS_KEY_ID="your_access_key"
|
||||
export AWS_SECRET_ACCESS_KEY="your_secret_key"
|
||||
export AWS_DEFAULT_REGION="ap-northeast-2"
|
||||
```
|
||||
|
||||
환경변수 설정 시 코드에서 자격증명 생략 가능:
|
||||
|
||||
```python
|
||||
client = boto3.client('ses') # 환경변수에서 자동 로드
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 상태 확인 명령어
|
||||
|
||||
```bash
|
||||
# 발송 활성화 상태
|
||||
aws ses get-account-sending-enabled
|
||||
|
||||
# 발송 한도 확인
|
||||
aws ses get-send-quota
|
||||
|
||||
# 등록된 Identity 목록
|
||||
aws ses list-identities
|
||||
|
||||
# 도메인 인증 상태
|
||||
aws ses get-identity-verification-attributes --identities anvil.it.com ironclad.it.com
|
||||
|
||||
# DKIM 상태
|
||||
aws ses get-identity-dkim-attributes --identities anvil.it.com ironclad.it.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 새 도메인 추가 방법
|
||||
|
||||
### 1. SES 도메인 등록
|
||||
|
||||
```bash
|
||||
aws ses verify-domain-identity --domain newdomain.com
|
||||
aws ses verify-domain-dkim --domain newdomain.com
|
||||
```
|
||||
|
||||
### 2. Cloudflare DNS 레코드 추가
|
||||
|
||||
출력된 토큰으로 TXT, CNAME 레코드 추가 (Cloudflare API 또는 대시보드)
|
||||
|
||||
### 3. 인증 확인
|
||||
|
||||
```bash
|
||||
aws ses get-identity-verification-attributes --identities newdomain.com
|
||||
aws ses get-identity-dkim-attributes --identities newdomain.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 참고 사항
|
||||
|
||||
- **프로덕션 모드**: 수신자 제한 없음
|
||||
- **DKIM**: 메일 신뢰도 향상 (스팸 방지)
|
||||
- **발송 한도**: 필요시 AWS에 증가 요청 가능
|
||||
- **비용**: $0.10 / 1,000통
|
||||
|
||||
---
|
||||
|
||||
## 관련 링크
|
||||
|
||||
- [AWS SES 콘솔](https://ap-northeast-2.console.aws.amazon.com/ses/)
|
||||
- [AWS SES 개발자 가이드](https://docs.aws.amazon.com/ses/latest/dg/)
|
||||
- [Cloudflare DNS](https://dash.cloudflare.com/)
|
||||
Reference in New Issue
Block a user