前のトピックへ

19.1. email — 電子メールと MIME 処理のためのパッケージ

次のトピックへ

19.1.2. email: 電子メールメッセージを解析(パース)する

このページ

19.1.1. email: 電子メールメッセージの表現

Message クラスは、 email パッケージの中心となるクラスです。 これは email オブジェクトモデルの基底クラスになっています。 Message はヘッダフィールドを検索したりメッセージ本体にアクセスするための 核となる機能を提供します。

概念的には、(email.message モジュールからインポートされる) Message オブジェクトには ヘッダペイロード が格納されています。ヘッダは、 RFC 2822 形式のフィールド名およびフィールド値がコロンで区切られたものです。コロンはフィールド名またはフィールド値のどちらにも含まれません。

ヘッダは大文字小文字を区別した形式で保存されますが、 ヘッダ名が一致するかどうかの検査は大文字小文字を区別せずにおこなうことができます。 Unix-From ヘッダまたは From_ ヘッダとして知られるエンベロープヘッダがひとつ存在することもあります。 ペイロードは、単純なメッセージオブジェクトの場合は単なる文字列ですが、 MIME コンテナ文書 (multipart/* または message/rfc822 など) の場合は Message オブジェクトのリストになっています。

Message オブジェクトは、メッセージヘッダにアクセスするためのマップ (辞書) 形式のインタフェイスと、ヘッダおよびペイロードの両方にアクセスするための明示的なインタフェイスを提供します。 これにはメッセージオブジェクトツリーからフラットなテキスト文書を生成したり、一般的に使われるヘッダのパラメータにアクセスしたり、またオブジェクトツリーを再帰的にたどったりするための便利なメソッドを含みます。

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

class email.message.Message

コンストラクタは引数をとりません。

as_string([unixfrom])

メッセージ全体をフラットな文字列として返します。オプション unixfromTrue の場合、返される文字列にはエンベロープヘッダも含まれます。 unixfrom のデフォルトは False です。

このメソッドは手軽に利用する事ができますが、必ずしも期待通りにメッセージをフォーマットするとは限りません。たとえば、これはデフォルトでは From で始まる行を変更してしまいます。以下の例のように Generator のインスタンスを生成して flatten() メソッドを直接呼び出せばより柔軟な処理を行う事ができます。

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

as_string(unixfrom=True)() と同じです。

is_multipart()

メッセージのペイロードが子 Message オブジェクトからなるリストであれば True を返し、そうでなければ False を返します。 is_multipart() が False を返した場合は、ペイロードは文字列オブジェクトである必要があります。

set_unixfrom(unixfrom)

メッセージのエンベロープヘッダを unixfrom に設定します。 これは文字列である必要があります。

get_unixfrom()

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

attach(payload)

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

get_payload([i[, decode]])

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

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

オプションの decode はそのペイロードが Content-Transfer-Encoding ヘッダに従ってデコードされるべきかどうかを指示するフラグです。 この値が True でメッセージが multipart ではない場合、 ペイロードはこのヘッダの値が quoted-printable または base64 のときにかぎりデコードされます。これ以外のエンコーディングが使われている場合、 Content-Transfer-Encoding ヘッダがない場合、あるいは曖昧なbase64データが含まれる場合は、ペイロードはそのまま (デコードされずに) 返されます。もしメッセージが multipart で decode フラグが True の場合は None が返されます。 decode のデフォルト値は False です。

set_payload(payload[, charset])

メッセージ全体のオブジェクトのペイロードを payload に設定します。 ペイロードの形式をととのえるのは呼び出し側の責任です。オプションの charset はメッセージのデフォルト文字セットを設定します。 詳しくは set_charset() を参照してください。

バージョン 2.2.2 で変更: charset 引数の追加.

set_charset(charset)

ペイロードの文字セットを charset に変更します。 ここには Charset インスタンス (email.charset 参照)、 文字セット名をあらわす文字列、あるいは None のいずれかが指定できます。 文字列を指定した場合、これは Charset インスタンスに変換されます。 charsetNone の場合、 charset パラメータは Content-Type ヘッダから除去されます。 これ以外のものを文字セットとして指定した場合、 TypeError が発生します。

ここでいうメッセージとは、 charset.input_charset でエンコードされた text/* 形式のものを仮定しています。これは、もし必要とあらばプレーンテキスト形式を変換するさいに charset.output_charset の エンコードに変換されます。MIME ヘッダ (MIME-Version, Content-Type, Content-Transfer-Encoding) は必要に応じて追加されます。

バージョン 2.2.2 で追加.

get_charset()

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

バージョン 2.2.2 で追加.

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

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

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

__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'] = 'PythonPythonPython!'
__delitem__(name)

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

has_key(name)

メッセージが name という名前をもつヘッダフィールドを持っていれば真を、そうでなければ偽を返します。

keys()

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

values()

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

items()

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

get(name[, failobj])

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

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

get_all(name[, failobj])

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

add_header(_name, _value, **_params)

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

キーワード引数辞書 _params の各項目ごとに、 そのキーがパラメータ名として扱われ、キー名にふくまれるアンダースコアはハイフンに置換されます (なぜならハイフンは通常の Python 識別子としては使えないからです)。 ふつう、パラメータの値が None 以外のときは、 key="value" の形で追加されます。 パラメータの値が None のときはキーのみが追加されます。

例を示しましょう:

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

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

Content-Disposition: attachment; filename="bud.gif"
replace_header(_name, _value)

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

バージョン 2.2.2 で追加.

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 として扱うよう定めています。

バージョン 2.2.2 で追加.

get_content_maintype()

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

バージョン 2.2.2 で追加.

get_content_subtype()

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

バージョン 2.2.2 で追加.

get_default_type()

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

バージョン 2.2.2 で追加.

set_default_type(ctype)

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

バージョン 2.2.2 で追加.

get_params([failobj[, header[, unquote]]])

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

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

バージョン 2.2.2 で変更: unquote が追加されました.

get_param(param[, failobj[, header[, unquote]]])

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

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

パラメータのキー比較は常に大文字小文字を区別しません。 返り値は文字列か 3 要素のタプルで、タプルになるのはパラメータが RFC 2231 エンコードされている場合です。3 要素タプルの場合、各要素の値は (CHARSET, LANGUAGE, VALUE) の形式になっています。 CHARSETLAGUAGENone になることがあり、 その場合 VALUEus-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 されます。ただし、 unquoteFalse に指定されている場合は unquote されません。

バージョン 2.2.2 で変更: unquote 引数の追加、3要素タプルが返り値になる可能性あり。

set_param(param, value[, header[, requote[, charset[, language]]]])

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

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

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

バージョン 2.2.2 で追加.

del_param(param[, header[, requote]])

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

バージョン 2.2.2 で追加.

set_type(type[, header][, requote])

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

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

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

バージョン 2.2.2 で追加.

get_filename([failobj])

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

get_boundary([failobj])

そのメッセージ中の 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])

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

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

バージョン 2.2.2 で追加.

get_charsets([failobj])

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

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

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

バージョン 2.5 で変更: 以前の非推奨メソッド get_type()get_main_type()get_subtype() は削除されました。

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

preamble

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

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

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

epilogue

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

バージョン 2.5 で変更: Generator でファイル終端に改行を出力するため、 epilogue に空文字列を設定する必要はなくなりました。

defects

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

バージョン 2.4 で追加.