添付ファイルの送信方法

[上に] [前に] [次に]
どん 1999/07/04(日) 16:34:37
サーバ上のファイルを、フォームページで入力されたメールアドレスに
添付送信するにはどうしたらよいのでしょうか?
フォームページからローカルの画像を添付してメール送信する
CGIプログラム(PERL)は、よく見かけるのですが、その逆の方法です。

見よう見まねで、スクリプト中のメール送信部分に
print OUT "Content-Type: multipart/mixed;\n\n";
print OUT "Content-Type: application/octet-stream; name=\"***.gif\"\n";
print OUT 'Content-Transfer-Encoding: X-uuencode' . "\n";
print OUT "Content-Disposition: attachment; filename=\"***.gif\"\n\n";
を加えてみましたが、うまくいきません。

お分かりの方がいらっしゃいましたら、教えて下さい。

B-Cus 1999/07/05(月) 00:08:00
> print OUT "Content-Type: application/octet-stream; name=\"***.gif\"\n";
> print OUT 'Content-Transfer-Encoding: X-uuencode' . "\n";
データ形式がわかってるなら、octet-streamはお勧めしません。
ちゃんとしたMIME形式を付けましょう(text/plainとかね)。
あと、X-uuencodeってことはuuencodeでエンコードしてるってことです。

まずは自分で自分にマルチパートメールを送ってみて、その形式を
研究してみてください。

どん 1999/07/05(月) 20:29:48
ありがとうございます。
まだ、print文がそのまま送信されるという状況です。
某フォーム送信スクリプトをベースにしているのですが、
かなり苦闘していて、時間がかかりそうなので、
まずはお礼まで。


現在の状況を説明しますと、
1 思っていたほど単純ではないようだと気付きました。

2 添付ファイルが.lzh(か.zip)なので、
print OUT "Content-Type: application/x-lzh; name=\"$file\"\n";
にする。(過去ログを参考にして)

3 multipartで送信されてきた別のメールと比べてみると、
boundary="-----というヘッダがないので、基本的に欠落している処理が
あるのだろうということは分かりました。

4 ある解説書によると、フォーム部分に、ENCTYPE="multipart/form-data"を入れるというのは、
「ブラウザのファイル添付機能を使う場合」とありました。
私の場合は、サーバ上のファイルをセレクトするためのフォームなので、
不要なのかなと思ったりもしています。

5 CGI_Liteを使う方法もあると聞いたので、調べてみようかと思っています。

../199907/99070033.htm
↑たしかに解決方法を書いて欲しかったですね。

もうすこし考えてみます。

yasu [HomePage] 1999/07/05(月) 21:51:10
Outlook Expressなど、添付ファイル対応メーラーで、
添付ファイル付きのメールを作ってみて、ソースを
見てみればいいはずです。
ぼくは、一応理解できました。エンコードなどが必要です。
エンコードは、ライブラリがあります。
で、ソースを見て、データの部分だけを書き換えてしまえば
いいんです(ヘッダを含む)。
何回も自分当てに送信してやってみれば、出来るでしょう。

> boundary="-----というヘッダがないので、基本的に欠落している処理が
> あるのだろうということは分かりました。
これが、結構ややこしいです。
別に、なんでもいいのですが、データ中に含まれない文字じゃないと
いけません。
で、最後だけに、“--”を付ける・・・

謎なレスですいませ〜ん(_ _)o

B-Cus 1999/07/05(月) 23:12:42
MIMEについてはRFCを読むのが筋ですが、めんどくさいしわかりにくいので
 http://www.mew.org/info/mew.jis_12.html
をどうぞ。要は

From: from <from@mail.address>
Subject: hoge
To: to@mail.address
Mime-Version: 1.0
Content-Type: Multipart/Mixed; boundary=simple
Content-Transfer-Encoding: 7bit

--simple
Content-Type: text/plain; charset=iso-2022-jp
Content-Transfer-Encoding: 7bit
(1行空けるべし=空行)
これは〜のLZHファイルです。
(ここにも空行)
--simple
Content-Type: application/x-lzh; name="hoge.lzh"
Content-Transfer-Encoding: base64
(ここにも空行)
hoge.lzhをBASE64エンコーディングしたもの。
(ここにも空行)
--simple--

という感じでしょうか。
 Content-Type: application/x-lzh; name="hoge.lzh"
の代わりに
 Content-Type: application/x-lzh;
 Content-Disposition: attachment; filename="hoge.lzh"
という形式もあるようですが、どちらがお勧めなのかはわかりません。

で、最後に全体の長さを調べて Content-Length: に埋め込む、と。
(Content-Lengthってoptionalでしたっけ?)

