# `email.generator`: MIME 문서 생성

소스 코드: Lib/email/generator.py

가장 일반적인 작업 중 하나는 메시지 객체 구조로 표현되는 전자 우편 메시지의 평평한 (직렬화된) 버전을 생성하는 것입니다. `smtplib.SMTP.sendmail()`이나 `nntplib` 모듈을 통해 메시지를 보내거나 콘솔에서 메시지를 인쇄하려면 이 작업을 수행해야 합니다. 메시지 객체 구조를 취하고 직렬화된 표현을 생성하는 것은 제너레이터 클래스의 작업입니다.

`email.parser` 모듈과 마찬가지로 번들 제너레이터의 기능으로 제한되지 않습니다; 처음부터 직접 작성할 수 있습니다. 그러나 번들 제너레이터는 표준 호환 방식으로 대부분 전자 우편을 생성하는 방법을 알고 있고, MIME과 비 MIME 전자 우편 메시지를 잘 처리하며, 변환 없는 같은 `policy`가 사용된다고 가정할 때 바이트열 지향 구문 분석과 생성 연산이 역이 되도록 설계되었습니다. 즉, `BytesParser` 클래스로 직렬화된 바이트 스트림을 구문 분석한 다음, `BytesGenerator`를 사용하여 직렬화된 바이트 스트림을 재생성하면 입력과 동일한 출력이 생성됩니다 1. (반면에, 프로그램에서 구축한 `EmailMessage`에 제너레이터를 사용하면 기본값이 채워지기 때문에 `EmailMessage` 객체가 변경될 수 있습니다.)

`Generator` 클래스를 사용하면 메시지를 (바이너리가 아닌) 텍스트 직렬화 표현으로 펼칠 수 있지만, 유니코드는 바이너리 데이터를 직접 표현할 수 없기 때문에, “8비트 클린”하지 않은 채널을 통한 전송을 위한 전자 우편 메시지를 인코딩하기 위한 표준 전자 우편 RFC 콘텐츠 전송 인코딩(Content Transfer Encoding) 기술을 사용하여 메시지를 ASCII 문자만 포함된 것으로 변환해야 합니다.

SMIME 서명된 메시지의 재현성 있는 처리를 위해 `Generator`는 `multipart/signed` 유형의 메시지 파트와 모든 서브 부분에 대해 헤더 접기를 비활성화합니다.

class `email.generator.``BytesGenerator`(outfp, mangle_from_=None, maxheaderlen=None, *, policy=None)

  `flatten()` 메서드에 제공된 모든 메시지나 `write()` 메서드에 제공된 모든 서로게이트 이스케이프 인코딩된 텍스트를 파일류 객체 outfp에 쓰는 `BytesGenerator` 객체를 반환합니다. outfp는 바이너리 데이터를 받아들이는 `write` 메서드를 지원해야 합니다.

  선택적인 mangle_from_이 `True`인 경우, 정확한 문자열 `"From "`으로 시작하는(즉 줄의 시작에 `From`이 오고 스페이스가 뒤따르는) 본문의 모든 줄 앞에 `>` 문자를 넣습니다. mangle_from_의 기본값은 policy의 `mangle_from_` 설정값입니다 (`compat32` 정책의 경우 `True`, 다른 모든 경우 `False`입니다). mangle_from_은 메시지가 유닉스 mbox 형식으로 저장될 때 사용하기 위한 것입니다 (`mailbox`와 WHY THE CONTENT-LENGTH FORMAT IS BAD를 참조하십시오).

  maxheaderlen이 `None`이 아니면, maxheaderlen보다 긴 헤더 줄을 다시 접거나, `0`이면 헤더를 다시 접지 않습니다. manheaderlen이 `None`(기본값)이면, policy 설정에 따라 헤더와 기타 메시지 줄을 줄 바꿈 합니다.

  policy가 지정되면, 해당 정책을 사용하여 메시지 생성을 제어합니다. policy가 `None`(기본값)이면 `flatten`에 전달된 `Message`나 `EmailMessage` 객체와 연관된 정책을 사용하여 메시지 생성을 제어합니다. policy가 제어하는 것에 대한 자세한 내용은 `email.policy`를 참조하십시오.

  버전 3.2에 추가.

  버전 3.3에서 변경: policy 키워드를 추가했습니다.

  버전 3.6에서 변경: mangle_from_과 maxheaderlen 매개 변수의 기본 동작은 정책을 따르는 것입니다.

  `flatten`(msg, unixfrom=False, linesep=None)

    msg를 루트로 하는 메시지 객체 구조의 텍스트 표현을 `BytesGenerator` 인스턴스가 만들어질 때 지정된 출력 파일에 인쇄합니다.

    `policy` 옵션 `cte_type`이 `8bit`(기본값)이면, 하이 비트가 설정된 바이트들이 원본에서와같이 재생성되도록 출력이 수정되지 않은 원본 구문 분석된 메시지의 헤더를 복사하고, 비 ASCII Content-Transfer-Encoding을 이것을 갖는 모든 본문 파트에서 보존합니다. `cte_type`이 `7bit`이면, 하이 비트가 설정된 바이트들을 ASCII 호환 Content-Transfer-Encoding을 사용하여 필요에 따라 변환합니다. 즉, 비 ASCII Content-Transfer-Encoding(Content-Transfer-Encoding: 8bit)을 갖는 파트를 ASCII 호환 Content-Transfer-Encoding으로 변환하고, 헤더에 있는 RFC 유효하지 않은 비 ASCII 바이트를 MIME `unknown-8bit` 문자 집합을 사용하여 인코딩하여, RFC 호환되게 만듭니다.

    unixfrom이 `True`이면, 루트 메시지 객체의 첫 번째 RFC 5322 헤더 앞에 유닉스 mailbox 형식(`mailbox`를 참조하십시오)에서 사용되는 봉투 헤더 구분자를 인쇄합니다. 루트 객체에 봉투 헤더가 없으면, 표준 헤더를 만듭니다. 기본값은 `False`입니다. 서브 파트의 경우 봉투 헤더가 인쇄되지 않음에 유의하십시오.

    linesep이 `None`이 아니면, 펼쳐진 메시지의 모든 줄 사이의 구분자 문자로 사용합니다. linesep이 `None`(기본값)이면, policy에 지정된 값을 사용합니다.

  `clone`(fp)

    정확히 같은 옵션 설정이고 fp를 새 outfp로 사용하는, 이 `BytesGenerator` 인스턴스의 독립 클론을 반환합니다.

  `write`(s)

    `ASCII` 코덱과 `surrogateescape` 에러 처리기를 사용하여 s를 인코딩하고, `BytesGenerator`의 생성자에 전달된 outfp의 write 메서드로 전달합니다.

