H"へメール転送


私はH"を使ってます。 インターネットメールが出来て便利です。
けど、『今出かけているからメールはxxxxx@pdx.ne.jpに送ってねー』なんて 非常に原始的です。 だからいつも使っているメールアドレスから転送すればバッチリですね。
転送設定はお決まりの.forwardに転送先メールアドレスを記述すればオッケー 簡単ですね。 しかあし、このまま転送先にH"のアドレスを記述すると・・・・
なんと添付ファイルとかも転送されちゃう! これじゃメールボックスがすぐにパンクしちゃう!
ってんで、メール本文は転送するけど添付ファイルは転送しないスクリプト を作成しましたので、ここに紹介します。

まず、添付ファイルありとなしで何が違うのか? インターネットとかで調べれば良いんでしょうけど、手っ取り早いのは 自分でメールを送ってみること。
というわけで添付ファイルありを自分宛てに送ってみました。
From xxxxx@xxxxx.com Wed Jun 21 10:22 JST 2000
Message-Id: <200006210117.xxxxx@xxxxxx.com>
Date: Wed, 21 Jun 2000 10:23:44 +0900
From: ryo ikuyama <xxxxx@xxxxx.com>
To: xxxxx@xxxxx.com
Subject: =?ISO-2022-JP?B?GyRCRTpJVSVVJSElJCVrJE4bKEI=?=
 TEST
Content-Length: 59584
Content-Type: multipart/mixed; boundary="U2F0LCAxNSBBcHIgMjAwMCAxMDoyMzo0NCArMDkwMA=="

--U2F0LCAxNSBBcHIgMjAwMCAxMDoyMzo0NCArMDkwMA==
Content-Type: text/plain; charset=ISO-2022-JP

添付ファイルのメールのテストです。



--U2F0LCAxNSBBcHIgMjAwMCAxMDoyMzo0NCArMDkwMA==
Content-Type: image/jpeg; name="PIC00001.jpg"
Content-Disposition: attachment;
 filename="PIC00001.jpg"
Content-Transfer-Encoding: base64

/9j/4AAQSkZJRgABAgEAkACQAAD/4AQQSkZYWAAQ/9j/2wBDABsSFBcUERsXFhceHBsgKEIrKCUl
FC4PHWqiD/DNWjPoXrRtk0LMMhZAT9K9o/tSa1hS6tfIMskQ8mNCeB9K83Hxu4nXhHqV7X4s2sMx
ttXguNMugSDJF908+lbL+JrLVIy9ve2V2G6YIB9e1cLo8uiO1tH/2Q==

--U2F0LCAxNSBBcHIgMjAwMCAxMDoyMzo0NCArMDkwMA==
Content-Type: application/octet-stream; name="test.c"
Content-Disposition: attachment;
 filename="test.c"
Content-Transfer-Encoding: base64

LyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
KioqKioqKioqKioqKioqKioqKiovDQovKiAgQmV0dHkgg0qBW4Nsg4uLpJLKlZQgg3WDiYNig06D
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICovDQovKi0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0qLw0Kdm9pZCBlbmQodm9pZCkNCnsNCn0NCg==

--U2F0LCAxNSBBcHIgMjAwMCAxMDoyMzo0NCArMDkwMA==--
添付ファイルなしはどうなっていたかと言うと、ヘッダー部にある Cntent-Type: が違っていました。
Content-Type: text/plain; charset=ISO-2022-JP
でした。
添付ファイルありだとここが
Content-Type: multipart/mixed; boundary="U2F0LCAxNSBBcHIgMjAwMCAxMDoyMzo0NCArMDkwMA=="
になってました。 添付ファイルの有無の判定はCntent-Typeがmultipart/mixed かそうでないかで判定出来そうです。
それから添付ファイルありの時にある"boundary"は読んで字のごとく 区切りの為の文字列でしょう。 でも、本文中にある区切り文字列には先頭に"--"がついていますね。 それから本文最後の区切り文字列には先頭に"--"と最後にも"--"がついていました。

添付ファイルありだと、本文中に区切り文字列が出てきて、またヘッダーが始まる みたいです。ヘッダーと本文の境はメインのヘッダーと本文の区切りと同じく 改行のみの行になっています。

