[Network] 2-4. Electronic Mail in the Internet

Park Yeongseo·2024년 7월 14일
1

Network

목록 보기
9/16
post-thumbnail

인터넷 이메일 시스템은 세 개의 주요 구성 요소, 사용자 에이전트(user agent), 메일 서버, SMTP로 이루어져 있다.

User Agent

사용자는 사용자 에이전트를 통해 메시지를 쓰고, 보내고, 저장하고, 전달한다. 사용자가 메시지 작성을 완료하면 사용자 에이전트는 해당 메시지를 그 사용자의 메일 서버로 보내며, 메시지는 메일 서버의 발신 메시지 큐(outgoing message queue)로 들어간다.

Mail Server

메일 서버는 이메일 인프라의 핵심이다. 각 사용자는 메일 서버 내에 메일박스(mailbox)를 가지고 있으며, 각 메일박스는 해당 사용자에게 보내진 메시지를 관리하고 유지한다.

메시지는 송신자의 사용자 에이전트를 출발해 송신자 메일 서버로 보내지고, 수신자 메일 서버로 보내져 수신자의 메일박스로 들어 간다. 송신자의 메일 서버는 수신자의 메일 서버로 메일을 전송할 수 없을 때, 해당 메시지를 메시지 큐에 가지고 있다 나중에 재전송한다.

SMTP

SMTP는 이메일의 주요 애플리케이션-계층 프로토콜이다. SMTP는 송신자 메일 서버에서 수신자 메일 서버로 메시지를 보내기 위해 TCP의 신뢰할 수 있는 데이터 전송 서비스를 사용한다. 다른 많은 애플리케이션-계층 프로토콜과 마찬가지로 SMTP에는 클라이언트와 서버의 두 쪽이 있다. 다른 메일 서버로 메일을 보내는 메일 서버는 SMTP 클라이언트의 역할을 하고, 다른 메일 서버로부터 메일을 받는 서버는 SMTP 서버의 역할을 한다.

1. SMTP(Simple Mail Transfer Protocol)

SMTP는 HTTP보다 오래 됐다. SMTP는 그 자체로 훌륭한 프로토콜이기는 하지만, SMTP가 처음 표준화된 1982년과 달리, 오늘날에는 여러 제약 사항으로 인해 그 자체로만 쓰이는 경우는 드물다. 예를 들어 SMTP에는 헤더 뿐만 아니라 바디도 7-비트 아스키로 제한되어 있다. 사람들이 이메일을 통해 큰 첨부 파일을 보내거나 하지는 않았던 1980년대에야 이 제약 사항이 문제가 되지 않았겠지만, 여러 멀티미디어 파일들을 이메일로 보내곤 하는 오늘날에 이 제약은 뼈아프다.

이제 SMTP의 기본적인 동작들을 시나리오를 통해 알아보자. Alice는 Bob에게 간단한 아스키 메시지를 보내려 한다.

  1. Alice는 자신의 사용자 에이전트를 켜고, Bob의 이메일 주소, 메시지를 제공한 후, 사용자 에이전트에게 메시지를 보내라고 명령한다.
  2. Alice의 사용자 에이전트는 메시지를 메일 서버로 보내고, 메시지는 메일 서버의 메시지 큐에 들어간다.
  3. Alice의 메일 서버에서 돌아가는 SMTP의 클라이언트 사이드는 메시지 큐 내에 있는 메시지를 확인하고, Bob의 메일 서버에서 돌아가는 SMTP 서버와 TCP 연결을 연다.
  4. SMTP 핸드셰이킹 이후, SMTP 클라이언트는 Alice의 멧시지를 TCP 연결로 내보낸다.
  5. Bob의 메일 서버의 서버 측 SMTP에서 메시지를 받아, 해당 메시지를 Bob의 메일 박스에 넣는다.
  6. Bob은 자기가 원할 때 자신의 사용자 에이전트를 켜서 메시지를 읽는다.

