본문 바로가기

app/python

왜 python의 http 헤더 파서는 email 클래스에 있는가??!!

클래스들은 나름의 이유로 클래스끼리의 묶임이나 폴더(패키지)에 상주합니다.

 

파이썬 코어 소스를 보면서 그중에서 가장 이해가 되지 않는 것은 http 헤더 파서를 email.parser를 통해 동작한다는 것입니다.

(이외에도 http 파서를 하기 위해 email.message, email.feedparser, email.utils 등을 사용합니다.)

 

http server를 실행했을 때의 동작 흐름입니다. email의 여러 함수들을 호출합니다. 

 

왜 http.header, http 등의 독립적인 클래스가 아닌 email 클래스에 있는 것일까요??

(parser는 클래스는 regex(정규표현식)를 위해 클래스가 존재합니다. 또한 이 글에서는 헤더에 관한 파서만을 생각했습니다. )

 

 

 

python email클래스는 무슨 일을 하는가?

Python Email 패키지는 MIME 및 기타를 포함하는 이메일 메시지를 관리하기 위한 라이브러리입니다. 가장 중요한 기능은 전자 메일의 내부 객체 모델 표현에서 전자 메일 메시지의 구문 분석 및 생성을 분리한다는 것입니다. 한마디로  정말 email 파싱 및 관리하는 패키지입니다. 

 

그렇다면 email의 구조는 어떻게 되어 있을까요? 이것은 RFC 822에  서술되어 있습니다.  

  1. 60년대에도 전자우편(더 정확히는 전자 문서에 가깝습니다.)은 있었으나, 최초의 전자메일은 RFC 196(1971년)에서 소개되었습니다.
  2. RFC 733(1977년)에서 email 최초 표준이 정해졌습니다.
  3. 개정안은 RFC 822 (1982년)에 정립됩니다.
  4. 우리가 쓰는 SMTP와 RFC 822 형식이 다시 RFC 2822(2001년)에서 다시 정의됩니다. 

번외

python2 버전부터 email 클래스는 현재의(3.8.*) 버전과 기능이 거의 동일합니다. 

python3.5부터 추가된 Email.headerregistry, email.contentmanager를 제외한 모든 기능이 동일합니다. 이는 아래 나올 MIME의 기능 확장 때문에 추가된 것으로 보입니다. 


 

RFC 822  Strandrad for ARPA Internet Text Messages

https://www.w3.org/Protocols/rfc822/

(ARPA는 방위 고등 연구 계획국은 미국 국방성의 연구, 개발 부문을 담당하고 있으며 인터넷의 원형인 ARPANET을 개발한 곳입니다. 한마디로 연구기관에서 쓰던 포맷이 세계 공식이 되어버렸습니다.)

 

RFC 822 중요한 점은 envelope / header / body의 정의입니다. 

가장 상위단에 envelope은 전송 과정에서 쓰이는 부분이며, header부터 body까지 실제 사용자에게 보이는 메시지입니다. 

 

최초의 메시지 정의는 아래 그림과 같습니다. 

envelope header의 내용에 대부분이 포함되어  이후 RFC 2822에서 envelope의 부분이 표준에서 제외됩니다. 

 


번외

재미있는 것은 파이썬에 rfc822 클래스가 존재했었습니다. python2.3 버전까지 사용 가능했었습니다. (이후 호환성 문제로 python3으로 넘어오면서 폐기되었습니다.) rfc822 클래스는 이름 그대로 메일 메시지를 나타내는 클래스를 정의했으며,  이메일 파싱을 위한 클래스였습니다. 심지어 정의는 rfc2822 메일 헤더 구분 분석이라 명명하였으나 이름은 rfc822로 되어 있습니다. (이런 것을 보면 python3의 구조가 참 잘 잡혔다는 생각도 듭니다. python2는 중구난방으로 된 클래스가 몇몇 보입니다. )


 

다시 RFC822의 문서로 넘어오면 그 당시 사람들은 "왜 텍스트만 보낼 수 있지? 다른 것도 보내고 싶어!라는 생각을 했습니다.

불행히도 ASCII 텍스트는 간단한 메모 및 기타 짧은 메시지를 작성하는 데 유용하지만 다른 유형의 통신을 지원할 수 있는 유연성은 없습니다. 사람들은 ASCII 이외의 문자 집합을 사용하여 전자 메일에서 멀티미디어 정보, 임의의 파일 및 메시지를 언어로 전달할 수 있도록 MIME (Multipurpose Internet Mail Extensions) 표준이 만들어졌습니다.

 

 

 

MIME(Multipurpose Internet Mail Extensions)

