# 18.11. `rfc822` --- RFC 2822 準拠のメールヘッダ読み出し

バージョン 2.3 で非推奨: `rfc822` モジュールを使うよりも `email` パッケージを使うべきです。このモジュールは以前のバージョンとの互換性のために保守されているにすぎません。 Python 3 ではこのモジュールは削除されました。

このモジュールでは、インターネット標準 RFC 2822 [1] で定義されている "電子メールメッセージ" を表現するクラス、 `Message` を定義しています。このメッセージはメッセージヘッダ群とメッセージボディの集まりからなります。このモジュールではまた、ヘルパークラス RFC 2822 アドレス群を解釈するための `AddressList` クラスを定義しています。 RFC 2822 メッセージ固有の構文に関する情報は RFC を参照してください。

`mailbox` モジュールでは、多くのエンドユーザメールプログラムによって生成されるメールボックスを読み出すためのクラスを提供しています。

class `rfc822.``Message`(file[, seekable])

  `Message` インスタンスは入力オブジェクトをパラメタに与えてインスタンス化します。入力オブジェクトのメソッドのうち、Message が依存するのは `readline()` だけです; 通常のファイルオブジェクトは適格です。インスタンス化を行うと、入力オブジェクトからデリミタ行 (通常は空行 1 行) に到達するまでヘッダを読み出し、それらをインスタンス中に保持します。ヘッダの後のメッセージ本体は読み出しません。

  このクラスは `readline()` メソッドをサポートする任意の入力オブジェクトを扱うことができます。入力オブジェクトが seek および tell できる場合、 `rewindbody()` メソッドが動作します。また、不正な行データを入力ストリームにプッシュバックできます。入力オブジェクトが seek できない一方で、入力行をプッシュバックする `unread()` メソッドを持っている場合、 `Message` は不正な行データにこのプッシュバックを使います。こうして、このクラスはバッファされているストリームから来るメッセージを解釈するのに使うことができます。

  オプションの seekable 引数は、 `lseek()` システムコールが動作しないと分かるまでは `tell()` がバッファされたデータを無視するような、ある種の stdio ライブラリでの回避手段として提供されています。可搬性を最大にするために、socket オブジェクトによって生成されたファイルのような、seek できないオブジェクトを渡す際には、最初に `tell()` が呼び出されないようにするために seekable 引数をゼロに設定すべきです。

  ファイルとして読み出された入力行データは CR-LF と単一の改行 (line feed) のどちらで終端されていてもかまいません; 行データを記憶する前に、終端の CR-LF は単一の改行と置き換えられます。

  ヘッダに対するマッチは全て大小文字に依存しません。例えば、 `m['From']` 、 `m['from']` 、および `m['FROM']` は全て同じ結果になります。

class `rfc822.``AddressList`(field)

  RFC 2833 アドレスがカンマで区切られたものとして解釈できる単一の文字列パラメタを使って、 `AddressList` ヘルパークラスをインスタンス化することができます。 (パラメタ `None` は空のリストを表します。)

`rfc822.``quote`(str)

  str 中のバックスラッシュが 2 つのバックスラッシュに置き換えられ、二重引用符がバックスラッシュ付きの二重引用符に置き換えられた、新たな文字列を返します。

`rfc822.``unquote`(str)

  文字列 str を 逆クォート した新しい文字列を返します。もし str の先頭あるいは末尾がダブルクォートだった場合、これらは単に切りおとされます。同様にもし str の先頭あるいは末尾が角ブラケット (<、>) だった場合も切りおとされます。

`rfc822.``parseaddr`(address)

  To や Cc といった、アドレスが入っているフィールドの値 address を解析し、含まれている "実名 (realname)" 部分および "電子メールアドレス" 部分に分けます。それらの情報からなるタプルを返します。解析が失敗した場合には 2 要素のタプル `(None, None)` を返します。

`rfc822.``dump_address_pair`(pair)

  `parseaddr()` の逆で、実名と電子メールアドレスからなる 2要素のタプル`(realname, email_address)` を引数にとり、 To あるいは Cc ヘッダに適した形式の文字列を返します。タプル pair の第1要素が偽である場合、第2要素の値をそのまま返します。

`rfc822.``parsedate`(date)

  RFC 2822 の規則に従っている日付を解析しようと試みます。しかしながら、メーラによっては RFC 2822 で指定されているような書式に従わないため、そのような場合には `parsedata()` は正しい日付を推測しようと試みます。 date は `'Mon, 20 Nov 1995 19:12:08 -0500'` のような RFC 2822 様式の日付を収めた文字列です。日付の解析に成功した場合、 `parsedate()` は `time.mktime()` にそのまま渡すことができるような 9 要素のタプルを返します; そうでない場合には `None` を返します。結果のインデックス 6、7、および 8 は有用な情報ではありません。