SMTP에서는 수신 메일 서버와 송신 메일 서버가 서로 지구 반대편에 있다 하더라도, 중간 메일 서버를 이용한다거나 하지 않고, 직접 TCP 연결을 맺는다. 메일을 보내려 할 때, 수신자의 메일 서버가 다운되어 있다면, 해당 메시지는 송신자의 메시지 큐에 들어가 있지, 중간 메일 서버의 어딘가에 들어가 있거나 하지 않는다.

어떻게 SMTP가 메시지를 송신 메일 서버에서 수신 메일 서버로 전송하는지를 더 자세히 알아보자.

  1. 우선 클라이언트 SMTP는 서버 SMTP의 25번 포트와 TCP 연결을 연다. 만약 서버가 다운되어 있다면 클라이언트는 나중에 재시도 한다.
  2. 연결이 되고 나면 서버와 클라이언트는 애플리케이션-계층의 핸드셰이크를 진행한다. 핸드셰이킹 과정에서 SMTP 클라이언트는 송신자의 이메일 주소와 수신자의 이메일 주소를 제공한다.
  3. 핸드셰이킹을 통해 SMTP 클라이언트와 서버가 서로 자신의 소개를 마치고 나면, 클라이언트는 메시지를 보낸다. 이때 SMTP는 TCP의 신뢰할 수 있는 데이터 전송 서비스를 이용한다.
  4. 만약 클라이언트에 해당 서버로 보낼 다른 메시지들이 남아있다면 같은 TCP 연결을 이용해 위 과정을 반복하고, 그렇지 않다면 연결을 끊어달라고 TCP에 알린다.

SMTP 클라이언트와 서버 사이의 메시지 교환을 나타내는 아래의 대화록을 보자. 서버의 호스트명은 hamburger.edu, 클라이언트의 호스트명은 crepes.fr이다. S: 는 서버가 자신의 TCP 소켓으로 보내는 메시지, C: 는 클라이언트가 자신의 TCP 소켓으로 보내는 메시지다. 이미 클라이언트와 서버 사이의 TCP 연결이 이루어졌음을 가정한다.

S:  220 hamburger.edu
C:  HELO crepes.fr
S:  250 Hello crepes.fr, pleased to meet you
C:  MAIL FROM: <alice@crepes.fr>
S:  250 alice@crepes.fr ... Sender ok
C:  RCPT TO: <bob@hamburger.edu>
S:  250 bob@hamburger.edu ... Recipient ok
C:  DATA
S:  354 Enter mail, end with ”.” on a line by itself
C:  Do you like ketchup?
C:  How about pickles?
C:  .
S:  250 Message accepted for delivery
C:  QUIT
S:  221 hamburger.edu closing connection

위 대화록에서 클라이언트는 서버에 "Do you like ketchup? How about pickles?"라는 메시지를 보내고 있고, 또한 클라이언트가 HELO, MAIL FROM, RCPT TO, DATA, QUIT의 다섯 커맨드를 사용하고 있음을 볼 수 있다. 또 마지막에 마침표 하나(.)도 볼 수 있는데, 이는 서버에 메시지의 끝을 알려주기 위함이다. 아스키 코드로 본다면, 각 메시지의 끝에는 CRLF도 붙어 있다.

서버는 각 커맨드에 대해 답을 하는데, 이 응답에는 답장 코드와 그에 대한 설명이 포함되어 있다.

SMTP는 지속 연결을 사용한다. 만약 송신 메일 서버에 수신 메일 서버로 보낼 메시지가 여러 개 있다면, 이 메시지들은 하나의 TCP 연결을 통해 보내진다. 각 메시지 마다 클라이언트는 새로운 MAIL FROM:을 통해 프로세스를 시작하며, 모든 메시지가 보내져 남은 메시지가 없는 경우에만 QUIT을 보낸다.

2. Comparison with HTTP