다목적 인터넷 메일 확장이란 뜻으로 전자우편의 데이터 형식을 정의한 표준 포맷입니다.

 

전자우편은 7비트 ASCII 코드를 사용하여 전송되기 때문에 문자 데이터 이외의 바이너리 데이터(이미지, 동영상, MS 워드 같은 문서 등)를 전송할 수 없었습니다. 때문에 여러 멀티미디어 데이터들의 바이너리 데이터를 ASCII코드로 변환하는 방법(인코딩)과 미디어 종류를 MIME 타입 목록으로 정의하였고, MIME 사양에 따라 멀티미디어 파일의 데이터를  ASCII 데이터로 변환 후 전송하였습니다.

 

이때 송신 측에서는 전송 ASCII 데이터가 원래는 어떤 형식의 파일이었는지 MIME 타입을 기록하여 전송하는데 수신 측에서는 해당 MIME 타입을 참고하여 수신한 ASCII 데이터를 원래의 멀티미디어 바이너리로 변환하여 해석합니다.

 

바로 헤더에 다음의 타입들을 추가하여 보냅니다. (최초의 MIME의 형식입니다.)

  • MIME-Version
  • Content-Type
  • Content-Transfer-Encoding
  • Content-ID
  • Content-Description

이렇게 하면 ASCII 데이터만 전송할 수 있는 인터넷 메일의 한계를 극복함과 동시에 여러 가지 타입의 멀티미디어 데이터를 주고받을 수 있는 것입니다.

 

위의 형식들은 어디서 많이 이름이 있습니다. 그렇습니다!! http의 헤더에 들어가는 형식입니다!!

 

MIME은 메일 전용으로 개발되었지만 인코딩 및 데이터 표현 방법은 다른 응용 프로그램 프로토콜에서도 채택된 것으로 매우 유명합니다. 가장 잘 알려진 것 중 하나는 HTTP (HyperText Transfer Protocol)로 , 전송되는 데이터의 특성을 나타내는 MIME 헤더를 사용합니다. 실제로 MIME의 일부 요소는 전자 메일이 아닌 HTTP 또는 다른 프로토콜에서 사용하기 위해 개발되었습니다. 그러나 HTTP는 MIME 일부 요소만 사용합니다. 중요한 차이점이 있으며 HTTP 메시지는 MIME 호환이 아닙니다.

 


번외 

MIME에 대해서 상세히 알고 싶으시면 아래의 문서를 참고하시면 됩니다. 

 

RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies

 - 인터넷 메시지 본문 형식 MIME의 기본 개념과 MIME 메시지 구조를 설명합니다.

 

RFC 2046 Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types

- MIME 미디어 유형 및 하위 유형의 개념을 설명하고 인코딩이 MIME 표준에 정의된 일부 미디어 유형을 설명합니다.

 

RFC 2047 MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text

- 비 ASCII 텍스트를 전달하기 위해 RFC 822 헤더를 수정하는 방법을 설명합니다.

 

RFC 2048 Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures

- MIME과 함께 사용할 추가 미디어 유형을 등록하는 방법에 대해 논의합니다.

 

RFC 2049 Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples

- 추가 구현 정보 및 MIME 사용 방법에 대한 예를 제공합니다.


 

다시 Python email 클래스 

이메일 및 MIME 처리 패키지 클래스입니다. 그렇습니다. MIME 관련 클래스는 email 클래스에 종속되어 있습니다. 따라서!!

 

결론 (이라 쓰며 의식의 흐름)

 

최초의 email 정의 -> 다른 파일도 보내고 싶어 -> MIME 정의 -> MIME 좋은데? HTTP에도 잘 맞을 거 같아 -> HTTP에서 MIME요소 사용. 

 

결국 같은 헤더의 사용으로 python 클래스 구조가 결정된 것입니다!! 끝!!

 

 

 

엉뚱한 생각에서 여기까지 조사하느라 힘든 주말을 보낸 나에게 과자를 선물하며 마칩니다.

또한 그동안 당연히 http가 이메일보다 먼저 생겼다고 생각한 나를 반성합니다…

 

 

 

 

참고사항

 

https://docs.microsoft.com/ko-kr/previous-versions/office/developer/exchange-server-2010/aa493918(v=exchg.140)

https://www.slideshare.net/jjuakim/internet-message-protocol-rfc822-rfc-2822

https://docs.microsoft.com/ko-kr/previous-versions/office/developer/exchange-server-2010/aa493906(v=exchg.140)

https://docs.python.org/3.5/library/email.html#module-email

https://dololak.tistory.com/130

http://www.tcpipguide.com/free/t_TCPIPElectronicMailSystemConceptsandProtocolsRFC82.htm