# `email.message.Message`: `compat32` API を使用した電子メールメッセージの表現

The `Message` class is very similar to the `EmailMessage` class, without the methods added by that class, and with the default behavior of certain other methods being slightly different. We also document here some methods that, while supported by the `EmailMessage` class, are not recommended unless you are dealing with legacy code.

The philosophy and structure of the two classes is otherwise the same.

This document describes the behavior under the default (for `Message`) policy `Compat32`. If you are going to use another policy, you should be using the `EmailMessage` class instead.

An email message consists of headers and a payload. Headers must be RFC 5322 style names and values, where the field name and value are separated by a colon. The colon is not part of either the field name or the field value. The payload may be a simple text message, or a binary object, or a structured sequence of sub-messages each with their own set of headers and their own payload. The latter type of payload is indicated by the message having a MIME type such as multipart/* or message/rfc822.

The conceptual model provided by a `Message` object is that of an ordered dictionary of headers with additional methods for accessing both specialized information from the headers, for accessing the payload, for generating a serialized version of the message, and for recursively walking over the object tree. Note that duplicate headers are supported but special methods must be used to access them.

The `Message` pseudo-dictionary is indexed by the header names, which must be ASCII values. The values of the dictionary are strings that are supposed to contain only ASCII characters; there is some special handling for non-ASCII input, but it doesn't always produce the correct results. Headers are stored and returned in case-preserving form, but field names are matched case-insensitively. There may also be a single envelope header, also known as the Unix-From header or the `From_` header. The payload is either a string or bytes, in the case of simple message objects, or a list of `Message` objects, for MIME container documents (e.g. multipart/* and message/rfc822).

`Message` クラスのメソッドは以下のとおりです:

class `email.message.``Message`(policy=compat32)

  If policy is specified (it must be an instance of a `policy` class) use the rules it specifies to update and serialize the representation of the message. If policy is not set, use the `compat32` policy, which maintains backward compatibility with the Python 3.2 version of the email package. For more information see the `policy` documentation.

  バージョン 3.3 で変更: キーワード引数 policy が追加されました。

  `as_string`(unixfrom=False, maxheaderlen=0, policy=None)

    Return the entire message flattened as a string. When optional unixfrom is true, the envelope header is included in the returned string. unixfrom defaults to `False`. For backward compatibility reasons, maxheaderlen defaults to `0`, so if you want a different value you must override it explicitly (the value specified for max_line_length in the policy will be ignored by this method). The policy argument may be used to override the default policy obtained from the message instance. This can be used to control some of the formatting produced by the method, since the specified policy will be passed to the `Generator`.

    もし、文字列への変換を完全に行うためにデフォルト値を埋める必要がある場合、メッセージのフラット化は `Message` の変更を引き起こす可能性があります (例えば、MIME の境界が生成される、変更される等)。

    Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does not do the mangling of lines that begin with `From` that is required by the Unix mbox format. For more flexibility, instantiate a `Generator` instance and use its `flatten()` method directly. For example:

        from io import StringIO
        from email.generator import Generator
        fp = StringIO()
        g = Generator(fp, mangle_from_=True, maxheaderlen=60)
        g.flatten(msg)
        text = fp.getvalue()

    If the message object contains binary data that is not encoded according to RFC standards, the non-compliant data will be replaced by unicode "unknown character" code points. (See also `as_bytes()` and `BytesGenerator`.)

    バージョン 3.4 で変更: policy キーワード引数が追加されました。

  `__str__`()

    `as_string()` と等価です。これにより `str(msg)` は書式化されたメッセージの文字列を作ります。

  `as_bytes`(unixfrom=False, policy=None)

    Return the entire message flattened as a bytes object. When optional unixfrom is true, the envelope header is included in the returned string. unixfrom defaults to `False`. The policy argument may be used to override the default policy obtained from the message instance. This can be used to control some of the formatting produced by the method, since the specified policy will be passed to the `BytesGenerator`.

    もし、文字列への変換を完全に行うためにデフォルト値を埋める必要がある場合、メッセージのフラット化は `Message` の変更を引き起こす可能性があります (例えば、MIME の境界が生成される、変更される等)。

    Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does not do the mangling of lines that begin with `From` that is required by the Unix mbox format. For more flexibility, instantiate a `BytesGenerator` instance and use its `flatten()` method directly. For example:

        from io import BytesIO
        from email.generator import BytesGenerator
        fp = BytesIO()
        g = BytesGenerator(fp, mangle_from_=True, maxheaderlen=60)
        g.flatten(msg)
        text = fp.getvalue()

    バージョン 3.4 で追加.

  `__bytes__`()

    `as_bytes()` と等価です。これにより `bytes(msg)` は書式化されたメッセージの bytes オブジェクトを作ります。

    バージョン 3.4 で追加.

  `is_multipart`()

    Return `True` if the message's payload is a list of sub-`Message` objects, otherwise return `False`. When `is_multipart()` returns `False`, the payload should be a string object (which might be a CTE encoded binary payload). (Note that `is_multipart()` returning `True` does not necessarily mean that "msg.get_content_maintype() == 'multipart'" will return the `True`. For example, `is_multipart` will return `True` when the `Message` is of type `message/rfc822`.)

  `set_unixfrom`(unixfrom)

    メッセージのエンベロープヘッダを unixfrom に設定します。これは文字列でなければなりません。

  `get_unixfrom`()

    メッセージのエンベロープヘッダを返します。エンベロープヘッダが設定されていない場合は `None` が返されます。

  `attach`(payload)

    与えられた payload を現在のペイロードに追加します。この時点でのペイロードは `None` か、あるいは `Message` オブジェクトのリストである必要があります。このメソッドの実行後、ペイロードは必ず `Message` オブジェクトのリストになります。ペイロードにスカラーオブジェクト (文字列など) を格納したい場合は、かわりに `set_payload()` を使ってください。

    This is a legacy method. On the `EmailMessage` class its functionality is replaced by `set_content()` and the related `make` and `add` methods.

  `get_payload`(i=None, decode=False)

    現在のペイロードへの参照を返します。これは `is_multipart()` が `True` の場合 `Message` オブジェクトのリストになり、 `is_multipart()` が `False` の場合は文字列になります。ペイロードがリストの場合、リストを変更することはそのメッセージのペイロードを変更することになります。

    オプション引数の i がある場合、 `is_multipart()` が `True` ならば `get_payload()` はペイロード中で 0 から数えて i 番目の要素を返します。 i が 0 より小さい場合、あるいはペイロードの個数以上の場合は `IndexError` が発生します。ペイロードが文字列 (つまり `is_multipart()` が `False`) にもかかわらず i が与えられたときは `TypeError` が発生します。

    Optional decode is a flag indicating whether the payload should be decoded or not, according to the Content-Transfer-Encoding header. When `True` and the message is not a multipart, the payload will be decoded if this header's value is `quoted-printable` or `base64`. If some other encoding is used, or Content-Transfer-Encoding header is missing, the payload is returned as-is (undecoded). In all cases the returned value is binary data. If the message is a multipart and the decode flag is `True`, then `None` is returned. If the payload is base64 and it was not perfectly formed (missing padding, characters outside the base64 alphabet), then an appropriate defect will be added to the message's defect property (`InvalidBase64PaddingDefect` or `InvalidBase64CharactersDefect`, respectively).

    When decode is `False` (the default) the body is returned as a string without decoding the Content-Transfer-Encoding. However, for a Content-Transfer-Encoding of 8bit, an attempt is made to decode the original bytes using the `charset` specified by the Content-Type header, using the `replace` error handler. If no `charset` is specified, or if the `charset` given is not recognized by the email package, the body is decoded using the default ASCII charset.

    This is a legacy method. On the `EmailMessage` class its functionality is replaced by `get_content()` and `iter_parts()`.

  `set_payload`(payload, charset=None)

    メッセージオブジェクト全体のペイロードを payload に設定します。クライアントはペイロードを変更してはいけません。オプションの charset はメッセージのデフォルト文字セットを設定します。詳しくは `set_charset()` を参照してください。

    This is a legacy method. On the `EmailMessage` class its functionality is replaced by `set_content()`.

  `set_charset`(charset)

    ペイロードの文字セットを charset に変更します。これは `Charset` インスタンス (`email.charset` 参照)、文字セット名を表す文字列、あるいは `None` のいずれかです。文字列を指定した場合は `Charset` インスタンスに変換されます。 charset が `None` の場合、 `charset` 引数は Content-Type ヘッダから除去されます (それ以外にメッセージは変更されません)。これら以外のものを文字セットとして指定した場合、 `TypeError` を送出します。

    MIME-Version ヘッダが存在しなければ、追加されます。 Content-Type ヘッダが存在しなければ、 text/plain を値として追加されます。 Content-Type が存在していてもいなくても、 `charset` パラメタは charset.output_charset に設定されます。 charset.input_charset と charset.output_charset が異なるなら、ペイロードは output_charset に再エンコードされます。 Content-Transfer-Encoding ヘッダが存在しなければ、ペイロードは、必要なら指定された `Charset` を使って transfer エンコードされ、適切な値のヘッダが追加されます。 Content-Transfer-Encoding ヘッダがすでに存在すれば、ペイロードはすでにその Content-Transfer-Encoding によって正しくエンコードされたものと見なされ、変形されません。

    This is a legacy method. On the `EmailMessage` class its functionality is replaced by the charset parameter of the `email.emailmessage.EmailMessage.set_content()` method.

  `get_charset`()

    そのメッセージ中のペイロードの `Charset` インスタンスを返します。

    This is a legacy method. On the `EmailMessage` class it always returns `None`.

  以下のメソッドは、メッセージの RFC 2822 ヘッダにアクセスするためのマップ (辞書) 形式のインタフェイスを実装したものです。これらのメソッドと、通常のマップ (辞書) 型はまったく同じ意味をもつわけではないことに注意してください。たとえば辞書型では、同じキーが複数あることは許されていませんが、ここでは同じメッセージヘッダが複数ある場合があります。また、辞書型では `keys()` で返されるキーの順序は保証されていませんが、 `Message` オブジェクト内のヘッダはつねに元のメッセージ中に現れた順序、あるいはそのあとに追加された順序で返されます。削除され、その後ふたたび追加されたヘッダはリストの一番最後に現れます。

  こういった意味のちがいは意図的なもので、最大の利便性をもつようにつくられています。

  注意: どんな場合も、メッセージ中のエンベロープヘッダはこのマップ形式のインタフェイスには含まれません。

  In a model generated from bytes, any header values that (in contravention of the RFCs) contain non-ASCII bytes will, when retrieved through this interface, be represented as `Header` objects with a charset of `unknown-8bit`.

  `__len__`()

    複製されたものもふくめてヘッダ数の合計を返します。

  `__contains__`(name)

    メッセージオブジェクトが name という名前のフィールドを持っていれば `True` を返します。この検査では名前の大文字小文字は区別されません。name は最後にコロンをふくんでいてはいけません。このメソッドは以下のように `in` 演算子で使われます:

        if 'message-id' in myMessage:
           print('Message-ID:', myMessage['message-id'])

  `__getitem__`(name)

    指定された名前のヘッダフィールドの値を返します。 name は最後にコロンをふくんでいてはいけません。そのヘッダがない場合は `None` が返され、 `KeyError` 例外は発生しません。

    注意: 指定された名前のフィールドがメッセージのヘッダに2回以上現れている場合、どちらの値が返されるかは未定義です。ヘッダに存在するフィールドの値をすべて取り出したい場合は `get_all()` メソッドを使ってください。

  `__setitem__`(name, val)

    メッセージヘッダに name という名前の val という値をもつフィールドをあらたに追加します。このフィールドは現在メッセージに存在するフィールドのいちばん後に追加されます。

    注意: このメソッドでは、すでに同一の名前で存在するフィールドは上書き されません。もしメッセージが名前 name をもつフィールドをひとつしか持たないようにしたければ、最初にそれを除去してください。たとえば:

        del msg['subject']
        msg['subject'] = 'Python roolz!'

  `__delitem__`(name)

    メッセージのヘッダから、name という名前をもつフィールドをすべて除去します。たとえこの名前をもつヘッダが存在していなくても例外は発生しません。

  `keys`()

    メッセージ中にあるすべてのヘッダのフィールド名のリストを返します。

  `values`()

    メッセージ中にあるすべてのフィールドの値のリストを返します。

  `items`()

    メッセージ中にあるすべてのヘッダのフィールド名とその値を 2-タプルのリストとして返します。

  `get`(name, failobj=None)

    指定された名前をもつフィールドの値を返します。これは指定された名前がないときにオプション引数の failobj (デフォルトでは `None`) を返すことをのぞけば、 `__getitem__()` と同じです。

  さらに、役に立つメソッドをいくつか紹介します:

  `get_all`(name, failobj=None)

    name の名前をもつフィールドのすべての値からなるリストを返します。該当する名前のヘッダがメッセージ中に含まれていない場合は failobj (デフォルトでは `None`) が返されます。

  `add_header`(_name, _value, **_params)

    拡張ヘッダ設定。このメソッドは `__setitem__()` と似ていますが、追加のヘッダ・パラメータをキーワード引数で指定できるところが違っています。 _name に追加するヘッダフィールドを、 _value にそのヘッダの 最初の 値を渡します。

    キーワード引数辞書 _params の各項目ごとに、そのキーがパラメータ名として扱われ、キー名にふくまれるアンダースコアはハイフンに置換されます (アンダースコアは、Python 識別子としてハイフンを使えないための代替です)。ふつう、パラメータの値が `None` 以外のときは、 `key="value"` の形で追加されます。パラメータの値が `None` のときはキーのみが追加されます。値が非 ASCII 文字を含むなら、それは `(CHARSET, LANGUAGE, VALUE)` の形式の 3 タプルにすることが出来ます。ここで `CHARSET` はその値をエンコードするのに使われる文字セットを指示する文字列で、 `LANGUAGE` は通常 `None` か空文字列にでき (これら以外で指定出来るものについては RFC 2231 を参照してください)、 `VALUE` は非 ASCII コードポイントを含む文字列値です。この 3 タプルではなく非 ASCII 文字を含む値が渡された場合は、 `CHARSET` に `utf-8` 、 `LANGUAGE` に `None` を使って RFC 2231 形式に自動的にエンコードされます。

    以下はこの使用例です:

        msg.add_header('Content-Disposition', 'attachment', filename='bud.gif')

    こうするとヘッダには以下のように追加されます

        Content-Disposition: attachment; filename="bud.gif"

    非 ASCII 文字を使った例:

        msg.add_header('Content-Disposition', 'attachment',
                       filename=('iso-8859-1', '', 'Fußballer.ppt'))

    は、以下のようになります

        Content-Disposition: attachment; filename*="iso-8859-1''Fu%DFballer.ppt"

  `replace_header`(_name, _value)

    ヘッダの置換。 _name と一致するヘッダで最初に見つかったものを置き換えます。このときヘッダの順序とフィールド名の大文字小文字は保存されます。一致するヘッダがない場合、 `KeyError` が発生します。

  `get_content_type`()

    そのメッセージの content-type を返します。返された文字列は強制的に小文字で maintype/subtype の形式に変換されます。メッセージ中に Content-Type ヘッダがない場合、デフォルトの content-type は `get_default_type()` が返す値によって与えられます。 RFC 2045 によればメッセージはつねにデフォルトの content-type をもっているので、 `get_content_type()` はつねになんらかの値を返すはずです。

    RFC 2045 はメッセージのデフォルト content-type を、それが multipart/digest コンテナに現れているとき以外は text/plain に規定しています。あるメッセージが multipart/digest コンテナ中にある場合、その content-type は message/rfc822 になります。もし Content-Type ヘッダが適切でない content-type 書式だった場合、 RFC 2045 はそれのデフォルトを text/plain として扱うよう定めています。

  `get_content_maintype`()

    そのメッセージの主 content-type を返します。これは `get_content_type()` によって返される文字列の maintype 部分です。

  `get_content_subtype`()

    そのメッセージの副 content-type (sub content-type、subtype) を返します。これは `get_content_type()` によって返される文字列の subtype 部分です。

  `get_default_type`()

    デフォルトの content-type を返します。ほどんどのメッセージではデフォルトの content-type は text/plain ですが、メッセージが multipart/digest コンテナに含まれているときだけ例外的に message/rfc822 になります。

  `set_default_type`(ctype)

    デフォルトの content-type を設定します。 ctype は text/plain あるいは message/rfc822 である必要がありますが、強制ではありません。デフォルトの content-type はヘッダの Content-Type には格納されません。

  `get_params`(failobj=None, header='content-type', unquote=True)

    メッセージの Content-Type パラメータをリストとして返します。返されるリストはキー/値の組からなる2要素タプルが連なったものであり、これらは `'='` 記号で分離されています。 `'='` の左側はキーになり、右側は値になります。パラメータ中に `'='` がなかった場合、値の部分は空文字列になり、そうでなければその値は `get_param()` で説明されている形式になります。また、オプション引数 unquote が `True` (デフォルト) である場合、この値は unquote されます。

    オプション引数 failobj は、 Content-Type ヘッダが存在しなかった場合に返すオブジェクトです。オプション引数 header には Content-Type のかわりに検索すべきヘッダを指定します。

    This is a legacy method. On the `EmailMessage` class its functionality is replaced by the params property of the individual header objects returned by the header access methods.

  `get_param`(param, failobj=None, header='content-type', unquote=True)

    メッセージの Content-Type ヘッダ中のパラメータ param を文字列として返します。そのメッセージ中に Content-Type ヘッダが存在しなかった場合、 failobj (デフォルトは `None`) が返されます。

    オプション引数 header が与えられた場合、 Content-Type のかわりにそのヘッダが使用されます。

    パラメータのキー比較は常に大文字小文字を区別しません。返り値は文字列か 3 要素のタプルで、タプルになるのはパラメータが RFC 2231 エンコードされている場合です。3 要素タプルの場合、各要素の値は `(CHARSET, LANGUAGE, VALUE)` の形式になっています。 `CHARSET` と `LAGUAGE` は `None` になることがあり、その場合 `VALUE` は `us-ascii` 文字セットでエンコードされているとみなさなければならないので注意してください。普段は `LANGUAGE` を無視できます。

    この関数を使うアプリケーションが、パラメータが RFC 2231 形式でエンコードされているかどうかを気にしないのであれば、 `email.utils.collapse_rfc2231_value()` に `get_param()` の返り値を渡して呼び出すことで、このパラメータをひとつにまとめることができます。この値がタプルならばこの関数は適切にデコードされた Unicode 文字列を返し、そうでない場合は unquote された元の文字列を返します。たとえば:

        rawparam = msg.get_param('foo')
        param = email.utils.collapse_rfc2231_value(rawparam)

    いずれの場合もパラメータの値は (文字列であれ3要素タプルの `VALUE` 項目であれ) つねに unquote されます。ただし、unquote が `False` に指定されている場合は unquote されません。

    This is a legacy method. On the `EmailMessage` class its functionality is replaced by the params property of the individual header objects returned by the header access methods.

  `set_param`(param, value, header='Content-Type', requote=True, charset=None, language='', replace=False)

    Content-Type ヘッダ中のパラメータを設定します。指定されたパラメータがヘッダ中にすでに存在する場合、その値は value に置き換えられます。 Content-Type ヘッダがまだこのメッセージ中に存在していない場合、 RFC 2045 にしたがいこの値には text/plain が設定され、新しいパラメータ値が末尾に追加されます。

    オプション引数 header が与えられた場合、 Content-Type のかわりにそのヘッダが使用されます。オプション引数 requote が `False` でない限り、この値は quote されます (デフォルトは `True`)。

    オプション引数 charset が与えられると、そのパラメータは RFC 2231 に従ってエンコードされます。オプション引数 language は RFC 2231 の言語を指定しますが、デフォルトではこれは空文字列となります。 charset と language はどちらも文字列である必要があります。

    If replace is `False` (the default) the header is moved to the end of the list of headers. If replace is `True`, the header will be updated in place.

    バージョン 3.4 で変更: `replace` キーワードが追加されました。

  `del_param`(param, header='content-type', requote=True)

    指定されたパラメータを Content-Type ヘッダ中から完全にとりのぞきます。ヘッダはそのパラメータと値がない状態に書き換えられます。 requote が `False` でない限り (デフォルトでは `True` です)、すべての値は必要に応じて quote されます。オプション変数 header が与えられた場合、 Content-Type のかわりにそのヘッダが使用されます。

  `set_type`(type, header='Content-Type', requote=True)

    Content-Type ヘッダの maintype と subtype を設定します。 type は maintype/subtype という形の文字列でなければなりません。それ以外の場合は `ValueError` が発生します。

    このメソッドは Content-Type ヘッダを置き換えますが、すべてのパラメータはそのままにします。 requote が `False` の場合、これはすでに存在するヘッダを quote せず放置しますが、そうでない場合は自動的に quote します (デフォルト動作)。

    オプション変数 header が与えられた場合、 Content-Type のかわりにそのヘッダが使用されます。 Content-Type ヘッダが設定される場合には、 MIME-Version ヘッダも同時に付加されます。

    This is a legacy method. On the `EmailMessage` class its functionality is replaced by the `make_` and `add_` methods.

  `get_filename`(failobj=None)

    そのメッセージ中の Content-Disposition ヘッダにある、 `filename` パラメータの値を返します。目的のヘッダに `filename` パラメータがない場合には Content-Type ヘッダにある `name` パラメータを探します。それも無い場合またはヘッダが無い場合には failobj が返されます。返される文字列はつねに `email.utils.unquote()` によって unquote されます。

  `get_boundary`(failobj=None)

    そのメッセージ中の Content-Type ヘッダにある、 `boundary` パラメータの値を返します。目的のヘッダが欠けていたり、 `boundary` パラメータがない場合には failobj が返されます。返される文字列はつねに `email.utils.unquote()` によって unquote されます。

  `set_boundary`(boundary)

    メッセージ中の Content-Type ヘッダにある、 `boundary` パラメータに値を設定します。 `set_boundary()` は必要に応じて boundary を quote します。そのメッセージが Content-Type ヘッダを含んでいない場合、 `HeaderParseError` が発生します。

    注意: このメソッドを使うのは、古い Content-Type ヘッダを削除して新しい boundary をもったヘッダを `add_header()` で足すのとは少し違います。 `set_boundary()` は一連のヘッダ中での Content-Type ヘッダの位置を保つからです。しかし、これは元の Content-Type ヘッダ中に存在していた連続する行の順番までは 保ちません 。

  `get_content_charset`(failobj=None)

    そのメッセージ中の Content-Type ヘッダにある、 `charset` パラメータの値を返します。値はすべて小文字に変換されます。メッセージ中に Content-Type がなかったり、このヘッダ中に `charaset` パラメータがない場合には failobj が返されます。

    注意: これは `get_charset()` メソッドとは異なります。こちらのほうは文字列のかわりに、そのメッセージボディのデフォルトエンコーディングの `Charset` インスタンスを返します。

  `get_charsets`(failobj=None)

    メッセージ中に含まれる文字セットの名前をすべてリストにして返します。そのメッセージが multipart である場合、返されるリストの各要素がそれぞれの subpart のペイロードに対応します。それ以外の場合、これは長さ 1 のリストを返します。

    リスト中の各要素は文字列であり、これは対応する subpart 中のそれぞれの Content-Type ヘッダにある `charset` の値です。しかし、その subpart が Content-Type をもってないか、 `charset` がないか、あるいは MIME maintype が text でないいずれかの場合には、リストの要素として failobj が返されます。

  `get_content_disposition`()

    Return the lowercased value (without parameters) of the message's Content-Disposition header if it has one, or `None`. The possible values for this method are inline, attachment or `None` if the message follows RFC 2183.

    バージョン 3.5 で追加.

  `walk`()

    `walk()` メソッドは多目的のジェネレータで、これはあるメッセージオブジェクトツリー中のすべての part および subpart をわたり歩くのに使えます。順序は深さ優先です。おそらく典型的な用法は、 `walk()` を `for` ループ中でのイテレータとして使うことでしょう。ループを一回まわるごとに、次の subpart が返されるのです。

    以下の例は、 multipart メッセージのすべての part において、その MIME タイプを表示していくものです。 :

        >>> for part in msg.walk():
        ...     print(part.get_content_type())
        multipart/report
        text/plain
        message/delivery-status
        text/plain
        text/plain
        message/rfc822
        text/plain

    `walk` iterates over the subparts of any part where `is_multipart()` returns `True`, even though `msg.get_content_maintype() == 'multipart'` may return `False`. We can see this in our example by making use of the `_structure` debug helper function:

        >>> for part in msg.walk():
        ...     print(part.get_content_maintype() == 'multipart',
        ...           part.is_multipart())
        True True
        False False
        False True
        False False
        False False
        False True
        False False
        >>> _structure(msg)
        multipart/report
            text/plain
            message/delivery-status
                text/plain
                text/plain
            message/rfc822
                text/plain

    Here the `message` parts are not `multiparts`, but they do contain subparts. `is_multipart()` returns `True` and `walk` descends into the subparts.

  `Message` オブジェクトはオプションとして 2つのインスタンス属性をとることができます。これはある MIME メッセージからプレーンテキストを生成するのに使うことができます。

  `preamble`

    MIME ドキュメントの形式では、ヘッダ直後にくる空行と最初の multipart 境界をあらわす文字列のあいだにいくらかのテキスト (訳注: preamble, 序文) を埋めこむことを許しています。このテキストは標準的な MIME の範疇からはみ出しているので、MIME 形式を認識するメールソフトからこれらは通常まったく見えません。しかしメッセージのテキストを生で見る場合、あるいはメッセージを MIME 対応していないメールソフトで見る場合、このテキストは目に見えることになります。

    preamble 属性は MIME ドキュメントに加えるこの最初の MIME 範囲外テキストを含んでいます。 `Parser` があるテキストをヘッダ以降に発見したが、それはまだ最初の MIME 境界文字列が現れる前だった場合、パーザはそのテキストをメッセージの preamble 属性に格納します。 `Generator` がある MIME メッセージからプレーンテキスト形式を生成するときメッセージが preamble 属性を持つことが発見されれば、これはそのテキストをヘッダと最初の MIME 境界の間に挿入します。詳細は `email.parser` および `email.generator` を参照してください。

    注意: そのメッセージに preamble がない場合、preamble 属性には `None` が格納されます。

  `epilogue`

    epilogue 属性はメッセージの最後の MIME 境界文字列からメッセージ末尾までのテキストを含むもので、それ以外は preamble 属性と同じです。

    `Generator` でファイル終端に改行を出力するため、 epilogue に空文字列を設定する必要はなくなりました。

  `defects`

    defects 属性はメッセージを解析する途中で検出されたすべての問題点 (defect、障害) のリストを保持しています。解析中に発見されうる障害についてのより詳細な説明は `email.errors` を参照してください。