SMTP와 HTTP는 모두 파일을 한 호스트에서 다른 호스트를 보낼 때 쓰이며, 파일 전송 시 모두 지속 연결을 사용한다는 공통점이 있다. 하지만 두 프로토콜 사이에는 중요한 차이점들이 있다.

  1. HTTP는 pull 프로토콜인 반면, SMTP는 push 프로토콜이다.
    • HTTP는 웹 서버에서 특정 정보를 가져오고 싶을 때 사용한다. 이때 TCP 연결은 파일을 받고 싶어하는 쪽에서 시작한다.
    • SMTP는 송신 서버에서 수신 서버로 메일을 내보내고자 할 때 쓰인다. 이때 TCP 연결은 파일을 보내고 싶어하는 쪽에서 시작한다.
  2. SMTP에서는 메시지가 (바디를 포함해) 7-비트 아스키 형식이어야 한다. 만약 7-비트 아스키가 아닌 문자나 바이너리 데이터가 포함된 경우, 메시지는 7-비트 아스키로 인코딩되어야 한다. 한편 HTTP에는 이런 제한이 없다.
  3. 문서에 여러 텍스트와 이미지가 포함되는 경우, HTTP는 각 객체를 자신의 HTTP 응답 메시지에 캡슐화한다. 따라서 HTTP에서 문서에 포함된 여러 이미지들을 가져오려면 여러 번 요청과 응답을 보내야 한다. 하지만 SMTP의 경우 메시지에 포함된 객체를 모두 메시지에 넣어 한 번에 보낸다.

3. Mail Message Formats

한 사람에게서 다른 사람에게로 이메일 메시지를 보낼 때, 메시지 바디 앞에 주변 정보들을 담은 헤더가 있어야 한다. 헤더 라인과 메시지 바디는 CRLF로 구분되며, HTTP와 마찬가지로 각 헤더 라인에는 키워드: 값 형식의 텍스트가 들어있다.

각 헤더에는 From: 헤더 라인과 To: 헤더 라인이 있어야 하고, Subject: 헤더 라인이 있을 수도 있다. 다만 이 헤더 라인들은 앞서 봤던 SMTP 커맨드들과는 다르다. 이 커맨드들은 SMTP 핸드셰이킹을 위해 쓰이는 것들이고, 이 헤더 라인들은 메일 메시지 자체를 설명하기 위해 쓰이는 것들이다.

전형적인 메시지 헤더는 다음과 같다.

From: alice@crepes.fr
To: bob@hamburger.edu
Subject: Searching for the meaning of life.

메시지 헤더 뒤에는 빈 줄이 있고, 그 뒤에는 ASCII 메시지 바디가 뒤따른다.

4. Mail Access Protocols

Alice의 메일 서버에서 Bob의 메일 서버로 메시지가 전달되면, 이 메시지는 Bob의 메일 박스에 들어간다. 이 메일 박스에 들어있는 메시지를 읽으려면 어떻게 해야할까?

1990년대 초까지, 사용자는 메일 박스에 있는 메시지를 읽기 위해, 서버 호스트에 로그인 하고 거기서 돌아가는 메일 리더를 실행해야 했다. 하지만 오늘날 메일 접근은 클라이언트-서버 구조를 사용한다. 사용자는 자신의 종단 시스템에서 실행되는 클라이언트를 통해 이메일을 읽는다.

수신자가 자신의 사용자 에이전트를 로컬 PC에서 실행한다면, 메일 서버도 마찬가지로 로컬 PC에다 두는 게 자연스러워 보인다. 이때 송신자의 메일 서버는 수신자의 PC와 직접 대화를 하게 될 것이다. 하지만 이러한 방식에는 몇 가지 문제점들이 있다. 만약 수신자의 메일 서버가 로컬 PC에 위치한다면, 수신자의 PC는 언제 도착할지 모르는 새 메일을 받기 위해 항상 켜져 있어야 하고, 또 인터넷에도 연결되어 있어야 한다.

때문에 보통 사용자는 사용자 에이전트는 로컬 PC에서 실행하고, 항상 켜져 있는 공유 메일 서버에 저장된 메일박스에 접근함으로써 자신이 받을 메일을 가져 온다. 이 메일 서버는 다른 사용자들과 공유되며, 보통 사용자의 ISP를 통해 유지된다.

