이메일과 메시징
메일 한 통이 보내는 앱에서 받는 사람의 메일함까지 가는 길 — 제출, MX 조회, SMTP 중계, 배달, IMAP — 과 그 위에 덧댄 암호화와 발신 인증(SPF·DKIM·DMARC), 스팸 판정, 반송을 따라가고, 문자·RCS·알림톡·푸시·메신저 같은 다른 채널과 비교한다.
목차 (15)
이메일이 전달되는 길
이메일은 우편과 닮았다. 보내는 사람이 동네 우체국에 맡기면, 우체국끼리 주고받아 받는 사람 동네의 우체국에 도착하고, 받는 사람은 자기 우편함에서 꺼낸다. 이메일에서 각 역할에 이름이 있다. 메일을 쓰고 읽는 앱이 MUA(Mail User Agent), 앱이 보낸 메일을 받아 주는 제출 서버가 MSA(Message Submission Agent), 서버끼리 메일을 건네는 것이 MTA(Mail Transfer Agent), 받은 메일을 메일함에 넣는 것이 MDA(Mail Delivery Agent)다. 실제 메일 서비스에서는 한 프로그램이 여러 역할을 겸하기도 한다.
구간마다 쓰는 프로토콜이 다르다. 앱 → MSA는 제출이고 포트 587을 쓴다(RFC 6409). 제출 서버는 로그인(SMTP AUTH)하지 않은 세션의 MAIL 명령을 거절해야 한다. 서버 → 서버는 중계이고 SMTP 포트 25를 쓴다. 받은 메일을 읽는 쪽은 IMAP(메일을 서버에 두고 여러 기기에서 폴더·읽음 표시를 동기화)이나 POP3(내려받아 읽기)다. RFC 8314는 IMAP 993, POP3 995, 제출 465처럼 접속하자마자 TLS를 거는 포트를 STARTTLS보다 먼저 쓰라고 권한다.
앨리스의 메일 앱(MUA)이 회사·메일 서비스의 제출 서버(MSA)에 로그인한 뒤 메일을 넘긴다. 제출 전용 포트는 587(STARTTLS)과 465(처음부터 TLS)다.
DNS MX 레코드
보내는 MTA는 bob@example.net의 @ 뒤 도메인을 보고, DNS에 그 도메인의 MX 레코드(Mail eXchanger)를 묻는다. MX 레코드는 "이 도메인의 메일은 이 서버가 받는다"는 표지판이고, 레코드마다 우선순위 숫자가 붙는다. RFC 5321에 따르면 숫자가 작을수록 먼저 시도한다. 우선순위가 다른 서버를 여럿 두면 주 서버가 죽어도 예비 서버가 받는다. 웹사이트 주소(A 레코드)와 메일 서버가 다른 회사에 있어도 되는 것은 이 덕분이다. DNS 자체는 네트워크 노트의 주소 절에 있다.
MX 레코드가 아예 없으면 도메인 이름 자체를 우선순위 0인 MX로 본다(암묵적 MX). 메일을 받지 않는 도메인은 MX 0 . 한 줄을 둔다. 이것이 null MX(RFC 7505)다. 점 하나는 올바른 호스트 이름이 아니라서 보내는 쪽이 며칠씩 재시도하지 않고 바로 실패로 처리할 수 있다.
SMTP 대화
SMTP는 사람이 읽을 수 있는 글자 명령으로 주고받는다. 접속하면 서버가 220으로 인사하고, 클라이언트가 EHLO로 자기 이름을 대면 서버가 지원하는 확장(STARTTLS, 크기 제한 등)을 알려 준다. 이어서 MAIL FROM으로 보내는 사람, RCPT TO로 받는 사람(여럿이면 여러 번)을 알리고, DATA를 보낸 뒤 서버가 354로 허락하면 메일 내용 전체를 보낸다. 내용의 끝은 마침표 하나만 있는 줄이다. 서버가 250으로 받으면 이제 메일의 책임은 받는 서버로 넘어간다.
응답 코드의 첫 자리가 뜻을 정한다. 2는 성공, 3은 "계속 보내라", 4는 일시 실패(나중에 다시), 5는 영구 실패다. RFC 3463은 여기에 5.1.1(없는 메일함)처럼 점으로 나눈 세 자리 상세 코드를 더했다.
봉투와 헤더: From 위조가 가능한 이유
RFC 5321은 "메일 객체는 봉투와 내용으로 이루어진다"고 말한다. 봉투는 SMTP 명령 MAIL FROM·RCPT TO에 실린 주소이고, 배달과 반송은 이것만 보고 한다. 내용은 DATA 뒤에 보내는 헤더와 본문이고, 메일 앱이 보여 주는 보낸 사람은 헤더의 From:이다. 둘은 서로 다른 칸이라 다른 값을 적어도 SMTP는 막지 않는다. 메일링 리스트가 반송을 자기 주소로 받거나, 발송 대행 서비스가 반송 처리 주소를 따로 쓰는 것이 정상적인 쓰임새다.
같은 이유로 처음 설계된 SMTP에서는 누구나 헤더 From에 남의 주소를 적어 보낼 수 있었다. From 위조를 막으려고 나중에 덧댄 장치가 아래의 SPF·DKIM·DMARC다.
메시지 형식: 헤더, MIME, 첨부
메일 내용의 형식은 RFC 5322가 정한다. 맨 위가 이름: 값 꼴의 헤더 줄들이고, 빈 줄 하나 뒤가 본문이다. 꼭 있어야 하는 헤더는 Date와 From 둘뿐이고, Message-ID는 있어야 한다(SHOULD). 한 줄은 998자를 넘으면 안 되고 78자 이하를 권한다. 원래 형식은 영어 글자만 생각했기에 한글·HTML·첨부를 실으려면 MIME(RFC 2045~)이 필요하다. MIME-Version: 1.0 헤더를 두고, 본문마다 Content-Type으로 종류(text/plain; charset=utf-8, image/png)를 밝히며, multipart로 여러 조각을 한 메일에 담는다. 같은 글의 텍스트판과 HTML판을 multipart/alternative로 함께 보내면 앱이 보여 줄 수 있는 쪽을 고른다.
본문은 줄 단위의 글자로 오가므로, 사진·PDF 같은 바이너리는 Base64로 글자로 바꿔 싣는다. 3바이트(24비트)를 6비트씩 넷으로 나눠 64가지 글자 하나씩으로 쓰므로 크기가 4/3이 된다. 여기에 RFC 2045가 정한 대로 76자마다 줄을 바꾸면 줄바꿈 글자까지 더해진다. 3 MB 첨부라면 Base64만으로 +33.3%, 줄바꿈까지 +36.8%다. 메일 서비스의 첨부 크기 제한에 실제로는 그보다 작은 파일만 들어가는 이유다. 비트와 인코딩 일반은 데이터 노트, 한글이 깨지는 문제는 문자와 시간 노트에 있다.
전송 구간 암호화: STARTTLS와 MTA-STS
서버 사이의 SMTP는 처음에 평문이었다. STARTTLS(RFC 3207)는 같은 포트 25 연결에서 서버가 EHLO 응답으로 STARTTLS를 광고하면, 클라이언트가 그 명령을 보내 TLS로 올라타는 방식이다. TLS가 맺어지면 그 전에 들은 내용은 버리고 EHLO를 다시 보낸다. 문제는 광고 자체가 평문이라는 점이다. RFC 3207도 중간자가 서버 응답에서 STARTTLS 줄을 지우면 클라이언트가 TLS를 시도하지 않는다고 적었다. 대부분의 서버는 TLS가 안 되면 그냥 평문으로 보내기 때문이다(기회적 암호화).
MTA-STS(RFC 8461)는 받는 도메인이 "우리 MX는 언제나 신뢰할 수 있는 인증서로 TLS를 한다"고 미리 밝혀 두는 장치다. DNS의 _mta-sts.example.net TXT 레코드로 정책이 있음을 알리고, 정책 파일은 HTTPS로 https://mta-sts.example.net/.well-known/mta-sts.txt에서 받는다. 모드가 enforce면 보내는 쪽은 이름이 맞지 않거나 인증서가 틀리거나 STARTTLS를 안 하는 MX에는 보내지 않는다. testing은 실패를 보고만 받고, 정책을 캐시해 두는 max_age는 최대 약 1년이다. 웹의 HSTS와 같은 발상이다(보안 › 네트워크 보안의 HSTS 절). 어느 쪽이든 지키는 것은 서버와 서버 사이의 구간뿐이고, 서버에 저장된 메일은 서비스 회사가 읽을 수 있다.
발신 인증: SPF, DKIM, DMARC
세 장치는 확인하는 대상이 다르다. 모두 보내는 도메인의 주인이 DNS에 정보를 올려 두고, 받는 서버가 그것을 읽어 확인한다.
- SPF(RFC 7208): 봉투의
MAIL FROM(과 HELO) 도메인이 "이 IP들만 우리 이름으로 보낸다"는 목록을 TXT 레코드로 둔다. 받는 서버는 접속해 온 IP가 목록에 있는지 본다. 결과는 pass, fail, softfail, neutral, none, temperror, permerror 일곱 가지이고,-all은 목록 밖이면 fail,~all은 softfail이다. 다른 레코드를 끌어오는include같은 DNS 조회는 10번까지만 허용되고, 넘으면 permerror다. 약점은 헤더 From을 보지 않는다는 것, 그리고 메일을 전달(포워딩)하면 보낸 IP가 바뀌어 깨진다는 것이다. - DKIM(RFC 6376): 보내는 서버가 본문의 해시와 고른 헤더(From은 반드시)에 전자 서명을 해
DKIM-Signature헤더로 붙인다.d=가 서명한 도메인,s=가 키 이름(셀렉터)이고, 공개 키는셀렉터._domainkey.도메인TXT 레코드에 있다. 내용이 바뀌지 않으면 전달되어도 서명이 살아남는다. 서명의 원리는 암호학 노트에 있다. - DMARC: 사람이 보는 헤더 From 도메인을 지킨다. SPF나 DKIM 가운데 하나 이상이 통과했고, 그 도메인이 From과 정렬(alignment)되어야 통과다. 정렬은 기본이 relaxed(조직 도메인이 같으면 됨, news.example.com과 example.com)이고,
adkim=s·aspf=s면 strict(완전히 같아야 함)다. 정책은_dmarc.도메인TXT 레코드에p=none(처리 요청 없음)·quarantine(의심 메일로)·reject(거부)로 적고,rua=로 받는 서버들의 집계 보고서를 받아 본다.
뉴스레터: From은 news.example.com, SPF는 bounce.example.com, DKIM은 example.com이다. 셋 다 조직 도메인이 example.com이라 relaxed 정렬로 맞는다. 둘 다 통과·정렬.
DMARC는 2015년 RFC 7489(정보 문서)로 나왔고, 2026년 표준판인 RFC 9989가 이를 대신했다. 새 판은 조직 도메인을 공개 접미사 목록 대신 DNS를 위로 거슬러 올라가며 찾고(트리 워크), 일부만 정책을 적용하던 pct 태그를 없애고 시험 모드 t=y를 두었으며, 보고서 형식은 RFC 9990·9991로 나눴다. 또 받는 쪽이 p=reject만 보고 거부하지는 말라고 권한다. 메일링 리스트처럼 정상적으로 내용을 바꾸는 중계가 있기 때문이다.
대량 발송 요건: Gmail·Yahoo 2024
오랫동안 SPF·DKIM·DMARC는 "하면 좋은 것"이었다. 이를 바꾼 것이 2024년 2월 1일부터 적용된 Google의 발신자 요건과, 같은 달부터 시행에 들어간 Yahoo의 요건이다. 두 회사 모두 모든 발신자에게 SPF나 DKIM, 올바른 정방향·역방향 DNS, 스팸 신고율 0.3% 미만을 요구한다. Google은 TLS 전송과 1024비트 이상의 DKIM 키도 요구한다.
대량 발신자(Google 기준 Gmail 계정으로 하루 5,000통 넘게 보내는 곳)에게는 더 많다. SPF와 DKIM을 둘 다 하고, DMARC 레코드를 두되 정책은 p=none이어도 되지만 From 도메인이 SPF나 DKIM 도메인과 정렬되어야 한다. 마케팅 메일에는 원클릭 구독 해지를 넣어야 한다. RFC 8058의 List-Unsubscribe(https 주소)와 List-Unsubscribe-Post: List-Unsubscribe=One-Click 헤더를 두고, 이 두 헤더가 DKIM 서명에 포함되어야 한다. 본문에도 잘 보이는 해지 링크를 둔다. Yahoo는 해지 요청을 2일 안에 처리하라고 덧붙였다.
스팸 판정과 평판
받는 서버는 한 가지 신호로 스팸을 가리지 않는다. 접속해 온 IP와 그 IP의 역방향 DNS, 발신 인증 결과, 보낸 도메인이 그동안 쌓은 평판, 본문의 링크와 첨부, 그리고 받는 사람들이 "스팸 신고"를 누른 비율을 함께 본다. 정확한 가중치는 서비스마다 다르고 공개하지 않는다. 공개된 숫자는 Google의 기준 정도다. Postmaster Tools로 보는 스팸 신고율을 0.1% 미만으로 두기를 권하고, 0.3% 이상은 피하라고 한다. 천 통에 세 명이 신고하면 선을 넘는다는 뜻이다.
그래서 평판은 주소를 사서 한꺼번에 보내는 식으로는 쌓이지 않는다. 받기로 한 사람에게만 보내고(가입 확인을 한 번 더 받는 더블 옵트인), 반송되는 주소는 빨리 목록에서 빼고, 해지를 쉽게 해 신고 대신 해지를 누르게 하는 것이 기본이다. 새 IP나 새 도메인은 이력이 없어 처음부터 대량으로 보내면 의심받기 쉽다.
바운스와 반송
받는 서버가 4로 시작하는 코드(예: 4.2.2 메일함 가득 참)를 돌려주면, 보내는 MTA는 메일을 대기열에 두고 나중에 다시 보낸다. RFC 5321은 재시도 간격을 적어도 30분, 포기하기까지를 적어도 4~5일로 권한다. 30분 간격으로 4일이면 최대 192번이다. 5로 시작하는 코드(예: 5.1.1 없는 메일함, 5.7.1 거부)는 다시 보내도 소용없으니 바로 실패로 처리한다.
실패하면 보낸 사람에게 반송 메일(바운스, 배달 상태 알림 DSN)이 간다. 이것은 헤더 From이 아니라 봉투의 MAIL FROM 주소로 가고, 반송 메일 자신은 봉투 주소를 빈 값 <>로 보내 반송의 반송이 끝없이 돌지 않게 한다. 받는 서버가 일단 250으로 받은 뒤에 배달에 실패하면 받는 서버가 반송을 만들어야 하는데, 봉투 주소를 위조한 스팸이면 엉뚱한 사람이 반송을 받는다. 그래서 요즘 서버는 거부할 메일을 되도록 SMTP 대화 도중에 5xx로 거절한다.
피싱 메일 구별
위의 장치를 알면 피싱 메일을 볼 때 어디를 봐야 할지가 보인다. 메일 앱이 굵게 보여 주는 표시 이름("예시은행 보안팀")은 아무 글자나 쓸 수 있다. 주소를 펼쳐서 @ 뒤 도메인의 끝부분을 본다. example.com.verify.example.net의 진짜 도메인은 맨 끝 example.net이다. 링크는 보이는 글자와 실제 주소가 다를 수 있으니 누르기 전에 마우스를 올리거나 길게 눌러 주소를 확인한다. "24시간 안에" 같은 재촉은 판단할 시간을 뺏는 수법이다.
메일 앱의 "원본 보기"에는 받는 서버가 남긴 Authentication-Results 헤더가 있어 spf=·dkim=·dmarc= 결과를 직접 볼 수 있다. 다만 DMARC 통과는 "그 도메인이 보낸 것이 맞다"는 뜻일 뿐 안전하다는 뜻이 아니다. 공격자가 비슷한 이름의 도메인을 사서 인증까지 제대로 걸 수 있다. 결국 가장 확실한 방법은 메일 속 링크 대신 즐겨찾기나 앱으로 직접 들어가 확인하는 것이다. 조직 차원의 대응과 훈련은 보안 › 사람과 운영 노트의 피싱 절에 있다.
푸시 알림과 문자 메시지 채널
앱 푸시 알림은 이메일과 달리 주소가 기기 토큰이고, 애플의 APNs와 구글의 FCM이 기기와 연결 하나를 대신 유지해 전달한다. 동작과 실무 규칙은 모바일 앱 개발 노트의 푸시 알림 절에 있다.
전화번호로 보내는 채널은 여럿이다. SMS는 한 통에 GSM-7 글자로 160자, 한글이나 이모지가 섞여 UCS-2로 바뀌면 70자다. 길면 여러 통으로 나뉘는데, 조각을 잇는 헤더(UDH)가 자리를 먹어 한 통에 153자·67자가 된다(Twilio 문서 기준). 그래서 한글 71자는 2통이 된다. 사진·영상은 MMS로 보낸다. 둘 다 종단 간 암호화가 없다. RCS는 데이터나 Wi-Fi로 주고받는 문자이고, 그 연결이 끊기면 SMS로 내려간다. Google 메시지 도움말은 두 사람이 모두 Google 메시지를 쓰고 RCS를 켠 경우 종단 간 암호화를 한다고 하고, Apple 지원 문서는 아이폰의 RCS가 iOS 18부터, 그 종단 간 암호화는 iOS 26.5부터이며 모든 참가자의 통신사가 지원할 때만 된다고 적었다.
국내에서 흔한 카카오 알림톡은 카카오톡 채널을 추가하지 않은 사람에게도 보낼 수 있는 정보성 메시지다. 광고는 보낼 수 없고, 카카오의 심사를 통과한 템플릿만 쓸 수 있으며, 카카오와 계약한 공식 딜러사를 통해 보낸다. 적법하게 모은 전화번호만 써야 한다.
메신저 종단 간 암호화
이메일과 SMS에서 서버는 내용을 읽을 수 있다. 전송 구간 TLS는 오가는 길만 지키기 때문이다. 종단 간 암호화(E2EE)는 보내는 기기와 받는 기기만 아는 키로 암호화해서, 중간의 서버는 암호문만 전달하게 한다. 대표가 Signal 프로토콜이다. 처음 대화를 시작할 때 상대가 서버에 미리 올려 둔 공개 키 묶음으로 키를 합의하고(X3DH, 그 양자내성판 PQXDH), 이후에는 더블 래칫으로 메시지마다 새 키를 만들어 키 하나가 새어도 앞뒤 메시지가 함께 풀리지 않게 한다. 여러 기기의 세션을 다루는 Sesame, ML-KEM을 쓰는 ML-KEM Braid도 공개 명세에 있다.
E2EE에서 서버를 믿지 않으니 남는 질문은 "이 공개 키가 정말 상대의 것인가"다. 그래서 메신저들은 두 사람이 비교할 수 있는 안전 번호·확인 코드를 보여 준다(Google 메시지의 RCS에도 대화마다 확인 코드가 있다). 키 합의에 쓰이는 디피–헬먼의 수학은 암호학 노트의 디피–헬먼 절에 있다.
흔한 오해
- "보낸 사람 주소가 회사 도메인이면 진짜다." 헤더 From은 봉투와 따로 적는 값이다. 그 도메인이 DMARC를
reject로 걸어 두었고 받는 서버가 따를 때만 위조가 막힌다. - "SPF만 있으면 된다." SPF는 봉투 도메인만 보고 전달하면 깨진다. DKIM과 DMARC를 함께 걸어야 From이 지켜진다.
- "이메일은 암호화되어 간다." STARTTLS는 기회적이라 상대가 지원하지 않거나 중간에 지워지면 평문으로 간다. 되어도 서버 사이 구간뿐이고, 메일함의 메일은 서비스가 읽을 수 있다.
- "첨부 제한이 20 MB면 20 MB 파일을 보낼 수 있다." Base64로 바꾸면 3분의 1 넘게 커진다.
- "DMARC 통과 메일은 안전하다." 통과는 도메인 주인이 보냈다는 뜻일 뿐이다. 비슷한 도메인을 산 공격자도 통과할 수 있다.
- "문자 메시지는 통신사 망이라 안전하다." SMS·MMS에는 종단 간 암호화가 없다(Apple·Google 도움말).
핵심 자료
DNS는 네트워크 노트, 피싱과 보안 운영은 보안 › 사람과 운영에 있다.
| 자료 | 종류 | 요지 | 링크 |
|---|---|---|---|
| RFC 5321 Simple Mail Transfer Protocol | 표준 | SMTP 명령과 응답 코드, 봉투와 내용의 구분, MX 우선순위, 재시도와 반송 규칙. 메일 전송의 뼈대다. | RFC Editor |
| RFC 5322 Internet Message Format | 표준 | 헤더와 본문의 형식. 꼭 있어야 하는 헤더는 Date와 From 둘뿐이고, 한 줄은 998자를 넘지 않는다. | RFC Editor |
| RFC 7208 SPF | 표준 | 봉투 도메인이 허락한 서버 목록을 DNS에 두는 방식. DNS 조회 10회 제한과 결과 일곱 가지. | RFC Editor |
| RFC 6376 DKIM Signatures | 표준 | 헤더와 본문에 도메인 서명을 붙이고 공개 키를 selector._domainkey에 두는 방식. | RFC Editor |
| RFC 9989 DMARC | 표준 | RFC 7489를 대신하는 표준판 DMARC. 조직 도메인을 DNS 트리 워크로 찾고, pct 대신 t(시험 모드) 태그를 둔다. | RFC Editor |
| 이메일 발신자 가이드라인 | 안내 | Gmail로 보내는 모든 발신자와 대량 발신자의 요건. 인증, PTR, TLS, 스팸 신고율, 원클릭 구독 해지. | |
| Sender Best Practices | 안내 | Yahoo의 발신자 요건. Gmail과 거의 같고, 구독 해지를 2일 안에 처리하라는 항목이 있다. | Yahoo |
| Signal Specifications | 명세 | X3DH·PQXDH 키 합의와 더블 래칫 등 Signal 프로토콜의 공개 명세. | Signal |
- RFC 5321 Simple Mail Transfer Protocol — RFC Editor
- RFC 5322 Internet Message Format — RFC Editor
- RFC 7208 SPF — RFC Editor
- RFC 6376 DKIM Signatures — RFC Editor
- RFC 9989 DMARC — RFC Editor
- 이메일 발신자 가이드라인 — Google
- Sender Best Practices — Yahoo
- Signal Specifications — Signal
- RFC 7489 DMARC (2015, 정보 문서) — RFC Editor
- RFC 6409 Message Submission for Mail — RFC Editor
- RFC 8314 Cleartext Considered Obsolete — RFC Editor
- RFC 9051 IMAP4rev2 — RFC Editor
- RFC 2045 MIME Part One — RFC Editor
- RFC 3207 SMTP Service Extension for Secure SMTP over TLS — RFC Editor
- RFC 8461 SMTP MTA Strict Transport Security (MTA-STS) — RFC Editor
- RFC 7505 A "Null MX" No Service Resource Record — RFC Editor
- RFC 8058 One-Click Unsubscribe — RFC Editor
- RFC 3463 Enhanced Mail System Status Codes — RFC Editor
- What is the SMS character limit? — Twilio
- Google 메시지의 종단 간 암호화 — Google 메시지 고객센터
- About iMessage and SMS/MMS/RCS — Apple 지원
- 알림톡 — 카카오비즈니스 가이드