infra
Platform

모듈 맵

[Infra Ops] SMTP 메일과 SMS 게이트웨이 운영 실무

0 / 52 완료

펼치기
0 / 52 완료0%

Infra-ops · 28 / 52

[Infra Ops] SMTP 메일과 SMS 게이트웨이 운영 실무

SMTP relay 설정, SPF/DKIM/DMARC 개념, SMS 게이트웨이 API 연동, 발송 실패 로그 분석까지

🚨INCIDENT ALERT
HIGH

서비스에 회원가입 인증 메일과 주문 완료 SMS 발송 기능이 추가됐습니다. 개발팀은 코드를 다 짰는데 실제로 메일이 스팸함으로 들어가고, SMS는 간헐적으로 실패합니다. 팀장이 "SPF 설정했어요? SMTP relay 포트 맞아요?"라고 묻는데 막막합니다.

메일이 수신자에게 도착하는 경로, 릴레이 서버 설정, 스팸 방지 DNS 레코드, SMS 게이트웨이 연동 — 이 모듈에서 실무에서 반드시 알아야 할 핵심만 짚습니다.

이번 챕터에서 배울 것
  • 1MTA/MDA/MUA의 역할 분담을 설명하고 메일 전달 경로를 그릴 수 있다
  • 2Postfix relay 설정(relayhost, smtp_sasl_auth_enable)을 작성할 수 있다
  • 3SPF/DKIM/DMARC의 역할 차이를 설명하고 DNS 설정 여부를 확인할 수 있다
  • 4swaks 또는 telnet으로 SMTP 연결을 테스트하고 메일 큐 상태를 확인할 수 있다
  • 5SMS 게이트웨이 HTTP API 호출 구조와 발송 실패 대응 흐름을 설명할 수 있다

메일 전달 구조 이해

💡개념

MTA·MDA·MUA — 메일은 세 주체가 릴레이한다

메일 발송이 실패하거나 스팸함에 들어갔을 때 "어디가 문제인지"를 모르는 이유는 메일 전달 구조를 모르기 때문입니다. 메일은 발신자 단말에서 수신자 단말까지 한 번에 가지 않고, 세 역할을 거쳐 릴레이됩니다.

MTA·MDA·MUA — 메일은 세 주체가 릴레이한다

역할전체 이름예시하는 일
MUAMail User AgentOutlook, Gmail 웹사용자가 메일을 작성·읽는 클라이언트
MTAMail Transfer AgentPostfix, Sendmail서버 간 메일을 라우팅·전달
MDAMail Delivery AgentDovecot, Procmail최종 수신자 메일함에 저장
[앱 서버] → MUA(SMTP 587) → [릴레이 MTA] → [수신 MTA] → MDA → [수신자 메일함]
              발송 요청         SMTP 25/587    DNS MX 조회     저장

실무에서 가장 흔한 구성:

  • 앱 서버는 직접 외부에 SMTP를 보내지 않고 사내 릴레이 MTA나 클라우드 SMTP 서비스(AWS SES, SendGrid 등)를 경유
  • 이유: 직접 25번 발송 시 대부분의 ISP/클라우드가 차단, IP 평판 관리 어려움

Bounce(반송) 유형:

유형코드 범위의미대응
영구 반송(Hard Bounce)5xx주소 없음, 도메인 없음즉시 수신자 목록에서 제거
임시 반송(Soft Bounce)4xx수신함 꽉 참, 서버 일시 불능자동 재시도 후 일정 기간 경과 시 제거
💡개념

Postfix relay 설정 — 앱 서버에서 외부 SMTP로 내보내기

앱 서버에 Postfix를 직접 설치해 외부 SMTP 릴레이로 보내는 구성은 기업 내부 시스템에서 가장 흔합니다. /etc/postfix/main.cf의 핵심 설정만 이해하면 됩니다.

Postfix relay 설정 — 앱 서버에서 외부 SMTP로 내보내기

로컬 터미널
# /etc/postfix/main.cf 핵심 설정 예시