多くのメーラでは、時刻やホスト名、プロセス番号などを加工したものを
boundaryとして使ってます。

BASE64は、いろいろライブラリはあるでしょうが、日本語マニュアルが
付いてるので、僕はmime_plsというのを使っています。

いいづか [HomePage] 1999/07/06(火) 00:06:46
宣伝です。
私の作った奴に、「ブラウザから文書を受け取り、
メールを作成して送信する」というのがあり、現在
添付ファイル送信機能を加えたベータ版があります。
ベータ版なのはマニュアル執筆の暇がないためであり、
実用に耐えうるレベルになってるはず(無保証)。
以下のURLにおいておきますので御参考まで。

http://www.releenet.co.jp/siizuka/pwbsmtp.txt

バウンダリはテキトウな文字(絶対出現しない奴)で
あれば何でもいいです。ご質問とは違うケースですが、
送信データをブラウザからもらう場合は、ブラウザが送って
きたバウンダリ文字列ををそのまま使っちゃうのが手っ取り
早いです。

どん 1999/07/06(火) 13:03:58
yasuさん、B-Cusさん、いいづかさん、ご丁寧に教えて下さいまして、
ありがとうごさいます。
いろいろ試していますが、まだうまくいっていません。
現在の状況は、次の通りです。

1 おかげさまで、なんとか添付ファイルの送信までたどりつきました。
ところが、添付ファイルを解凍することができません。

2 B-Cusさんに教えていただいたmime_plsを設置してみましたが、うまくいきません。
&base64encode($ufile);をいれてみましたがエラーになります。
解凍できない理由は、エンコードに失敗しているのためだろうと感じています。

3 B-Cusさんのコメントで
>で、最後に全体の長さを調べて Content-Length: に埋め込む、と。
>(Content-Lengthってoptionalでしたっけ?)
のところが、まだ調べられていません。

某スクリプトで、
($boundary) = $ENV{'CONTENT_TYPE'} =~ m#multipart/form-data; boundary=(.*)#;
$bound = "--" . $boundary;
というのがありましたが、そのままコピーしてもうまくいかないで、
工夫が必要なようです。

4 いいづかさんのスクリプトを試させていただいて気付いたのですが、
「参照」ボタンを押すとローカルのファイルをアップロード(メール)できますが、
ファイルのURLを直接入力してサーバ上のファイルを送ることも可能なんですね。
ということは、フォーム部分で、<input type=hidden name=file value="1">の
ようにし、処理部分で$file=[$FORM{'file'}]として、@files=(1.lzh,2.lzh,3.lzh)
から選ぶようにすれば、URLを知られたり入力させずにメール送信できるということに
なるのでは……。横道にそれました。


初期設定の一部と、メール送信部分を書き出してみました。
ここまで来たので、もう少し頑張ります。


require "./cgi-lib217.pl";
require "./lib/mimer.pl";

sub sendmail {
$mailto = $FORM{'email'};
$name = "$FORM{'name'}様";
$comment1 = "ありがとうございました。ファイルをお送りします。";
$comment2 = "LZH形式で圧縮されていますので、解凍してお使い下さい。";

$bound = 'wq5se3d1ew';
$ufile = '11.lzh';
&jcode'convert(*subject,'jis');
&jcode'convert(*name,'jis');
&jcode'convert(*comment1,'jis');
&jcode'convert(*comment2,'jis');
#メールサーバーを開きます
if (!open(OUT,"| $sendmail -t -f $ownermail")) { &error(1); }
#メールにコメント内容を送信
print OUT "FormMailer: FormMail\n";
print OUT "To: $mailto\n";
print OUT "From: $ownermail\n";
print OUT "Subject: $subject\n";
print OUT "MIME-Version: 1.0\n";
print OUT "Content-Type: multipart/mixed; boundary=\"$bound\"\n\n";
print OUT "\n";
print OUT "\-\-$bound\n";
print OUT "Content-Type: text/plain charset=\"iso-2022-jp\"\n";
print OUT "Content-Transfer-Encoding: 7bit\n";
print OUT "\n";
print OUT "$name\n\n";
print OUT "$comment1\n";
print OUT "$comment2\n";
print OUT "\n";
print OUT "\-\-$bound\n";
print OUT "Content-Type: application/x-lzh; name=\"$ufile\"\n";
print OUT "Content-Transfer-Encoding: BASE64\n\n";
print OUT "\n";
print OUT "Content-Disposition: attachment; filename=\"$ufile\"\n";
print OUT "\n";
print OUT "\-\-$bound\-\-\n";

close(OUT);
}