`rfc822.``parsedate_tz`(date)

  `parsedate()` と同じ機能を実現しますが、 `None` または 10 要素のタプルを返します; 最初の 9 要素は `time.mktime()` に直接渡すことができるようなタプルで、 10 番目の要素はその日のタイムゾーンにおける UTC (グリニッチ標準時の公式名称) からのオフセットです。(タイムゾーンオフセットの符号は、同じタイムゾーンにおける `time.timezone` 変数の符号と反転しています; 後者の変数が POSIX 標準に従っている一方、このモジュールは RFC 2822 に従っているからです。) 入力文字列がタイムゾーン情報を持たない場合、タプルの最後の要素は `None` になります。結果のインデックス 6、7、および 8 は有用な情報ではありません。

`rfc822.``mktime_tz`(tuple)

  `parsedata_tz()` が返す 10 要素のタプルを UTC タイムスタンプに変換します。タプル内のタイムゾーン要素が `None` の場合、地域の時刻を表しているものと仮定します。些細な欠陥: この関数はまず最初の 8 要素を地域における時刻として変換し、次にタイムゾーンの違いに対する補償を行います; これにより、夏時間の切り替え日前後でちょっとしたエラーが生じるかもしれません。通常の利用に関しては心配ありません。

参考

`email` モジュール
  包括的な e-mail 処理パッケージです。 `rfc822` に取って代わります。
`mailbox` モジュール
  エンドユーザのメールプログラムによって生成される、様々な mailbox 形式を読み出すためのクラス群。
`mimetools` モジュール
  MIME エンコードされたメッセージを処理する `rfc822.Message` のサブクラス。

## 18.11.1. Message オブジェクト

`Message` インスタンスは以下のメソッドを持っています:

`Message.``rewindbody`()

  メッセージ本体の先頭に seek します。このメソッドはファイルオブジェクトが seek 可能である場合にのみ動作します。

`Message.``isheader`(line)

  ある行が正しい RFC 2822 ヘッダである場合、その行の正規化されたフィールド名 (インデクス指定の際に使われる辞書キー) を返します; そうでない場合 `None` を返します (解析をここで一度中断し、行データを入力ストリームに押し戻すことを意味します)。このメソッドをサブクラスで上書きすると便利なことがあります。

`Message.``islast`(line)

  与えられた line が Message の区切りとなるデリミタであった場合に真を返します。このデリミタ行は消費され、ファイルオブジェクトの読み位置はその直後になります。標準ではこのメソッドは単にその行が空行かどうかをチェックしますが、サブクラスで上書きすることもできます。

`Message.``iscomment`(line)

  与えられた行全体を無視し、単に読み飛ばすときに真を返します。標準では、これは控えメソッド (stub) であり、常に `False` を返しますが、サブクラスで上書きすることもできます。

`Message.``getallmatchingheaders`(name)

  name に一致するヘッダ全てで構成される行のリストを返します。各物理行は継続行であるか否かに関わらず別々のリスト要素になります。 name に一致するヘッダがない場合、空のリストを返します。

`Message.``getfirstmatchingheader`(name)

  name に一致する最初のヘッダと、その行に継続する (複数) 行からなる行データのリストを返します。 name に一致するヘッダがない場合 `None` を返します。

`Message.``getrawheader`(name)

  name に一致する最初のヘッダにおけるコロン以降のテキストが入った単一の文字列を返します。このテキストには、先頭の空白、末尾の改行、また継続の行がある場合には途中の改行と空白が含まれます。 name に一致するヘッダが存在しない場合には `None` を返します。

`Message.``getheader`(name[, default])

  name に一致する最後のヘッダから先頭および末尾の空白を剥ぎ取った単一の文字列を返します。途中にある空白は剥ぎ取られません。オプションの default 引数は、 name に一致するヘッダが存在しない場合に、別のデフォルト値を返すように指定するために使われます。デフォルトは `None` です。パースされたヘッダを得る方法としてはこれが好ましいでしょう。

`Message.``get`(name[, default])

  正規の辞書との互換性をより高めるための `getheader()` の別名です。

`Message.``getaddr`(name)

  `getheader(name)` が返した文字列を解析して、 `(full name, email address)` からなるペアを返します。 name に一致するヘッダが無い場合、 `(None, None)` が返されます; そうでない場合、 full name および address は (空文字列をとりうる) 文字列になります。

  例: m に最初の From ヘッダに文字列 `'jack@cwi.nl (Jack Jansen)'` が入っている場合、 `m.getaddr('From')` はペア `('Jack Jansen', 'jack@cwi.nl')` になります。また、 `'Jack Jansen <jack@cwi.nl>'` であっても、全く同じ結果になります。