# 릴레이할 SMTP 서버 (포트 587: STARTTLS)
relayhost = [smtp.example.com]:587

# SASL 인증 활성화 (릴레이 서버가 인증을 요구할 때)
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous

# TLS 사용 (STARTTLS)
smtp_tls_security_level = encrypt
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt

# 발신 도메인
myorigin = example.com
로컬 터미널
# /etc/postfix/sasl_passwd (인증 정보 파일)
[smtp.example.com]:587  mailuser@example.com:secretpassword

# 파일 등록 후 해시 생성 및 권한 설정
sudo postmap /etc/postfix/sasl_passwd
sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db

# Postfix 재로드
sudo systemctl reload postfix

메일 큐 확인 명령어:

로컬 터미널
# 큐에 쌓인 메일 목록
mailq
# 또는
postqueue -p

# 큐 강제 발송 시도
postqueue -f

# 특정 메일 큐 항목 상세 확인 (Queue ID로)
postcat -q <QUEUE_ID>

# 큐 전체 삭제 (주의: 미발송 메일 전부 삭제)
postsuper -d ALL

SPF/DKIM/DMARC

💡개념

스팸 방지 3종 세트 — DNS로 메일 신뢰도를 증명한다

메일이 스팸함으로 분류되는 가장 흔한 이유는 SPF/DKIM/DMARC 중 하나라도 빠진 경우입니다. 셋은 각각 다른 문제를 해결합니다.

SPF (Sender Policy Framework) — 발신 서버 IP 인증:

# DNS TXT 레코드 예시 (example.com 도메인)
example.com.  IN  TXT  "v=spf1 ip4:203.0.113.10 include:_spf.sendgrid.net ~all"

# 읽는 법:
# v=spf1          → SPF 버전 1
# ip4:203.0.113.10 → 이 IP에서 보내는 메일은 허용
# include:...      → SendGrid 서버도 허용
# ~all             → 목록 외 서버는 SoftFail (수신은 하되 의심 마킹)
# -all             → 목록 외 서버는 HardFail (거부)

DKIM (DomainKeys Identified Mail) — 메일 내용 서명:

# DNS TXT 레코드 (selector._domainkey.example.com)
default._domainkey.example.com.  IN  TXT
  "v=DKIM1; k=rsa; p=MIGfMA0GCSq..."

# 동작 원리:
# 발신 서버 → 메일 헤더+바디를 개인키로 서명 → 서명값을 헤더에 첨부
# 수신 서버 → DNS에서 공개키 조회 → 서명 검증 → 위변조 여부 확인

DMARC (Domain-based Message Authentication) — 정책 선언:

# DNS TXT 레코드 (_dmarc.example.com)
_dmarc.example.com.  IN  TXT
  "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; pct=100"

# p=none      → 모니터링만 (처음 도입 시 권장)
# p=quarantine → 실패 메일을 스팸함으로
# p=reject    → 실패 메일을 거부
# rua=        → 일일 집계 보고서 수신 주소

빠른 확인 명령어:

로컬 터미널
# SPF 레코드 조회
dig TXT example.com | grep spf

# DKIM 레코드 조회 (selector 이름은 메일 서버 설정 확인)
dig TXT default._domainkey.example.com

# DMARC 레코드 조회
dig TXT _dmarc.example.com

SMTP 연결 테스트

1telnet으로 SMTP 25번 연결 확인

가장 기초적인 SMTP 연결 테스트입니다. 포트가 열려있는지, 서버가 응답하는지 바로 확인합니다.

로컬 터미널
# telnet으로 25번 연결
telnet smtp-server 25

# 정상 응답 예시:
# Trying 203.0.113.10...
# Connected to smtp-server.
# Escape character is '^]'.
# 220 smtp-server ESMTP Postfix (Ubuntu)

# 수동 SMTP 대화 (연결 확인 후)
EHLO testclient
# 250-smtp-server
# 250-PIPELINING
# 250-SIZE 10240000
# 250-STARTTLS
# 250 8BITMIME

QUIT