ってことで作成した設計書
メイル転送スクリプト案
現在はryo@my-machine.comからxxxxx@xxxxx.xxxと
xxxxx@pdx.ne.jpにメール転送を.forwardにより単純に転送
しているが、pdxの方に添付ファイルを転送するとサーバ容量
によりエラーになってしまう。

そこで、pdxに転送するのは本文のみとし、添付ファイルは転送
しない仕組みを考えた。

.forwardの中身

現在
xxxxx@xxxxx.xxx
xxxxx@pdx.ne.jp

新
xxxxx@xxxxx.xxx
"| ./mailtrans.pl"

./mailtrans.plスクリプトにより添付ファイル削除後のメールを
pdxに転送する。


mailtrans.plフロー

ヘッダを解釈
Content-Typeを調べる
ヘッダはそのまま一時ファイルに出力(変更)
ヘッダからFromとSubjectを抜き出して変数に格納する。
text/plainの場合{
    本文をそのまま一時ファイルに出力
}
multipart/mixedの場合{
    $boundary文字列取得
    $outf = OFF;
    $headf = ON;
    while(本文){
        "--"$boundary"--"を見つけたら{
            break;
        }
        "--"$boundaryを見つけたら{
            $headf = ON;
            $outf = OFF;
        }
        if($headf == ON){
            /Content-Typeがtext/plainなら$outf=ON;
            改行のみなら$header = OFF;
        }else{
            if($outf == ON){
                一時ファイルに出力
            }
        }
    }
    一時ファイルをxxxxx@pdx.ne.jpに転送
}
終了
設計書と実際のスクリプトはいくつか違っていますが気にしないでください。
スクリプト名も違いますね。
メール一番最後の"--"$boundary"--"を見つけたときの処理が実際のスクリプト には入っていませんが、支障ないのでやめました。

訳わからないメモ書き見たいな設計書じゃなんだかわからないだろうから 簡単に処理を説明します。
初めにヘッダーをなめてFromとSubjectを抜き出します。 エンコードとか抜きにしてそのまま再利用する様にしています。
これでjcode.plを使う必要がなくなりました。
それからContent-Typeを調べてmixedならば添付ファイルありと判定し、 それ以外なら添付ファイルなしとしました。 うーこんなんで良いのだろうか・・・
それから添付ファイルありの場合は区切り文字列をContent-Typeの行から 抜き出して$boundaryに格納しています。

ヘッダー処理が終わったら次は本文の処理。
ヘッダーをなめて添付なしと判定したのなら本文はそのままtempfileに書き込みます。
添付ファイルありの場合はその本文中にまたある、サブのヘッダーと本当の本体を 以下の方法で区別しています。
区切り文字列が見つかったらそれ以降はヘッダー部分
ヘッダー処理中に改行のみの行が見つかったらそれ以降は本体部分
です。 ヘッダー部分にはそれに続く本当の本体部分のContent-Typeが記述されているので、 その部分を見て、text/plainなら続く本体部分はメールの本文と判定しています。 text/plain以外ならなんらかの添付ファイルですので続く本体部分は転送しないように します。
ここに更にmultipart/mixedって場合とかあるんでしょうか?
ヘッダー部分のContext-Typeにより続く本体を転送するかしないかを判定して $outfをセット、クリアしています。 ヘッダー処理中に改行のみの行が出来たら本体部分の開始です。 $outfを見て転送するのなら区切り文字列がでてくるまでtempfileに書き込みます。 区切り文字列が出てきたら再びサブのヘッダー処理を行います。
これをメール本文全体分処理をして、最後にsendmailに流し込んで転送しています。

ヘッダーには他にもいろいろと情報が入っているのですが、H"で見られるのは 差出人と件名ぐらいなので他のDateとかは全て削除しています。
Error-To:とかつけた方が良いかなって思ったけど、転送先はいつも同じだから いいかなって思ってつけていません。

このスクリプトを自分のホームに置いて、実行属性つけて.forwardを設定して 完成です。 .forwardの設定は、このスクリプトに送られてきたメールを流し込む為です。
自分のホームにある(なければ作成)、 .forwardに
"| ./mailforward.pl"
の一行を追加します。

