ラウンドナップ・コンサルティング公式ブログ 代表中山陽平が記事執筆。コンサルのノウハウ進化のための情報収集の一部を発信中。2004年〜開始。

MIME::Toolsドキュメント私家版日本語訳

MIME::Toolsの理解がどうにもいい加減な気がするので、cpanのドキュメントを訳してみました。私家版なので、翻訳ミスなどあるかと思います。もしありましたら、コメントお待ちし取ります(‘A`)

しかし英語が出来ないことが年を経るごとに弱点に…。こないだ見たシュワンツのライディングスクールのDVDも字幕無かったら完全にアウトでした。何か強烈なモチベーションを得られそうなものを探さなければ。

原文はMIME-tools 5.503(cpanが最近重いのでこっち)
また、So you want to make a Mime Parser …も役に立つかと思いますのでクリップ。

しかし基本的に好きな分野ではないせいか、コードを書いているとすぐに飽きます。Blog Hacksの作者の人たちとか、あれですかね、絵描きが、絵さえ描いていれば他に何もいらないと思うような、そういう感じなんでしょうか。うぅむ。

名前

MIME-tools

構文

MIME形式のメッセージを分析して、指定したディレクトリにMIMEコンポーネントを出力するという基本的なコードをいくつか書きます。

use MIME::Parser;
###パーサを作り、オプションをいくつか設定する。
my $parser = new MIME::Parser; $parser->output_under("$ENV{HOME}/mimemail");

### パースして入力
$entity = $parser->parse(*STDIN) or die "parse failedn";

### トップレベルのエンティティをチラッと見る。
$entity->dump_skeleton;

続いて、3つのパートを含んだMIME形式のメッセージを組み上げて、さらにそれを送信するコードを書きます。

use MIME::Entity;

###トップレベルの要素を作り、メールのヘッダーをセットする。
$top = MIME::Entity->build(Type =>"multipart/mixed",
From => "me@myhost.com",
To => "you@yourhost.com",
Subject => "Hello, nurse!");

### パート1 単純なテキスト
$top->attach(Path=>"./testin/short.txt");

### パート2: GIF画像
$top->attach(Path => "./docs/mime-sm.gif",
Type => "image/gif",
Encoding => "base64");

### パート3 いくつかの一般的な文書
$top->attach(Data=>$message);

### 送るぞ
open MAIL, "| /usr/lib/sendmail -t -oi -oem" or die "open: $!";
$top->print(*MAIL);
close MAIL;

MIME::Toolsの各ページを見れば、もっと色々スクリプトの例が載っています。

記述

MIME::ToolsはPerl5のコレクションです。

これは、シングルパートないしマルチパート(ネストしている場合もある)のMIMEメッセージを分析したり、デコードしたり、生成する為のモジュールです。
(そうだよ少年、これは気味でもGIF画像を添付したメールを遅れるってことだよ。)

必要条件

MIME::Toolsを使うには、システムに以下の物が必要です。

File::Path
File::Spec
IPC::Open2 (オプション)
IO::Scalar, ... from the IO-stringy distribution
MIME::Base64
MIME::QuotedPrint
Net::SMTP
Mail::Internet, ... from the MailTools distribution.

これらの必須モジュールが入っているかどうか、また、そのバージョンがいくつなのかは、お手持ちのシステムのMalefile.PL等をご覧下さい。

クイックツアー

クラスの概観

一般的に直接扱うであろうクラスの概観はこんな感じです。


(START HERE)            results() .-----------------.
                 .-------->| MIME::          |
.-----------.   /          | Parser::Results |
| MIME::    |--'           `-----------------'
| Parser    |--.           .-----------------.
`-----------'    filer()  | MIME::          |
| parse()     `-------->| Parser::Filer   |
| gives you             `-----------------'
| a...                                  | output_path()
|                                       | determines
|                                       | path() of...
|    head()       .--------.            |
|    returns...   | MIME:: | get()      |
V       .-------->| Head   | etc...     |
.--------./          `--------'            |
.---> | MIME:: |                                 |
`-----| Entity |           .--------.            |
parts() `--------'          | MIME:: |           /
returns            `-------->| Body   |<---------'
sub-entities    bodyhandle() `--------'
(if any)        returns...       | open()
| returns...
|
V
.--------. read()
| IO::   | getline()
| Handle | print()
`--------' etc...

図解すると、こういう感じで構文を解析しているのです。

"Parser"はMIMEストリームを解析します。
ParserはMIME::のインスタンスです。
これをファイルハンドルの様に、入力ストリームに持っていくことで、そのメッセージを解析できます。
解析が成功裏に終われば、MIMEエンティティが返されます。
解析されたメッセージは、エンティティとして表現されます。
エンティティとは、Mail::Internetのサブクラスである、MIME:Entity:のインスタンスです。
エンティティは、Content-typeやsenderやsubjectline等のメッセージヘッダーの情報を持っています。
エンティティの"body"部分は、メッセージデータの場所を知っています。
そのメッセージデータを読み書きするために、"open"することが出来ます。そうすることで入出力のハンドル( I/O handle )を持ってくることができるのです。
"body"を開いて、入出力ハンドル( I/O handle )を得て、メッセージデータを読み書きできます。
このハンドルは、IO::と基本的には同じです。ハンドルとファイルハンドル……これはどんなクラスでもありうるものです。それが、小さくて、基礎となっているデータソースへの標準的な読み書きの手順をサポートしている限りは。

2つのパートを含んでいる典型的なマルチパートのメッセージ(グリーティングメッセージとGIF画像)は、MIME::Entityのツリーになっています。それぞれのパーツもそれぞれMIME::Headを持っています。こんな感じに。


.--------.
| MIME:: | Content-type: multipart/mixed
| Entity | Subject: Happy Samhaine!
`--------'
|
`----.
parts |
|   .--------.
|---| MIME:: | Content-type: text/plain; charset=us-ascii
|   | Entity | Content-transfer-encoding: 7bit
|   `--------'
|   .--------.
|---| MIME:: | Content-type: image/gif
| Entity | Content-transfer-encoding: base64
`--------' Content-disposition: inline;
filename="hs.gif"

メッセージの構文解析

まずはMIME::Parserインスタンスを作り、どこに抽出したファイルを置くかや、ファイルの命名ルールなどのパラメータを決めるところから解析は始まります。

そのインスタンスを、MIMEメッセージが待っている、読み取り可能なファイルハンドルに持って行きます。それが上手くいくと、Mail:Internetのサブクラスである、MIME::Entityを得ることが出来ます。これは以下のものを内に持っています。

  • MIMEのヘッダーのデータを持っているMIME::Head。これはMIME::Headerのサブクラスです。
  • メッセージの本文の場所を知っているMIME::Body。あなたは、これを"open"して読み取りることができます。データへのファイルハンドルをくれるのです。これはファイルハンドルと同様のオブジェクトです。そして、IO::Handleインターフェイスのサブクラスである限りどんなクラスでもあり売ります。

もし元のメッセージデータがマルチパートだったら、MIME::Entityオブジェクトは、空ではない"parts"のリストを持っています。それはそれぞれMIME::Entityを持っています(それはさらにネスとしてるかもしれません)。

内部では、パーサ(MIME::Parser)は、必要なときはMIME::Decorderインスタンスに、エンコードされたデータをデコードさせます。MIME::Decorderはbase64等のサポートしているエンコーディングから、デコード可能なインスタンスへのマッピングをします。このマッピングはnewやexperimentメソッドで変更を加えることが出来ます。また、それ自体でデコーダとして使うことが出来ます。

メッセージを組み上げる

メッセージの組み上げは、全てMIME::Entityを通じて行います。シングルパートのメッセージなら、MIME::Entity/buildコンストラクタで簡単に作ることが出来ます。

マルチパートのメッセージなら、まず MIME::Entity::build()メソッドトップレベルのマルチパートを作ります。そして MIME::Entity::attach() でパーツをくっつけていきます。
  ※注意:私たちが「メールと添付したGIF画像」と思っているものは、実際は2つのパートを含むマルチパートメッセージです。一つ目はテキスト、2つ目はGIF画像です。

MIMEエンティティを作っているとき、二つの重要な情報を与えてあげないといけません。 content type と content transfer encodingです。これは直接にファイルのタイプを決めます。例えば、
HTML file なら text/htmlです。もう一つの、 encodingは、しかしながらトリッキーです。例えば、7bit-compliantなHTMLもあれば、非常に長くて、信頼性を得るために
quoted-printableで送られないとまずいものもあります。

メールを送る

MIME::EntityはMail::Internetを継承していますので、それを使ってメールを送ることが出来ます。例えば

$entity->smtpsend;

エンコードとデコードのサポート

MIME::Decorderクラスは同様にエンコードすることもできます。これは、MIME::Entityを出力するときに行われます。全てのスタンダードなエンコードがサポートされています(詳細に関してはをMIME入門書をご覧下さい)


Encoding:        | Normally used when message contents are:
-------------------------------------------------------------------
7bit             | 7-bit data with under 1000 chars/line, or multipart.
8bit             | 8-bit data with under 1000 chars/line.
binary           | 8-bit data with some long lines (or no line breaks).
quoted-printable | Text files with some 8-bit chars (e.g., Latin-1 text).
base64           | Binary files.

あなたが与えられた文書に対して、どのエンコーディングを選ぶかは、主に(1)あなたが文書の内容(テキストなのかバイナリなのかとか)について何を知っているか、(2)7ビット通信を行うインターネットでの電子メール送受信において、信頼できるメッセージを必要とするか、次第です。

一般的には、 quoted-printable で base64 なものだけが、保障できる信頼性のある送受信データです。他の三つ、まず no-encodingはただ単にデータを送ります。そのデータが1000行未満の7ビットASCIIであり、マルチパート境界でコンフリクトを起こしていない限りにおいて、信頼できます。

私は、 content-type と encodingを。ファイルパスから自動的に推定できるように作ったつもりですが、問題もあるようです…少なくともMail::capは…。

メッセージのロギング

MIME::Toolsは様々な外部からの入力を扱う、複雑なツールキットです。ロギングは、裏で本当なにがおこなわれているかを知る助けになります。MIME::Tools自身で記録しているメッセージがいくつかあります。

Debug Messages
STDERRに直接、 "MIME-tools :debug "という接頭辞をつけて出力します。あなたがDebuggingするように設定しない限り、ログは出力されません。
 
Warning messages
異例の事態になったときに、標準のPerlがwarn()で出すものと同じメカニズムで記録されます。 $^Wが真で、MIME::Toolsがquietに設定されていなければ記録されます。
Error Messages
何かが失敗したときに、標準のPerlがwarn()で出すものと同じメカニズムで記録されます。 $^Wが真で、MIME::Toolsがquietに設定されていなければ記録されます。
Usage messages
上の”典型的な”ものとは違って、データ処理や使い方の警告です。あまり良くない使い方や怪しげな呼び出しを開発者に警告します。$^Wが真で、MIME::Toolsがquietに設定されていなければ記録されます。

MIME::Parser(ないし内部のヘルパークラス)が上記のようなメッセージを伝えたいとき、上の様な関数が呼び出される前に、即座にMIME::Parser::Resultオブジェクトが呼び出されます。つまり、各Parserはそれぞれ独自にトレースログを持っているということです。

 

ツールキットを設定する

debugging
デバッグのオンオフを設定します。デフォルトはオフです。 (例 : MIME::Tools->debugging(1); )
quiet
warningとerrorメッセージの報告をオンオフします。デフォルトはオンです。 (例 :  MIME::Tools->quiet(1); )
version
MIME::Toolsのバージョンを返します。(例 :  print MIME::Tools->version, "n";  )

THINGS YOU SHOULD DO

(省略)

THINGS I DO THAT YOU SHOULD KNOW ABOUT

(省略)

 

MIME入門書

MIMEを解析しなければいけないけれど、詳しいことが良く分からない…大丈夫です。

用語集

ここにあるのは、RFC-1521に適合した専門用語についての定義です。それぞれは同等のMIMEモジュールを携えています…。

atattchment
"atattchment"マルチパートに関して、一般に広まっている俗語です。「これが前に約束してた画像だよ」みたいなメッセージは、これには含まれません。システム上は、単なるトップレベルのエンティティの下にあるMIME:Entityです。恐らく、partsの中の一つになっています。

body

エンティティの"body"とは、ヘッダーと、実際のいわゆる”メッセージ”を含む部分です。例えば、GIF画像の添付書類があるなら、そのGIFファイルのbodyは、
base64によってコード化されたGIFファイルそれ自体です。bodyはMIME::Bodyインスタンスによってあらわされます。bodyhandle()メソッドを使って実際のメール本文を得ることが出来ます。
body parts
マルチパートのエンティティのパートの一つなので、"body parts"はまた、bodyとheaderを持ちます。なのでこれで"bodyのbody"というということの意味が分かりますね。bodyはエンティティとほぼ同義です。もちろん、MIME::Entityインスタンスです。
entity
エンティティは、メッセージ部分か、body partsのどちらかを意味しています。すべてのエンティティにはheaderとbodyがあります。エンティティはMIME::Entityで表されます。
エンティティからheader(MIME::Header)とbody(MIME::Body)を得るメソッドがあります。
header
MIMEメッセージの一番上にあるものです。これは "Content-type", "Content-transfer-encoding",などを含んでいます。全てのMIMEエンティティはMIME::Headerで表されるヘッダーを持っています。headメソッドで、エンティティからMIME::Headerを得ることが出来ます。

message

一般的に、messageはネットワークで伝達されている、完全に(ないしトップレベルが)テキストであるものを意味します。
現在、"messages"をきちんと明白に定義するパッケージは、MIME::にはありません。messageとは、ファイルやファイルハンドルから読まれうるデータのストリームです。あなたは、MIME::Parserで返されたMME::Entityを、messageの全てであるとして扱えます。

Content-types

これは、通常どんな形式のデータがMIMEメッセージとして示されるかを、 majortype/minortype と言う感じで記述したものです。主要なものは以下の様になっています。より包括的なリストは、RFC-2046で見つけることが出来るかもしれません。

application
他のカテゴリーにはまらないデータで、特にアプリケーションで処理されるもの。

audio

オーディオ。
image
グラフィックスデータ。
message
通常のメッセージ、メールまたはMIMEメッセージ 。
multipart
他のメッセージを含むメッセージ 。

text

人が読むことになっている、文のデータ。

video

ビデオかビデオ+オーディオデータ。

Content transfer encodings

これは、メッセージのbodyが安全な転送のためにどのようにパッケージされるかということです。主要な5つのMIMEエンコーディングが以下に挙げられています。より包括的なリストは、RFC-2046で見つけることが出来るかもしれません。

7bit
コード化が全く行われません。 このラベルは8ビットの文字は一切無いことを主張し、改行コードを含んだ文字数が1000を超えないことを主張しています。
8bit
コード化は全く行われません。このラベルは8ビットの文字があるかもしれないことを主張し、改行コードを含んだ文字数が1000を超えないことを主張しています。
binary
コード化は全く行われません。このラベルは8ビットの文字があるかもしれないことを主張し、改行コードを含んだ文字数が1000を超えるやもしれないことを主張しています。まずメールゲートウェイを通り抜けられることは無いでしょう。

base64

スタンダードなエンコーディング。(それは任意の2進のデータを7ビットのドメインにマッピングします)。
非ASCII文字を含むメッセージ(例えば、ラテン語-1、ラテン語-2、またはいかなる他の8ビットのアルファベットも)をコード化することの役に立ちます。

quoted-printable

スタンダードなエンコーディング。(それは任意のline-orientedのデータを7ビットのドメインにマッピングします)。非ASCII文字を含むメッセージ(例えば、ラテン語-1、ラテン語-2、またはいかなる他の8ビットのアルファベットも)をコード化することの役に立ちます。

 

 

Webコンサルタント中山陽平公式サイトお悩みの方へ。一回のご相談で解決することもあります
ラウンドナップ・コンサルティングへのお問合せ方法 お電話でのご相談もお気軽に。[048-234-3361](10〜16 土日祝日除)全国対応 24時間受付 お問合せメールフォーム

コメントはこちらから

Loading Facebook Comments ...

No Trackbacks.