연결이 안 되면 방화벽 또는 보안 그룹에서 25번 포트가 차단된 것입니다.

telnet smtp-server 25
🔍SMTP 25번 연결 확인 결과
  • telnet smtp-server 25 접속 후 220 ESMTP 응답이 왔는가
  • EHLO testclient 명령에 250-STARTTLS 등 서버 기능 목록이 나왔는가
  • 연결이 거부됐다면 방화벽/보안 그룹 25번 포트 차단 여부를 확인했는가
2STARTTLS로 587번 연결 테스트

운영 환경에서 실제 사용하는 587번 포트 + STARTTLS 조합을 테스트합니다. TLS 협상이 정상인지 인증서가 유효한지 한 번에 확인합니다.

로컬 터미널
openssl s_client -connect smtp-server:587 -starttls smtp

# 정상 응답에서 확인할 것:
# - "verify return:1" → 인증서 검증 성공
# - "CONNECTED(00000003)" → TCP 연결 성공
# - 서버 인증서 정보 (Issuer, Subject)

# 연결 후 수동 인증 테스트 (Base64 인코딩)
AUTH LOGIN
# username (Base64): dXNlckBleGFtcGxlLmNvbQ==
# password (Base64): c2VjcmV0cGFzcw==
openssl s_client -connect smtp-server:587 -starttls smtp
🔍STARTTLS 587번 연결 테스트 결과
  • openssl s_client 출력에서 CONNECTED(00000003)가 나왔는가
  • verify return:1이 나왔는가 (TLS 인증서 검증 성공)
  • 서버 인증서의 SubjectIssuer 정보가 출력됐는가
3swaks로 실제 메일 발송 테스트

swaks(Swiss Army Knife for SMTP)는 명령줄에서 실제 메일을 발송해볼 수 있는 SMTP 테스트 도구입니다. telnet보다 훨씬 편하게 전체 발송 과정을 검증합니다.

로컬 터미널
# 설치
sudo apt-get install -y swaks   # Ubuntu
sudo dnf install -y swaks       # RHEL/CentOS

# 기본 발송 테스트
swaks \
  --to recipient@example.com \
  --from noreply@myapp.com \
  --server smtp-server \
  --port 587 \
  --auth LOGIN \
  --auth-user mailuser@myapp.com \
  --auth-password mysecret \
  --tls \
  --header "Subject: SMTP Test" \
  --body "This is a test mail from swaks"

# 성공 시 출력 예시:
# -> MAIL FROM:<noreply@myapp.com>
# <- 250 2.1.0 Ok
# -> RCPT TO:<recipient@example.com>
# <- 250 2.1.5 Ok
# -> DATA
# <- 354 End data with <CR><LF>.<CR><LF>
# <- 250 2.0.0 Ok: queued as 3A1B2C4D
swaks --to user@example.com --from noreply@myapp.com --server smtp-server --port 587 --auth LOGIN --auth-user mailuser --auth-password secret --tls
🔍swaks 실제 메일 발송 테스트 결과
  • swaks 출력에서 <- 250 2.1.0 Ok(MAIL FROM 수락)와 <- 250 2.1.5 Ok(RCPT TO 수락)가 나왔는가
  • 마지막 응답에 250 2.0.0 Ok: queued as ...가 나왔는가 (발송 큐 등록 성공)
  • 수신자 메일함(받은 편지함 또는 스팸함)에 테스트 메일이 도착했는가
4메일 로그 실시간 확인

메일을 발송하면서 로그를 실시간으로 확인합니다. 성공/실패 여부, 릴레이 경로, 수신 서버 응답이 모두 기록됩니다.

로컬 터미널
# RHEL/CentOS
sudo tail -f /var/log/maillog

# Ubuntu/Debian
sudo tail -f /var/log/mail.log

# 정상 발송 로그 예시:
# May 30 09:15:32 server postfix/smtp[1234]: 3A1B2C4D:
#   to=<user@example.com>, relay=smtp-server[203.0.113.10]:587,
#   delay=0.8, status=sent (250 2.0.0 OK)

