このページは福井県立大学の田中求之が2006年1月まで運用していた Mac のサーバ運用に関する会議室 「Web Scripter's Meeting」の記録です。情報が古くなっている可能性がありますのでご注意ください。

EIMS を活用する(AutoShare, SS for MJ の技術的背景)

発言者:田中求之
( Date Wednesday, March 08, 2000 02:09:35 )


EIMS 用のリストサーバの AutoShare や稲垣さんの Subject Share for
Macjordomo は、いずれも、EIMS のある仕組みを利用して、メールの処理を
行っています。その仕組みを解説します。そして、簡単なリストサーバを
AppleScript で作ってみます。

なお、EIMS 2.x 以下のバージョンを対象とします(3については確認していな
いため)。また EIMS の設定方法などについてはすでに理解済みとして説明し
ません。

AppleScript については、Tanaka's osax 2.0 をインストールしてある環境で
あることを前提とします。

●実験の準備

EIMS に適当なアカウントを作ってください(以下、説明中では、g3.tanaka
というドメインに test というアカウントを作ったものとして説明していきま
す)。そして、そのアカウントに届いたメールはフォルダ中にファイルとして
保存されるように設定してください。

アカウントが出来たら、自分が普段使っているアカウントから、新たに作った
実験用アカウントに、適当な内容のメールを送ってみてください。無事にフォ
ルダーの中にファイルが作られたら、準備完了です。


● EIMS のファイル処理

メールをファイルに保存するようにした場合、EIMS は指定されたフォルダー
の中にメールを1通ごとにファイルとして保存していきます。このとき、ファ
イルの形式は以下のようになっています。

■ファイルのデータ(データフォーク)
→メールのデータ(ヘッダと本文)が RFC822 に則った形式で記録されます
 簡単に言うと、漢字コードは JIS (ヘッダは MIME)、改行コードは CRLF
 になったものです。インターネットを流れるメールのデータがそのままの
 形で記録されたものです。

■ファイルのリソース
→3つのリソースが付加されます。
 'BODY' リソース
 →おそらくメールのデータのフォーマットを示すリソースと思われます
  通常、ID 8192 のリソースに '822 ' という4バイトの文字列(OS Type
  の方が正確か?)が入ったものになるはずです

 'STR ' リソース
 → ID 8192 のリソースが追加され、ここにメールの送り主のアドレスが記
  録されています

 'STR#' リソース
 → ID 8192 のリソースが追加され、Index 1 にメールの受取人のアドレス
  が記録されています。

たとえば、mact@antares.ecn.fpu.ac.jp から test@g3.tanaka にメールを送っ
て、それがファイルになった場合、

'STR ' ID 8192 は "mact@antares.ecn.fpu.ac.jp" (名前などは含まれない)
'STR#' ID 8192 Index 1 は "test@g3.tanaka" (やはり名前は含まれない)

ということになるわけです。

SMTP について理解されている方なら、STR リソースは SMTP の MAIL FROM で
STR# リソースの方は RCPT TO のアドレスだということがわかると思います。


で、EIMS の美味しいところは、この形式のファイルを EIMS がメールを保存
するのに利用している Mail Folder の中にある Incoming Mail フォルダーに
入れると、そのファイルを送信してくれるという所にあります。

以下のような実験を行ってもらえば、何のことを言っているのか分かっていた
だけると思います。

●実験

1:実験用のアカウントのメールのファイルをフォルダーから取り出す。

2:スクリプト編集プログラムを使って以下のスクリプトを実行し、STR# リ
ソースを書き換える。スクリプトを実行するとファイルの選択を要求しますの
で、先ほどフォルダーから取り出したメールのファイルを選択してください。

set myMail to choose file with prompt "メールのファイルは?" of type "TEXT"
MT Write Resource "your@mail.address" to myMail of type "STR#" ID 8192 index 1

* your@mail.address は、あなたの実際のメールアドレスにしてください
* ResEdit をお持ちの場合は、ResEdit で STR# ID8192 Index 1 を書き換え
てもらえばよいでしょう。

3:STR# を書き換えたメールを EIMS の Incoming Mail フォルダーに入れる

4:EIMS のコンソールや Mail Log の表示に注目 …ファイルがメールとし
て処理されるのが表示されるはずです。

5:メールソフトを使って自分のアカウントのメールを確認する
  →すると、自分が最初に実験用アカウントに送ったメールが、自分宛に送
   られてきているのが確認できるはずです。