ざざざっと説明しましたけどわかりますか?
実際には私はbigfoot.comのメール転送 サービスを利用していて、ここである程度フィルタリングしています。
DMはAのメールアドレスに転送してそうじゃないメール(MLやメルマガ)はBの アドレスへ転送と言うようにしています。
今回の転送スクリプトはAのところに設置して、DMのメールの更に添付ファイルを 削除した物をH"に転送って事になります。

このスクリプトを改良してTo:フィールドをチェックして転送する/しないを 判定すればbigfoot.comのフィルタリング/転送サービスは必要ないですね。
あと、ブラックリストとか作成しておけばゴミメールはdev/nullへってね。
今度時間があったら作成してみようと思います。

見苦しい物ですが最後にソースを載せておきます。
助言、意見等ありましたらメール下さい。お願いします。
#!/usr/bin/perl
$sendmail = '/usr/lib/sendmail';
$forwardto = 'To: xxxxxxx@pdx.ne.jp';
$tempfile = './tempfile.txt';

&make_mail;
&mail_forward;

sub mail_forward {
    open(OUT,"| $sendmail -t") || die "Cannnot open $sendmail";
    print OUT "$forwardto\n";
    print OUT "$from";
    print OUT "$subject";
    print OUT "\n";
    open(TEMP,"<$tempfile") || die "Cannot open $tempfile.";
    while(<TEMP>){
        print OUT;
    }
    close(TEMP);
    close(OUT);
}

sub make_mail {
    open(TEMP,">$tempfile") || die "Cannot open $tempfile.";
    open(STDIN);
    $mainheaderf = 1;                   #ヘッダーフラグセット
    $mixf        = 0;                   #添付ファイル有無フラグクリア
    $headf       = 0;                   #途中のヘッダーフラグ
    $outf        = 0;                   #出力フラグ
    while(<STDIN>){
        if($mainheaderf){               #メインのヘッダー処理
            if(/^$/){                   #改行だけの行
                $mainheaderf = 0;       #次からは本文
            }
            if(/^From:/){               #Fromの行
                $from = $_;
            }
            if(/^Subject:/){            #Subjectの行
                $subject = $_;
            }
            if(/^Content-Type:/){       #Content-Typeの行
                if(/mixed/){            #添付あり
                    $mixf = 1;
                    ($temp,$boundary) = split("=",$_,2);
                    $boundary =~ s/\"//g;
                }
            }
        }else{                          #本文処理
            if($mixf){                  #添付ファイルありの場合
                if(/^--$boundary$/){    #区切り文字列
                    $headf = 1;         #ヘッダーの開始
                    $outf  = 0;         #出力フラグクリア
                }
                if($headf){             #ヘッダー処理
                    if(/^Content-Type:/){   #Content-Typeの行
                        if(/text\/plain/){  #text/plainなら
                            $outf = 1;  #出力フラグオン
                        }else{          #text/plainじゃないなら
                            $outf = 0;  #出力しない
                        }
                    }
                    if(/^$/){           #改行だけの行なら
                        $headf = 0;     #ヘッダー部終了
                    }
                }else{                  #本文処理
                    if($outf){          #出力して良いなら
                        print TEMP;     #一時ファイルに格納
                    }
                }
            }else{                      #添付ファイルなしの場合
                print TEMP;             #全文をそのまま一時ファイルへ
            }
        }
    }
    close(TEMP);
    close(STDIN);
}

この記事は数年前に作成した物です。 my-machine.comのドメインはもう使っていません。 bigfootのフィルタリングサービスももう無いかも知れません。 ご了承ください。
2002年春からH"は受信無料のライトEメールなるサービスが始まっています。 受信は246バイトまでですが、重要メールが来たことがわかるので便利です。 メールの先頭から246バイトはH"へ転送。 添付ファイルを削除した全文をvisor用に作成したメールアドレス xxxxxx@ikuyama.netへ転送ってしています。 H"で最初の246バイトだけ読んで、必要ならばVisorで全文受信ってしています。 外出時にVisorもって行かなかったら意味なしですけどね。 (July 30,2002)

Back to home
mailto:ryo@my-machine.com
メールはこちらから