# 실패 로그 예시:
# May 30 09:16:44 server postfix/smtp[1235]: 5E6F7G8H:
#   to=<user@example.com>, relay=smtp-server[203.0.113.10]:587,
#   status=bounced (550 5.1.1 The email account does not exist)
sudo tail -f /var/log/maillog
🔍실행 후 확인할 것
  • telnet smtp-server 25 연결 시 '220 ESMTP' 응답이 왔는가 (포트 열림 확인)
  • openssl s_client에서 'verify return:1'이 나왔는가 (TLS 인증서 정상)
  • swaks 발송 후 로그에 'status=sent'가 찍혔는가
  • 수신자 메일함(받은 편지함 또는 스팸함)에 테스트 메일이 도착했는가
  • mailq 명령어 실행 시 큐가 비어 있는가 (메일이 정상 발송됨)

SMS 게이트웨이 연동

💡개념

SMS 게이트웨이 HTTP API — 구조와 운영 포인트

SMS 게이트웨이는 HTTP API를 제공합니다. 앱 서버가 REST API를 호출하면 게이트웨이가 통신사를 통해 단문 메시지를 전달합니다. 국내 주요 사업자로는 NHN Cloud, 카카오 알림톡, 솔라피, 채널톡 등이 있습니다.

기본 HTTP API 호출 구조:

로컬 또는 서버
# curl로 SMS 발송 테스트 (가상의 게이트웨이 예시)
curl -X POST https://api.sms-gateway.com/v1/send \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "from": "01012345678",
    "to": "01098765432",
    "text": "[인증번호] 귀하의 인증번호는 123456입니다.",
    "type": "SMS"
  }'

# 응답 예시 (성공):
# {
#   "resultCode": "1",
#   "message": "성공",
#   "messageId": "MSG20260530001234"
# }

# 응답 예시 (실패):
# {
#   "resultCode": "-1001",
#   "message": "미등록 발신번호"
# }

운영 체크리스트:

항목내용
발신번호 사전등록통신사에 서비스 번호 등록 필수 (전기통신사업법)
API 키 보안환경변수 또는 Secret Manager로 관리, 코드에 하드코딩 금지
재시도 로직4xx는 재시도 금지, 5xx는 exponential backoff 재시도
발송 이력 DB 저장메시지 ID, 수신번호, 발송시각, 결과코드 반드시 저장
발송 실패 알림일정 횟수 이상 실패 시 Slack/메일로 알림

발송 결과 코드 분류:

로컬 터미널
# 게이트웨이 로그에서 실패 분류
# -1001: 미등록 발신번호 → 번호 등록 확인
# -1002: 잔액 부족 → 충전
# -9999: 통신사 오류 → 재시도
# 수신 거부: 080 수신거부 서비스 가입자 → 목록에서 제거

트러블슈팅

원인: SPF, DKIM, DMARC 레코드 중 하나 이상이 미설정이거나 실패하고 있습니다. 수신 서버는 이 세 가지 인증이 모두 통과되지 않으면 스팸으로 분류합니다.

로컬 터미널
# 1. 발송 도메인의 SPF 레코드 확인
dig TXT yourdomain.com | grep spf
# 결과 없으면 → SPF 레코드 미설정

# 2. DKIM 레코드 확인 (selector 확인 필요)
dig TXT default._domainkey.yourdomain.com
# 결과 없으면 → DKIM 설정 미완료

# 3. DMARC 레코드 확인
dig TXT _dmarc.yourdomain.com
# 결과 없으면 → DMARC 미설정

# 4. 실제 수신된 메일 헤더에서 인증 결과 확인
# Gmail: 메일 열기 → 점 세 개 메뉴 → "원본 메시지 보기"
# Authentication-Results: mx.google.com;
#   spf=pass (sender IP is authorized)
#   dkim=pass header.d=yourdomain.com
#   dmarc=pass

# 5. 외부 진단 도구 활용
# https://mxtoolbox.com/SuperTool.aspx
# mail-tester.com 에서 실제 발송 후 점수 확인

