# 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) ``` --- ## 이메일 인증 (SPF, DKIM, DMARC) > DMARC 준수를 위해 SPF와 DKIM 모두 설정 필요. 두 가지 중 하나라도 통과하면 DMARC 통과. ### 인증 방식 비교 | 방식 | 역할 | 검증 대상 | |------|------|----------| | **SPF** | 발신 서버 허용 목록 | MAIL FROM 도메인 | | **DKIM** | 메일 서명 검증 | 메일 헤더 서명 | | **DMARC** | SPF/DKIM 정책 통합 | From 도메인 정렬 | --- ## DNS 설정 (Cloudflare) ### anvil.it.com **TXT 레코드 (도메인 소유권 확인)** | Type | Name | Content | |------|------|---------| | TXT | `_amazonses.anvil.it.com` | `0cuw9v32N+aeFiNlTh2Poxglgzf3BlmFRjVOjeLEdy4=` | **TXT 레코드 (SPF)** ⭐ 신규 | Type | Name | Content | |------|------|---------| | TXT | `anvil.it.com` | `v=spf1 include:amazonses.com ~all` | **TXT 레코드 (DMARC)** ⭐ 신규 | Type | Name | Content | |------|------|---------| | TXT | `_dmarc.anvil.it.com` | `v=DMARC1; p=quarantine; rua=mailto:dmarc@anvil.it.com; pct=100` | **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=` | **TXT 레코드 (SPF)** ⭐ 신규 | Type | Name | Content | |------|------|---------| | TXT | `ironclad.it.com` | `v=spf1 include:amazonses.com ~all` | **TXT 레코드 (DMARC)** ⭐ 신규 | Type | Name | Content | |------|------|---------| | TXT | `_dmarc.ironclad.it.com` | `v=DMARC1; p=quarantine; rua=mailto:dmarc@ironclad.it.com; pct=100` | **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` | ### DMARC 정책 옵션 | 정책 | 설명 | 권장 단계 | |------|------|----------| | `p=none` | 모니터링만 (조치 없음) | 초기 테스트 | | `p=quarantine` | 스팸함으로 이동 | 중간 단계 | | `p=reject` | 수신 거부 | 최종 단계 | --- ## 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': '

Hello

', '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 = """

안녕하세요!

AWS SES로 발송된 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 ``` --- ## 반송/불만 처리 (SNS 연동) > 반송(Bounce)과 불만(Complaint) 처리는 SES 평판 유지에 필수 ### SNS 토픽 생성 ```bash # 반송 알림용 토픽 aws sns create-topic --name ses-bounces --region ap-northeast-2 # 불만 알림용 토픽 aws sns create-topic --name ses-complaints --region ap-northeast-2 ``` ### SES 알림 설정 ```bash # 반송 알림 연결 aws ses set-identity-notification-topic \ --identity anvil.it.com \ --notification-type Bounce \ --sns-topic arn:aws:sns:ap-northeast-2:ACCOUNT_ID:ses-bounces # 불만 알림 연결 aws ses set-identity-notification-topic \ --identity anvil.it.com \ --notification-type Complaint \ --sns-topic arn:aws:sns:ap-northeast-2:ACCOUNT_ID:ses-complaints ``` ### 반송 유형 | 유형 | 설명 | 조치 | |------|------|------| | **Hard Bounce** | 영구적 실패 (주소 없음) | 즉시 목록에서 제거 | | **Soft Bounce** | 일시적 실패 (용량 초과) | 재시도 후 제거 | | **Complaint** | 스팸 신고 | 즉시 목록에서 제거 | ### 권장 임계값 - **반송률**: 5% 미만 유지 (10% 초과 시 계정 정지 위험) - **불만률**: 0.1% 미만 유지 --- ## 인증 검증 명령어 ```bash # SPF 레코드 확인 dig TXT anvil.it.com +short # DMARC 레코드 확인 dig TXT _dmarc.anvil.it.com +short # DKIM 레코드 확인 dig CNAME dgcehnldehfmfgpvrrbc6drwasiibhnp._domainkey.anvil.it.com +short ``` --- ## 참고 사항 - **프로덕션 모드**: 수신자 제한 없음 - **DKIM**: 메일 서명으로 위변조 방지 - **SPF**: 허용된 발신 서버 목록 정의 - **DMARC**: SPF/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/)