このように、EIMS では、Incoming Mail に EIMS のフォーマットに則ったファ
イルを入れておくと、それをメールのデータとして発送してくれるという機能
があります。これをうまく使うことで、リストサーバを構築することができる
のです。

(続く)

稲垣 さんからのコメント
( Wednesday, March 08, 2000 13:15:44 )

 少し前の話題ですが・・・。

 夏に行われたWorkshop 475 in Kobeでの私の資料がありますので、こちらも
多少参考になるかと思います。



→  Send Mail Sample

田中求之 さんからのコメント
( Thursday, March 09, 2000 02:37:57 )

● EIMS のファイルの活用

EIMS のファイル送信機能の活用法に入る前に、EIMS がメールをファイルとし
て保存する機能を活用する方法を紹介しておきましょう。

たとえば、メールで送られてきたデータをファイルメーカーに取り込むという
処理を考えてみます。この場合、EIMS を使うのであれば、まずメールの受け
取り口になるアカウントを EIMS で作り、そのアカウントに届いたメールはファ
イルに保存するように設定します。これでメールはすべてファイルになってサー
バ上に存在することになりますので、あとは、このファイルのデータをファイ
ルメーカーに取り込む処理を AppleScript で組めばよいわけです。POP サー
バにアクセスして云々というネットワーク処理が不要になるわけです。なお、
ファイルメーカーをサーバマシンで動かすとサーバのパフォーマンスにかなり
の影響を与える場合がありますので、ファイルメーカはサーバとは別のマシン
で動かしておいて、AppleTalk 経由でファイルの処理を行うのが現実的でしょ
う。とはいえ、この処理もプログラムリンクを使えばいいだけですから、難し
いことではありません。

さて、では、EIMS がファイルに保存したメールをファイルメーカに取り込む
にはどうすればよいのか?

先に説明したように、EIMS が保存したファイルには、インターネットを流れ
るメールのデータが生の形で記録されていますので、そのままファイルメーカー
に読み込んでも活用は難しいものになります。ですから、メールのデータを、
通常我々が Mac で扱っているデータの形式に変換する処理を行う必要が出て
きます。

データの変換処理としては、以下のことを行う必要があります。

1:ヘッダ部分と本文のデータを分離する
2:ヘッダの折り返し処理を元に戻す
3:ヘッダ部分の MIME エンコードされた部分をデコードする
4:ヘッダと本文ともに、漢字コードを JIS から SJIS に変換する
5:ヘッダと本文ともに、改行コードを CRLF から CR に変換する

なお、メールのヘッダには、普通は我々にとって必要ない情報も色々と記載さ
れていますので、ヘッダの中から必要な情報(メールが発送された日時、差出
人のアドレス、題名など)を抜き出すという処理も必要になると思います。

では、これらの処理のやり方を順に見ていくことにします。なお、以下のスク
リプトの説明では、myMailFile に処理するファイル(EIMS が保存したメール
のファイル)が指定済みであることを前提に、これを処理するスクリプトを示
していきます。


●本文とヘッダ部分の分離

メールの本文とヘッダ部分を分離するには、CRLF+CRLF をデリミタに設定して、
item 1 と、それ以外に分けるという処理を行います。これは、メールにおい
てはヘッダ部分の終わりの合図として必ず空行が挿入される(=つまり改行コー
ドの CRLF が2回繰り返されることになる)という規則があることを利用する
わけです。

以下のスクリプトによって、myHeaders にヘッダ部分が、myBody にメールの
本文が収まることになります。

set crlf to return & (ASCII character 10)
set myMail to MT Read File myMailFile

set oldDel to AppleScript's text item delimiters
set AppleScript's text item delimiters to {crlf & crlf}
set myHeaders to text item 1 of myMail
set myBody to (rest of (text items of myMail)) as string
set AppleScript's text item delimiters to oldDel

* Applescript's text item delimiters を操作する場合には、面倒なようで
も、上記のように、初期値を保存しておいてから変更を行い、処理が終わった
時点で初期値に戻しておくようにするのが、不要なトラブルを避けるためには
よいと思います。特に CGI や複数のアプレットが入り乱れて動くような状況
では、上記のようなスクリプトを書かないと泣きを見ます。


●ヘッダの折り返し処理を元に戻す