다시 Alice에게서 Bob으로 이메일 메시지를 보낸다고 해보자. 이때 Alice의 메시지는 어떻게든 Bob의 메일 서버에 저장되어야 한다. Alice의 사용자 에이전트에서 Bob의 메일 서버로, SMTP를 이용해 직접 메시지를 보낼 수도 있다. 하지만 보통 송신자의 사용자 에이전트는 수신자 메일 서버와 직접 대화하지 안흔다. 그 대신 Alice의 사용자 에이전트는 SMTP를 이용해 자신의 메일 서버로 이메일 메시지를 푸시하고, Alice의 메일 서버도 SMTP를 이용해 이메일 메시지를 Bob의 메일 서버로 중계한다. 왜 굳이 이렇게 두 단계를 거치게 만들었을까?

가장 큰 이유는, 송신자의 사용자 에이전트에서 수신사의 메일 서버로 직접 메시지를 보내는 경우 , 수신자의 메일 서버가 어떤 이유로 다운되어 있다면 해당 수신자에게 메일을 보낼 수 없기 때문이다. Alice의 메시지를 우선 메일 서버에 담아 둔다면, Bob에게 메시지를 지속적으로 다시 보내 위와 같은 경우를 해결할 수 있다.

그렇다면 수신자 Bob은 어떻게 자신의 사용자 에이전트를 로컬 PC에서 실행하면서, Bob의 ISP에 위치한 메일 서버에서 자신의 메시지를 가져올 수 있을까? Bob의 사용자 에이전트는 메시지를 가져오기 위해 SMTP를 사용할 수 없다. 메시지를 가져오는 것은 pull이고, SMTP는 push 프로토콜이기 때문이다. 이를 위해서는 Bob의 메일 서버에서 로컬 PC로 메시지를 전송하기 위한 특별한 메일 접근 프로토콜이 필요하다.

POP3

POP3는 아주 간단한 메일 접근 프로토콜인데, 너무 단순한 나머지 기능적으로도 제한이 있다. POP3는 사용자 에이전트가 포트 110으로 메일 서버와 TCP 연결을 열 때 시작한다. TCP 연결이 되고 나면 POP3는 authorization, transaction, update의 세 단계로 진행된다.

  1. Authorization 단계에서 사용자 에이전트는 사용자 인증을 위한 사용자명과 패스워드를 전달한다.
  2. Transaction 단계에서 사용자 에이전트는 메시지를 탐색한다. 여기서 사용자 에이전트는 메시지에 삭제 마크를 달거나, 삭제 마크를 지우거나, 메일 통계도 얻을 수 있다.
  3. Update 단계는 클라이언트가 quit 커맨드를 보내 POP3 세션을 마치고 나면 일어난다. 여기서 메일 서버는 삭제하도록 마크된 메시지들을 삭제한다.

POP3 transaction에서, 사용자는 커맨드를 보내고, 서버는 각 커맨드에 대한 응답을 보낸다. 여기에는 두 가지 응답이 있을 수 있는데, +OK-ERR다.

Authorization 단계에는 user <username>pass <password>의 두 커맨드가 있다.

telnet mailServer 110
+OK POP3 server ready
user bob
+OK
pass hungry
+OK user successfully logged on

만약 커맨드를 잘못 입력하면 POP3 서버는 -ERR 메시지로 응답하게 될 것이다.

Transaction 단계를 보자. POP3를 사용하는 사용자 에이전트는 "download and delete" 모드와 "download and keep" 모드 중 하나를 선택할 수 있다. POP3 사용자 에이전트가 만드는 커맨드 시퀀스는 사용자 에이전트가 이 두 모드 중 어떤 모드를 선택하고 있는지에 따라 달라진다.

Download-and-delete 모드에서 사용자 에이전트는 list, retr, dele 커맨드를 보낸다. 아래 대화록에서 C: 는 사용자 에이전트, S: 는 메일 서버다.

C: list
S: 1 498
S: 2 912
S: .
C: retr 1
S: (blah blah ...
S: .................
S: ..........blah)
S: .
C: dele 1
C: retr 2
S: (blah blah ...
S: .................
S: ..........blah)
S: .
C: dele 2
C: quit
S: +OK POP3 server signing off