B-Cus 1999/07/06(火) 22:40:39
えっとね、メールの構造ですが、
 ヘッダ
 空行(改行)
 ボディ
です。空行がヘッダとボディのセパレータ。
 ヘッダ
 空行(改行)
 空行(改行)
 ABC
なら、ボディは「改行ABC」になります。multipartメールも同じです。
ですので、
> print OUT "Content-Type: application/x-lzh; name=\"$ufile\"\n";
> print OUT "Content-Transfer-Encoding: BASE64\n\n";
> print OUT "\n";
> print OUT "Content-Disposition: attachment; filename=\"$ufile\"\n";
> print OUT "\n";
はまずいと。BASE64なはずのボディに Content-Disposition: が入って
しまってます。あと、こういうときは
 print OUT <<END;
 ...
 END
とした方が見やすいと思います。

当方の環境では以下のコードでうまくいっているように見えます。
バグがあったら失礼。

require "../lib/src/mime_pls/mimew.pl";
require "jcode.pl";

$bound = 'wq5se3d1ew';
$ufile = 'hoge.lzh';

open(IN,"$ufile");
$lzhdata = join('',<IN>);
$base64_lzhdata = &bodyencode($lzhdata);
$base64_lzhdata .= &benflush;

#-------BEGINBEGIN---------
$header =<<END;
FormMailer: FormMail
To: $mailto
From: $ownermail
Subject: $subject
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="$bound"
END
#-------ENDEND----------

#-------BEGINBEGIN---------
$body =<<END;
--$bound
Content-Type: text/plain; charset="iso-2022-jp"
Content-Transfer-Encoding: 7bit

$FORM{'name'}様

ありがとうございました。ファイルをお送りします。
LZH形式で圧縮されていますので、解凍してお使い下さい。

--$bound
Content-Type: application/x-lzh; name="$ufile"
Content-Transfer-Encoding: BASE64

$base64_lzhdata
--$bound--
END
#-------ENDEND----------

&jcode::convert(*header,'jis');
&jcode::convert(*body,'jis');
$header .= "Content-length: ".length($body)."\n";

if (!open(OUT,"| sendmail -t -f $ownermail")) { &error(1); }
print OUT "$header\n$body";
close(OUT);

B-Cus 1999/07/07(水) 00:15:31
> $base64_lzhdata
> --$bound--
あ、この間にも空行が要りましたね。

どん 1999/07/07(水) 20:09:31
ありがとうございます。
すべてを教えていただく結果になってしまい、恐縮しています。
おかげさまで、教えていただいた方法で成功しました。
問題はないと思うのですが、
open(IN,"$ufile");に対応するclose(IN);がないので、付け加えてみました。

しかし、新たな問題が生じています。

1 せっかく教えていただいたのですが、テストで設置していたサーバでは
問題ないものの、本設置するサーバではどうしてもうまくいきません。
ためしに、直前にアクセスログをとる部分を加えてみたのですが、
そこまではうまく作動しているようなので、どうも、メール送信が引っかかって
いるようです。
別のフォームスクリプトは作動するので、mime_plsが原因なのかもと思っています。

2 送信の原理から考えて、不特定多数のプロバイダなどからアクセスして
いる人が、設置している管理者のサーバを通じてSMTP送信するということに
危険はないのかということに気付きました(今さらですが……)。
いたずらでの送信だけでなく、管理者の重要な情報などが漏れてしまう危険などがあれば、
設置を考え直す必要があるのではと考え始めています。


mime_plsのことはサーバ管理者に問い合わせてみようと思っています。

いいづか 1999/07/08(木) 00:28:32
もしかすると、どんさんのプロバイダではメール送信ができない
(sendmailが使えない、socketが使えないなど)かもしれません。
僕の使っていたところには、「sendmailとsocketの両方がOK」
「sendmailは使えるけどsocketがダメ」「全部ダメ」の
全パターンがありました。

どん [E-Mail] 1999/07/10(土) 23:35:09
[[解決]]
ありがとうございます。原因が分かりました。
B-Cusさんに教えていただいた中で
if (!open(OUT,"| sendmail -t -f $ownermail")) { &error(1); }
の部分が引っかかっていました。
$sendmailでした。
ケアレスミスなのですが、テスト用のサーバでは作動していたため、
見落としていました。

皆さん、本当にありがとうございました。

2つ前の投稿で書いた「新たな問題2」については、
これから勉強したいと思います。

なお、サーバの管理者に問い合わせたところ、
socketに関する制限等はないとのことでした。

[上に] [前に] [次に]