해결: DNS 관리 콘솔에서 SPF, DKIM, DMARC TXT 레코드를 순서대로 추가합니다. DNS TTL 전파에 30분~1시간이 걸립니다.

원인: 릴레이 SMTP 서버의 587번 포트가 차단됐거나 서버가 응답하지 않습니다. 방화벽 규칙, 보안 그룹, Postfix main.cf의 relayhost 설정 오류 세 가지를 순서대로 확인합니다.

로컬 터미널
# 1. 포트 연결 가능 여부 확인
nc -zv smtp-server 587
# Connection refused → 방화벽 또는 서버 문제

# 2. 현재 서버에서 외부 SMTP 포트 차단 확인
telnet smtp-server 587
# 연결 안 되면 → 아웃바운드 587 차단

# 3. Postfix 설정 확인
grep relayhost /etc/postfix/main.cf
# relayhost = [smtp-server]:587
# 대괄호 [] 빠지면 MX 조회 시도 → 오동작

# 4. 인증 정보 파일 확인
sudo cat /etc/postfix/sasl_passwd
# [smtp-server]:587  user@domain:password 형식 확인

# 5. Postfix 재로드 후 큐 처리
sudo systemctl reload postfix
postqueue -f

# 6. 실시간 로그 확인
sudo tail -f /var/log/maillog
💼
실무 맥락
현업 패턴

실제 업무에서 이 지식이 쓰이는 상황:

인프라 엔지니어가 메일/SMS 관련으로 가장 자주 받는 요청은 세 가지입니다.

1. "메일이 스팸함으로 가요" 처리:

로컬 터미널
# 빠른 진단 루틴
dig TXT yourdomain.com | grep -E "spf|v=spf1"
dig TXT default._domainkey.yourdomain.com
dig TXT _dmarc.yourdomain.com
# 셋 다 있으면 → 메일 헤더의 Authentication-Results 확인
# 하나라도 없으면 → DNS 설정 추가

2. SMTP relay 설정 요청 (신규 서버):

로컬 터미널
# Postfix 설치 및 릴레이 설정
sudo apt-get install -y postfix
sudo postconf -e "relayhost = [smtp.yourrelay.com]:587"
sudo postconf -e "smtp_sasl_auth_enable = yes"
sudo postconf -e "smtp_tls_security_level = encrypt"
# sasl_passwd 파일 설정 → postmap → systemctl reload

3. SMS 발송 실패 원인 파악: 앱 로그에서 게이트웨이 응답 코드를 확인합니다. -1001(미등록 발신번호)이 가장 흔하며, 실제 서비스 번호를 게이트웨이 콘솔에서 등록하면 해결됩니다. 발송 이력을 DB에 저장하지 않으면 "왜 A 고객한테 인증 메시지가 안 갔나"를 추적할 수 없습니다.

다음 모듈에서는 SFTP와 배치 파일 송수신을 통한 외부 기관 연계 실무를 다룹니다.

지식 확인

퀴즈 — 4문제

Q1

SPF 레코드를 DNS에 등록하는 주된 이유는?

Q2

SMTP 포트 25, 465, 587의 차이로 올바른 것은?

Q3

메일 발송 실패 시 인프라 엔지니어가 가장 먼저 확인해야 할 로그 위치는?

Q4

국내에서 SMS 발송 시 발신번호를 사전 등록해야 하는 이유는?

0 / 4 답변

🧪 실습으로 확인하기

Nginx 설치 및 기동

초급

Linux 서버에 Nginx를 설치하고 systemd 서비스로 등록하여 80포트에서 응답하는 상태까지 만든다.

30📋 3단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요

infra-ops중급 · 60
[Infra Ops] JDBC Connection Pool과 DB 장애 분리 실무
인프라 서비스 운영 트랙 계속
linux입문 · 30
[Linux] 개발자가 왜 리눅스 서버와 커맨드라인을 반드시 배워야 하는가
Linux 트랙 시작점