편의상, `EmailMessage`는 `as_bytes()` 메서드와 `bytes(aMessage)`(일명 `__bytes__()`)를 제공하여 메시지 객체의 직렬화된 바이너리 표현 생성을 단순화합니다. 자세한 내용은 `email.message`를 참조하십시오.

문자열은 바이너리 데이터를 나타낼 수 없어서, `Generator` 클래스는 펼쳐지는 모든 메시지의 바이너리 데이터를 ASCII 호환 Content-Transfer_Encoding으로 변환하여 ASCII 호환 형식으로 변환해야 합니다. 전자 우편 RFC의 용어를 사용하면, 이를 “8비트 클린”이 아닌 I/O 스트림으로 직렬화하는 `Generator`로 생각할 수 있습니다. 즉, 대부분 응용 프로그램은 `Generator`가 아닌 `BytesGenerator`를 사용하려고 합니다.

class `email.generator.``Generator`(outfp, mangle_from_=None, maxheaderlen=None, *, policy=None)

  `flatten()` 메서드에 제공된 모든 메시지나 `write()` 메서드에 제공된 텍스트를 파일류 객체 outfp에 쓰는 `Generator` 객체를 반환합니다. outfp는 문자열 데이터를 받아들이는 `write` 메서드를 지원해야 합니다.

  선택적인 mangle_from_이 `True`인 경우, 정확한 문자열 `"From "`으로 시작하는(즉 줄의 시작에 `From`이 오고 스페이스가 뒤따르는) 본문의 모든 줄 앞에 `>` 문자를 넣습니다. mangle_from_의 기본값은 policy의 `mangle_from_` 설정값입니다 (`compat32` 정책의 경우 `True`, 다른 모든 경우 `False`입니다). mangle_from_은 메시지가 유닉스 mbox 형식으로 저장될 때 사용하기 위한 것입니다 (`mailbox`와 WHY THE CONTENT-LENGTH FORMAT IS BAD를 참조하십시오).

  maxheaderlen이 `None`이 아니면, maxheaderlen보다 긴 헤더 줄을 다시 접거나, `0`이면 헤더를 다시 접지 않습니다. manheaderlen이 `None`(기본값)이면, policy 설정에 따라 헤더와 기타 메시지 줄을 줄 바꿈 합니다.

  policy가 지정되면, 해당 정책을 사용하여 메시지 생성을 제어합니다. policy가 `None`(기본값)이면 `flatten`에 전달된 `Message`나 `EmailMessage` 객체와 연관된 정책을 사용하여 메시지 생성을 제어합니다. policy가 제어하는 것에 대한 자세한 내용은 `email.policy`를 참조하십시오.

  버전 3.3에서 변경: policy 키워드를 추가했습니다.

  버전 3.6에서 변경: mangle_from_과 maxheaderlen 매개 변수의 기본 동작은 정책을 따르는 것입니다.

  `flatten`(msg, unixfrom=False, linesep=None)

    msg를 루트로 하는 메시지 객체 구조의 텍스트 표현을 `Generator` 인스턴스가 만들어질 때 지정된 출력 파일에 인쇄합니다.

    `policy` 옵션 `cte_type`이 `8bit`이면, 옵션이 `7bit`로 설정된 것처럼 메시지를 생성합니다. (문자열은 비 ASCII 바이트를 나타낼 수 없기 때문에 필요합니다.) 하이 비트가 설정된 모든 바이트를 ASCII 호환 Content-Transfer-Encoding을 사용하여 필요에 따라 변환합니다. 즉, 비 ASCII Content-Transfer-Encoding(Content-Transfer-Encoding: 8bit)을 갖는 파트를 ASCII 호환 Content-Transfer-Encoding으로 변환하고, 헤더에 있는 RFC 유효하지 않은 비 ASCII 바이트를 MIME `unknown-8bit` 문자 집합을 사용하여 인코딩하여, RFC 호환되게 만듭니다.

    unixfrom이 `True`이면, 루트 메시지 객체의 첫 번째 RFC 5322 헤더 앞에 유닉스 mailbox 형식(`mailbox`를 참조하십시오)에서 사용되는 봉투 헤더 구분자를 인쇄합니다. 루트 객체에 봉투 헤더가 없으면, 표준 헤더를 만듭니다. 기본값은 `False`입니다. 서브 파트의 경우 봉투 헤더가 인쇄되지 않음에 유의하십시오.

    linesep이 `None`이 아니면, 펼쳐진 메시지의 모든 줄 사이의 구분자 문자로 사용합니다. linesep이 `None`(기본값)이면, policy에 지정된 값을 사용합니다.

    버전 3.2에서 변경: `8bit` 메시지 본문을 다시 인코딩하기 위한 지원과 linesep 인자가 추가되었습니다.

  `clone`(fp)

    정확히 같은 옵션을 갖고 fp를 새 outfp로 사용하는, 이 `Generator` 인스턴스의 독립 클론을 반환합니다.

  `write`(s)

    `Generator`의 생성자에 전달된 outfp의 write 메서드로 s를 씁니다. 이것은 `print()` 함수에서 사용될 `Generator` 인스턴스를 위해 딱 필요한 만큼의 파일류 API를 제공합니다.