メールのヘッダは、1行の長さが 80 バイトを越えるものは、途中で経由した
サーバや送信に使われたメールソフトによって折り返し処理が行われているの
が普通です。特に Subject (題名)に日本語が使われていた場合には、MIME
エンコード処理されるために元の日本語の SJIS の文字列に較べるとかなり長
くなりますので(Base64 エンコードによって 4/3 倍になるうえに MIME ヘッ
ダがくっつく)、折り返しされている可能性がかなり高くなります。ですから、
これを元に戻しておかないとヘッダの情報を正確に取り出せないことになりま
す。

ヘッダの折り返しが行われた場合、折り返しによって次の行に送られた部分は、
先頭にスペースかタブが挿入されるという決まりになっています。つまり、ヘッ
ダ部分の内部で行頭がスペースかタブになっているものは、前の行のヘッダの
折り返しによって送られた行であることになります。

これだけのことなら処理は比較的簡単なのですが、実際のメールにおいては以
下のような面倒なことがあります。

・行頭のタブ/スペースが1つとは限らない

・英文の場合はワードの切れ目で折り返されているのでスペースを挿入して単
純に結合できるが、日本語の場合は文字の切れ目で折り返されることがあるの
でスペースを挿入するとおかしくなる場合もあるし、英語同様にスペースを挿
入しなければならない場合もある(はっきり言って、ヘッダのデータだけでは
どちらに該当するか判断が難しい場合があります)。

厳密さを求めるときりがないので、ここでは、とりあえず、折り返しが行われ
ていた場合には、スペースを一つ挿入して前の行に続けるようにする、ただし
日本語が連続している場合にはスペースを入れずに連結する、という処理を行っ
ておくことにします。

先ほどのスクリプトで取り出した myHeaders を処理するスクリプトとしては
以下のようになります。

set myHeaders to MT Replace myHeaders search tab replace "  "
set myHeaders to MT Change Spaces To Tab myHeaders per 2
set myHeaders to MT Replace myHeaders search tab replace " "
set myHeaders to MT Replace myHeaders search ("?=" & crlf & " =?") replace "?==?"
set myHeaders to MT Replace myHeaders search (crlf & " ") replace " "

* Tanaka's osax 2.0fc1 以降のバージョンであれば以下のように書けます。

set myHeaders to MT Replace myHeaders search tab replace "  "
set myHeaders to MT Change Spaces To Tab myHeaders per 2
set myHeaders to MT Replace myHeaders search {tab, ("?=" & crlf & " =?"), (crlf & " ")} replace {" ", "?==?", " "}

(続く)

田中求之 さんからのコメント
( Thursday, March 09, 2000 09:35:41 )

あ、上記のスクリプトには、大きな欠点がひとつあって、それは、
意図的に書かれた複数のスペースも、すべて一つのスペースに
縮めてしまうというものです。

今夜にでも、修正します。

田中求之 さんからのコメント
( Friday, March 10, 2000 00:34:33 )

>今夜にでも、修正します。

色々なメールのヘッダを調べながらスクリプトを試していたんですが、これ、
厳密にやろうとすると結構めんどうですね。英文の場合でも、必ずしもスペースを
残したままで単純に連結すればよいというものではないようです。

やれやれ。

とりあえず、問題が少なそうな処理は以下のようになると思います。

set myHeader to MT Replace myHeader search tab replace " "
set AppleScript's text item delimiters to {crlf}

set myHeader to text items of myHeader
set myNewHeader to {}

repeat with thisLine in myHeader
    set thisLine to contents of thisLine
    if character 1 of thisLine is not " " then
        set end of myNewHeader to thisLine
    else
        set item -1 of myNewHeader to (item -1 of myNewHeader) & trim(thisLine)
    end if
end repeat

set myNewHeader to myNewHeader as string
set myNewHeader to MT Replace myNewHeader search "==?= =?" replace "==?==?"


-- 処理用ハンドラ
on trim(myText)
    set x to length of myText
    repeat with y from 2 to x
        if character y of myText is not " " then
            return " " & (text y thru -1 of myText)
        end if
    end repeat
    return myText
end trim


…結局、泥臭いことをやってるんですね。

なお、上記のスクリプトでは myNewHeader を文字列に直しちゃってますが
必要なヘッダだけ抜き出す場合には、リストのままにしておいて、そこから
必要なものを調べて抜き出すという処理を行うことになります。