사용자 에이전트는 우선 메일 서버에 저장된 각 메시지의 사이즈를 리스트해달라고 묻는다. 이후 사용자 에이전트는 각 메시지를 탐색하고 서버로부터 삭제한다. 마지막 quit 커맨드 이후 POP3 서버는 업데이트 단계로 넘어가 메시지 1, 2를 메일박스에서 삭제한다.

Download-and-delete 모드를 사용하는 경우, 사용자는 같은 메시지를 다른 기기에서 받을 수 없게 된다. 예컨대 Bob이 PC에서 위의 1번 메시지를 읽었다고 해보자. 이 메시지는 Bob의 메일 박스에서 사라져서 다른 기기에서는 읽을 수 없게 된다. 이와 달리 Download-and-keep 모드를 이용하면, 사용자는 메시지를 다운로드 한 후 메일 서버에 해당 메시지를 그대로 남겨 놓는다. 이 경우 Bob은 메시지를 다른 기기에서도 읽을 수 있게 된다.

사용자 에이전트와 메일 서버 사이의 POP3 세션 동안, POP3 서버는 어떤 사용자 메시지가 삭제되도록 마크됐는지 등의 상태 정보를 유지한다. 하지만 이 상태 정보는 POP3 세션 간에는 유지되지 않는다.

POP3 접근을 이용하면, Bob은 메시지를 로컬 머신으로 다운로드 한 후, 메일 폴더를 만들어 다운로드 한 메시지를 폴더로 이동시킬 수 있다. Bob은 다운로드한 메시지를 삭제하거나, 이동하거나, 탐색할 수 있지만, 이런 동작들은 모두 Bob의 로컬 머신에서만 일어난다. 그렇기 때문에 POP3는 폴더 계층 구조를 어떤 컴퓨터에서든 접근할 수 있는 원격 서버에서도 유지하고 싶은 사용자에게는 좋은 선택지가 되지 못한다.

IMAP

위와 같은 문제를 해결하기 위해 만들어진 게 IMAP이다. IMAP은 POP3와 같은 메시지 접근 프로토콜인데, POP3보다 더 많은 기능들을 제공하는 대신 조금 더 복잡하다.

IMAP 서버는 메시지를 폴더로 관리한다. 메시지는 서버에 도착하고 나서 수신자의 INBOX 폴더에 들어간다. 수신자는 메시지를 새로운, 사용자가 생성한 폴더로 이동시킬 수도 있고, 메시지를 삭제할 수도 있으며, IMAP 프로토콜은 이런 동작들을 위한 여러 커맨드들도 제공한다. IMAP은 또한 원격 폴더에서 특정 기준에 맞는 메시지들을 검색하기 위한 커맨드도 제공한다.

IMAP의 경우, 사용자 에이전트가 메시지의 컴포넌트를 얻을 수 있도록하는 커맨드도 제공한다. 예를 들어 사용자 에이전트는 메시지의 헤더를 얻을 수도 있고, 멀티파트 MIME 메시지의 한 파트만을 얻을 수도 있다. 이러한 기능은 사용자 에이전트와 메일 서버 사이에 저-대역폭 연결만이 가능한 경우 유용하게 쓰일 수 있다.

Web-Based E-mail

오늘날에는 많은 사람들이 웹 브라우저를 통해 이메일에 접근한다. 이 서비스를 이용하는 경우, 사용자 에이전트는 웹 브라우저가 되고, 사용자는 HTTP를 통해 원격 메일 박스와 통신한다. 수신자가 메일 박스의 메시지에 접근하고 싶을 때, 이메일 메시지는 POP3나 IMAP 프로토콜이 아니라 HTTP를 통해 밥의 브라우저로 메시지를 전송한다. 송신자가 이메일 메시지를 보낼 때에도 마찬가지로, 이메일 메시지는 HTTP를 통해 사용자 브라우저에서 메일 서버로 전송된다. 다만 송신자 메일 서버에서 수신자 메일 서버로 메시지를 보낼 때는 여전히 SMTP를 사용한다.

0개의 댓글