[Review] 시스템 설계 기초 2 - 분산 이메일 서비스
《가상 면접 사례로 배우는 대규모 시스템 설계 기초 2》 의 8장 '분산 이메일 서비스' 에 대한 후기입니다.
1. POP
이 책에서 소개된 이메일 프로토콜은 SMTP, POP, IMAP,
그중에서도 POP는 이메일 클라이언트가 원격 메일 서버에서 이메일을 수신하고 다운로드하기 위해 사용되는 표준 프로토콜이며, 다음과 같은 특징이 있습니다.
1. 한 대 단말에서만 이메일을 읽을 수 있다.
2. 클라이언트는 이메일을 일부만 읽을 수 없고, 전부 내려받아야한다.
처음 접했을 때는 위의 개념이 이해가 되지 않았습니다.
처음 접했을 때는 위의 개념이 이해가 되지 않았습니다.
하나씩 예시를 통해 이해해봅시다.
1. 한 대 단말에서만 이메일을 읽을 수 있다.
과거 POP는 말 그대로 데이터가 이동했습니다.
클라이언트가 메일을 가져가면 기존 서버에서는 데이터가 지워졌습니다.
인터넷 서비스 초창기 시절이 90년대~00년대 초반이었음을 생각하면 그럴만도 하죠.
현대의 POP는 "여러 기기 간의 동기화가 불가능하다." 입니다.
구글이나 네이버 등 메일 서비스의 POP 다운로드 설정을 보면,
"외부 메일 가져오기" > "서버에 복사본 저장" 옵션이 있습니다.
이제는 여러 대의 기기에서 같은 메일을 POP로 다운로드할 수 있습니다.
그럼에도 여전히 "한 대 단말에서만 사용한다" 라는 평가받는 이유는, 상태 정보 동기화가 되지 않기 때문입니다.
기존 이메일 서비스 A와, A의 클라이언트 B가 있다고 가정해봅시다.
그리고 B는 '복사본 유지' 옵션을 활성화했습니다. 따라서 A와 B가 현재 동일한 메일을 갖고 있습니다.
A에서 메일을 읽어도 B에서는 메일의 읽음 상태는 '안읽음' 입니다.
A에서 메일을 삭제해도 B에는 메일이 삭제되지 않고 남아있습니다.
따라서 실질적으로는 메일을 관리하는 메인 단말기 한 대를 지정해서 써야합니다.
2. 클라이언트는 이메일을 일부만 읽을 수 없고, 전부 내려받아야한다.
예를 들어, 다음과 같은 메일이 있음을 가정해봅시다.
제목: 긴급소식!!!
본문: 뻥임
첨부파일: 200MB 크기의 MOV 파일
POP를 사용하면 200MB 크기의 MOV 파일이 모두 다운로드가 끝나기 전까지는 이메일 내용(본문 등)을 볼 수 없습니다.
2. DNS (도메인 이름 서비스)
DNS 서버는 수신자 도메인의 메일 교환기 레코드 검색에 이용됩니다.
백문이 불여일견, gmail.com의 메일 교환기 레코드를 확인하기 위한 `nslookup` 명령어와,
명령어 출력 결과를 확인해봅시다.
![[Review] 시스템 설계 기초 2 - 분산 이메일 서비스](https://objectstorage.ap-chuncheon-1.oraclecloud.com/n/axxcchwrqnfq/b/k-devcon-dev/o/uploads%2F2026-03-06%2F27fa11d2-818c-41f0-ad35-c904cfe38cbf.webp)
mail exchanger = {숫자} 는 메일 교환기 레코드의 우선순위 값을 나타냅니다.
낮을 수록 선호도가 높은 것이며,
송신차 측 메일 서버는 가장 높은 우선 순위의 메일 서버에 접속하여 메시지를 보내려고 시도합니다.
연결에 실패하면 그 다음으로 우선 순위가 높은 메일 서버에 연결을 시도합니다.
이번엔 naver.com 을 확인해봅시다.
![[Review] 시스템 설계 기초 2 - 분산 이메일 서비스 - 이미지 2](https://objectstorage.ap-chuncheon-1.oraclecloud.com/n/axxcchwrqnfq/b/k-devcon-dev/o/uploads%2F2026-03-06%2F4dfa13ed-2032-486b-b513-75f94956444d.webp)
이번엔 우선순위가 겹치네요!
우선순위 10인 서버가 3개, 20인 서버가 2개가 존재합니다.
우선 순위가 동일할 땐 송신 서버가 어떻게 특정 서버에 연결을 시도할까요?
(Section 5.1)
"...If there are multiple destinations with the same preference [...] then the sender-SMTP MUST randomize them to spread the load across multiple mail exchangers..."
url: https://www.rfc-editor.org/rfc/rfc5321.txt
해석
동일한 우선순위(preference)를 가진 목적지가 여러 개 있다면,
송신 측 SMTP는 특정 조직의 메일 서버들에 부하를 분산하기 위해 반드시 무작위로 섞어야(randomize) 한다.
RFC 표준 규약에서 랜덤 선택을 강제(MUST) 하고 있다는 점이 신기하네요.
3. 첨부 파일
이메일 첨부 파일은 일반적으로 Base64 인코딩을 사용합니다.
예상 외로 기본적이어서 신기했는데요,
초기 SMTP는 7비트 ASCII 문자만 전송하도록 설계가 되었다고 합니다.
현대의 SMTP는 이미지, PDF 등의 바이너리 파일은 8비트 체계도 처리 가능한 확장 규격을 사용합니다.
하지만 SMTP end-to-end 중 하나라도 8비트를 읽지 못하는 구식 노드가 존재한다면 파일이 깨질 수 가능성이 존재하기 때문에, 어느 서비스에서나의 호환성을 위해 Base64 방식을 fallback으로라도 사용하는 것 같습니다.
바이너리 파일을 Base64 인코딩하면 크기가 약 33% 증가합니다.
그리고 지메일은 개인 계정의 첨부파일 크기를 25MB 로 제한하고 있습니다. (25MB 이상 크기의 파일은 Google Drive로 전송)
그럼 지메일의 크기 제한 '25MB' 는 Base64 인코딩 전 파일 기준일까요? 아니면 Base64 인코딩 후 파일 기준일까요?
지메일이 내부적으로 Base64 인코딩을 하지 않을 수도 있지만, 전세계가 사용하는 서비스인 지메일은 호환성을 위해 Base64 인코딩을 해본다고 가정해봅시다.
25MB에 근접한 파일을 만들기 위해 `truncate` 명령어를 사용했습니다.
참고로 정확히 25MB이 만들어지는 건 아니라더라구요.
![[Review] 시스템 설계 기초 2 - 분산 이메일 서비스 - 이미지 3](https://objectstorage.ap-chuncheon-1.oraclecloud.com/n/axxcchwrqnfq/b/k-devcon-dev/o/uploads%2F2026-03-06%2Ff3cef613-4189-42b3-a477-8093a4ea28d8.webp)
만들어진 파일을 Base64 포맷으로 변환 후 바이트 수를 세봅시다.
약 25MB인 파일을 인코딩하니 약 34.95MB 가 되네요.
![[Review] 시스템 설계 기초 2 - 분산 이메일 서비스 - 이미지 4](https://objectstorage.ap-chuncheon-1.oraclecloud.com/n/axxcchwrqnfq/b/k-devcon-dev/o/uploads%2F2026-03-06%2F807fc0f4-ec67-453b-9465-6772c152c745.webp)
마지막으로 지메일 첨부파일 크기 테스트를 위해 메일 발송을 해보면?!
문제 없이 전송이 됩니다.
유저 단에서 첨부파일의 크기를 25MB로 제한하더라도 내부적으로는 35~50MB 즈음까지 허용한다고 예상해볼 수 있겠습니다.
![[Review] 시스템 설계 기초 2 - 분산 이메일 서비스 - 이미지 5](https://objectstorage.ap-chuncheon-1.oraclecloud.com/n/axxcchwrqnfq/b/k-devcon-dev/o/uploads%2F2026-03-06%2F75566956-b3a6-4184-ad59-a3ec97a46edf.webp)
이번엔 테스트 메일을 받은 네이버 메일을 확인해봅시다.
네이버 메일은 지메일보다 첨부파일 크기를 훨씬 제한하여, 10MB 까지만 첨부할 수 있습니다.
하지만 25MB 파일(인코딩 후 35MB) 이 문제 없이 도착했습니다.
![[Review] 시스템 설계 기초 2 - 분산 이메일 서비스 - 이미지 6](https://objectstorage.ap-chuncheon-1.oraclecloud.com/n/axxcchwrqnfq/b/k-devcon-dev/o/uploads%2F2026-03-06%2F0716faf7-ac90-48f6-99fd-e759bd35a099.webp)
end-to-end가 성공했음을 통해 예상해볼 수 있는 내부 설정값은,
네이버 또한 35~50MB 수준으로 높게 설정해두었을 것 같네요.
송신 측에서 용량 크기 제한이 문제가 없더라도 수신 측의 수용 한도를 넘어서면 전송은 실패합니다.
따라서 타 서버 간 안정적인 통신을 위해서는 어느 정도 수용량을 넉넉히 잡아두어야 합니다.