편의상, `EmailMessage`는 `as_string()` 메서드와 `str(aMessage)`(일명 `__str__()`)를 제공하여 메시지 객체의 포맷된 문자열 표현 생성을 단순화합니다. 자세한 내용은 `email.message`를 참조하십시오.

`email.generator` 모듈은 또한 파생 클래스인 `DecodedGenerator`를 제공하는데, `Generator` 베이스 클래스와 유사하지만, 비 text 파트는 직렬화되지 않고, 대신에 파트에 대한 정보로 채워진 템플릿에서 파생된 문자열로 출력 스트림에 표시됩니다.

class `email.generator.``DecodedGenerator`(outfp, mangle_from_=None, maxheaderlen=None, fmt=None, *, policy=None)

  `Generator`와 같이 작동하지만, `Generator.flatten()`에 전달된 메시지의 서브 파트에 대해, 서브 파트가 메인 유형이 text이면, 서브 파트의 디코딩된 페이 로드를 인쇄하고, 메인 유형이 text가 아니면, 그것을 인쇄하지 않고 파트 정보를 사용하여 문자열 fmt를 채운 후에 그 문자열을 인쇄합니다.

  fmt를 채우기 위해, `fmt % part_info`를 실행하는데, 여기서 `part_info`는 다음 키와 값으로 구성된 딕셔너리입니다:

  - `type` – text가 아닌 파트의 전체 MIME 유형

  - `maintype` – text가 아닌 파트의 메인 MIME 유형

  - `subtype` – text가 아닌 파트의 서브 MIME 유형

  - `filename` – text가 아닌 파트의 파일명

  - `description` – text가 아닌 파트와 관련된 설명

  - `encoding` – text가 아닌 파트의 콘텐츠 전송 인코딩(Content transfer encoding)

  fmt가 `None`이면, 다음 기본 fmt를 사용합니다:

  > “[Non-text (%(type)s) part of message omitted, filename %(filename)s]”

  선택적 _mangle_from_ 및 maxheaderlen은 `Generator` 베이스 클래스와 같습니다.

각주

1

  이 문장은 `unixfrom`에 적절한 설정을 사용하고, 자동 조정을 요구하는 `policy` 설정이 없다고 가정합니다 (예를 들어, `refold_source`는 `none`이어야 하며, 이는 기본값이 아닙니다). 메시지가 RFC 표준을 준수하지 않으면 때때로 구문 분석 에러 복구 중에 정확한 원본 텍스트에 대한 정보가 손실되므로 100% 사실이 아니기도 합니다. 가능하다면 이 후자의 경계 사례를 해결하는 것이 목표입니다.