`Message.``getaddrlist`(name)

  `getaddr(list)` に似ていますが、複数のメールアドレスからなるリストが入ったヘッダ (例えば To ヘッダ) を解析し、 `(full name, email address)` のペアからなるリストを (たとえヘッダには一つしかアドレスが入っていなかったとしても) 返します。 name に一致するヘッダが無かった場合、空のリストを返します。

  指定された名前に一致する複数のヘッダが存在する場合 (例えば、複数の Cc ヘッダが存在する場合)、全てのアドレスを解析します。指定されたヘッダが継続行で収められている場合も解析されます。

`Message.``getdate`(name)

  `getheader()` を使ってヘッダを取得して解析し、 `time.mktime()` と互換な 9 要素のタプルにします; フィールド 6、7、および 8 は有用な値ではないので注意して下さい。 name に一致するヘッダが存在しなかったり、ヘッダが解析不能であった場合、 `None` を返します。

  日付の解析は黒魔術のようなものであり、全てのヘッダが標準に従っているとは限りません。このメソッドは多くの発信源から集められた膨大な数の電子メールでテストされており、正しく動作することが分かっていますが、間違った結果を出力してしまう可能性はまだあります。

`Message.``getdate_tz`(name)

  `getheader()` を使ってヘッダを取得して解析し、10 要素のタプルにします; 最初の 9 要素は `time.mktime()` と互換性のあるタプルを形成し、10 番目の要素はその日におけるタイムゾーンの UTC からのオフセットを与える数字になります。フィールド 6、7、および 8 は有用な値ではないので注意して下さい。 `getdate()` と同様に、 name に一致するヘッダがなかったり、解析不能であった場合、 `None` を返します。

`Message` インスタンスはまた、限定的なマップ型のインタフェースを持っています。すなわち: `m[name]` は `m.getheader(name)` に似ていますが、一致するヘッダがない場合 `KeyError` を送出します; `len(m)` 、 `m.get(name[, default])` 、 `name in m`, `m.keys()` 、 `m.values()` 、 `m.items()` 、および `m.setdefault(name[, default])` は期待通りに動作します。ただし `setdefault()` は標準の設定値として空文字列をとります。 `Message` インスタンスはまた、マップ型への書き込みを行えるインタフェース `m[name] = value` および `del m[name]` をサポートしています。 `Message` オブジェクトでは、 `clear()` 、 `copy()` 、 `popitem()` 、あるいは `update()` といったマップ型インタフェースのメソッドはサポートしていません。 (`get()` および `setdefault()` のサポートは Python 2.2 でしか追加されていません。)

最後に、 `Message` インスタンスはいくつかの public なインスタンス変数を持っています:

`Message.``headers`

  ヘッダ行のセット全体が、(setitem を呼び出して変更されない限り) 読み出された順番に入れられたリストです。各行は末尾の改行を含んでいます。ヘッダを終端する空行はリストに含まれません。

`Message.``fp`

  インスタンス化の際に渡されたファイルまたはファイル類似オブジェクトです。この値はメッセージ本体を読み出すために使うことができます。

`Message.``unixfrom`

  メッセージに Unix `From` 行がある場合はその行、そうでなければ空文字列になります。この値は例えば `mbox` 形式のメールボックスファイルのような、あるコンテキスト中のメッセージを再生成するために必要です。

## 18.11.2. AddressList オブジェクト

`AddressList` インスタンスは以下のメソッドを持ちます:

`AddressList.``__len__`()

  アドレスリスト中のアドレスの数を返します。

`AddressList.``__str__`()

  アドレスリストの正規化 (canonicalize) された文字列表現を返します。アドレスはカンマで分割された "name" <host@domain> 形式になります。

`AddressList.``__add__`(alist)

  二つの `AddressList` 被演算子中の双方に含まれるアドレスについて、重複を除いた (集合和の) 全てのアドレスを含む新たな `AddressList` インスタンスを返します。

`AddressList.``__iadd__`(alist)

  `__add__()` のインプレース演算版です; `AddressList` インスタンスと右辺値 alist との集合和をとり、その結果をインスタンス自体と置き換えます。

`AddressList.``__sub__`(alist)

  左辺値の `AddressList` インスタンスのアドレスのうち、右辺値中に含まれていないもの全てを含む (集合差分の) 新たな `AddressList` インスタンスを返します。

`AddressList.``__isub__`(alist)

  `__sub__()` のインプレース演算版で、 alist にも含まれているアドレスを削除します。

最後に、 `AddressList` インスタンスは public なインスタンス変数を一つ持ちます:

`AddressList.``addresslist`

  アドレスあたり一つの文字列ペアで構成されるタプルからなるリストです。各メンバ中では、最初の要素は正規化された名前部分で、二つ目は実際の配送アドレス (`'@'` で分割されたユーザ名とホスト.ドメインからなるペア) です。

脚注

[1] | このモジュールはもともと RFC 822 に適合していたので、そういう名前になっています。その後、 RFC 2822 が RFC 822 に対する更新としてリリースされました。このモジュールは RFC 2822 適合であり、特に RFC 822 からの構文や意味付けに対する変更がなされています。