|
Perl/CGI研究室 'PERL-LABO' TOPへ |
戻る(History.Back) |
メールにはファイルを添付することができます。 Perlとsendmailを使ってファイルを添付する方法を研究しましょう。
sendmailを使用してPerlからメールを送信するには、 メールヘッダを含むデータをsendmailに渡してあげるんでした。 残念ながら、ファイル名を指定するだけでそのファイルが添付されるような 便利な機能はないようで、 メールデータの中に自力でファイルが添付されていることを示すヘッダや 添付するファイルデータなどを加える必要があるようです。
ファイルを添付したときの、ヘッダなどを含むメールの内容は次のようになります。
Content-Type: Multipart/Mixed; boundary="(バウンダリー文字列)" Content-Transfer-Encoding:Base64 From: 送信元 To: 送信先 Subject: 件名 --(バウンダリー文字列) Content-Type: text/plain; charset="ISO-2022-JP" (メール本文) --(バウンダリー文字列) Content-Type: application/octet-stream; name="(添付ファイル名)" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="(添付ファイル名)" (添付するデータをbase64でエンコードしたもの) --(バウンダリー文字列)--
まず、「Content-Type: Multipart/Mixed; 〜」というので、 このメールが複数のパートに分かれていることを示します。 (バウンダリー文字列)というのは、任意の文字列で、 データの境界、パートの始まりを示すのに使用されます。 「--(バウンダリー文字列)」となっているのがデータの境界です。 この境界に続いて、そのパートの内容を「Content-Type」で指定してやります。 「Content-Type: text/plain;」となっている1つ目のパートがメール本文、 「Content-Type: application/octet-stream」という2つ目のパートが添付ファイルを 示すパートです。 「--(バウンダリー文字列)--」となっているのはメールデータの終わりです。
なんでこうなるのかというのは、とりあえずおいておきましょう (^^; こうゆうふうにすると、ファイルが添付されているとメーラーの方で処理してくれるわけです。 そういうルールなんですね。このルールの詳細については、またいつか研究することにします。
さて、問題は、添付するファイル本体ですが、 (添付するデータをbase64でエンコードしたもの)でなければいけません。 この点に注意しつつ、プログラムを作成してみました。
# v 1.04
package plab;
use Jcode;
use MIME::Base64;
# sendmailのパス
$sendmailpath = '/usr/sbin/sendmail';
# 引数 (差出人名, 差出人メールアドレス, 送信先名, 送信先メールアドレス,
# 件名, 本文 [, 返信先名, 返信先メールアドレス, 日時とホストを追加しない1]
# [, Cc名, Ccアドレス, Bcc名, Bccアドレス])
# いずれも空欄可
sub sendmail
{
local $from_name = $_[0];
local $from_adr = $_[1];
local $to_name = $_[2];
local $to_adr = $_[3];
local $subject = $_[4];
local $body = $_[5];
local $rep_name = $_[6];
local $rep_adr = $_[7];
local $notimehost = $_[8];
local $cc_name = $_[9];
local $cc_adr = $_[10];
local $bcc_name = $_[11];
local $bcc_adr = $_[12];
# Fromメールアドレスがからっぽだとエラーになるので
if ($from_adr eq "") {
return 0;
}
# JIS に変換します。
local $jis_body = Jcode::convert($body, 'jis');
# MIMEヘッダ内の日本語をエンコードします。
local $header_subject = mimeencode_headnamemail('Subject', $subject);
local $header_from = mimeencode_headnamemail('From', $from_name, $from_adr);
local $header_to = mimeencode_headnamemail('To', $to_name, $to_adr);
local $header_replyto = mimeencode_headnamemail('Reply-To', $rep_name, $rep_adr);
local $header_cc = mimeencode_headnamemail('Cc', $cc_name, $cc_adr);
local $header_bcc = mimeencode_headnamemail('Bcc', $bcc_name, $bcc_adr);
if (! open(MAIL, "| $sendmailpath -t")) {
return 0;
}
# メールヘッダ〜本文を出力します。
print MAIL "$header_from\n";
print MAIL "$header_to\n";
if ($rep_adr ne "") { print MAIL "$header_replyto\n"; }
if ($cc_adr ne "") { print MAIL "$header_cc\n"; }
if ($bcc_adr ne "") { print MAIL "$header_bcc\n"; }
print MAIL "$header_subject\n";
print MAIL "Content-Transfer-Encoding: 7bit\n";
print MAIL "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n";
print MAIL "\n";
print MAIL "$jis_body";
if ($notimehost ne "1") {
# ホスト名、送信時間を付加します。
local $ip = $ENV{'REMOTE_ADDR'};
local $host = gethostbyaddr(pack("C4", split('\.', $ip)), 2) || $ip;
local @tim = localtime(time());
local $year = $tim[5] + 1900;
local $mon = $tim[4] + 1;
local $t = sprintf('%02d:%02d:%02d', $tim[2], $tim[1], $tim[0]);
print MAIL "\n";
print MAIL "----------------------------\n";
print MAIL "DateTime : $year/$mon/$tim[3] $t\n";
print MAIL "Host : $host";
}
close MAIL;
return 1;
}
# メールヘッダを作る
# 引数(ヘッダ名, 名前, メールアドレス)
sub mimeencode_headnamemail
{
local ($head, $name, $mail) = @_;
if ($name eq "" && $mail eq "") { return ""; }
# 汚染チェック
$mail =~ s/\r|\n//g;
local $jis_name = Jcode::convert($name, 'jis');
local $mime_name = Jcode::mime_encode([\$jis_name]);
if ($name ne "" && $mail eq "") { return "$head: $mime_name"; }
else { return "$head: $mime_name<$mail>"; }
}
# 添付ファイル付きでメールを送る
# 引数 (添付するファイルパス, 添付するパス無しファイル名,
# 差出人名, 差出人メールアドレス, 送信先名, 送信先メールアドレス,
# 件名, 本文 [, 返信先名, 返信先メールアドレス, 日時とホストを追加しない1]
# [, Cc名, Ccアドレス, Bcc名, Bccアドレス])
sub sendmail_attach
{
local $fname = $_[0];
local $ftitle = $_[1];
local $from_name = $_[2];
local $from_adr = $_[3];
local $to_name = $_[4];
local $to_adr = $_[5];
local $subject = $_[6];
local $body = $_[7];
local $rep_name = $_[8];
local $rep_adr = $_[9];
local $notimehost = $_[10];
local $cc_name = $_[11];
local $cc_adr = $_[12];
local $bcc_name = $_[13];
local $bcc_adr = $_[14];
# Fromメールアドレスがからっぽだとエラーになるので
if ($from_adr eq "") {
return 0;
}
# ファイルを読み込んでBase64エンコードします
if (! open(FILE, "< $fname")) {
return 0;
}
$filesize = -s $fname; # ファイルサイズ
$readsize = read(FILE, $filebody, $filesize);
close(FILE);
$base64filebody = MIME::Base64::encode($filebody);
# JIS に変換します。
local $jis_body = Jcode::convert($body, 'jis');
# MIMEヘッダ内の日本語をエンコードします。
local $header_subject = mimeencode_headnamemail('Subject', $subject);
local $header_from = mimeencode_headnamemail('From', $from_name, $from_adr);
local $header_to = mimeencode_headnamemail('To', $to_name, $to_adr);
local $header_replyto = mimeencode_headnamemail('Reply-To', $rep_name, $rep_adr);
local $header_cc = mimeencode_headnamemail('Cc', $cc_name, $cc_adr);
local $header_bcc = mimeencode_headnamemail('Bcc', $bcc_name, $bcc_adr);
if (! open(MAIL, "| $sendmailpath -t")) {
return 0;
}
$boundary = "B4B5O6U7N8D9A0R1Y";
# メールヘッダを出力します。
print MAIL "$header_from\n";
print MAIL "$header_to\n";
if ($rep_adr ne "") { print MAIL "$header_replyto\n"; }
if ($cc_adr ne "") { print MAIL "$header_cc\n"; }
if ($bcc_adr ne "") { print MAIL "$header_bcc\n"; }
print MAIL "$header_subject\n";
print MAIL "Content-Type: Multipart/Mixed; boundary=\"$boundary\"\n";
print MAIL "\n";
# 本文を出力します。
print MAIL "--$boundary\n";
print MAIL "Content-Transfer-Encoding: 7bit\n";
print MAIL "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n";
print MAIL "\n";
print MAIL "$jis_body\n";
if ($notimehost ne "1") {
# ホスト名、送信時間を付加します。
local $ip = $ENV{'REMOTE_ADDR'};
local $host = gethostbyaddr(pack("C4", split('\.', $ip)), 2) || $ip;
local @tim = localtime(time());
local $year = $tim[5] + 1900;
local $mon = $tim[4] + 1;
local $t = sprintf('%02d:%02d:%02d', $tim[2], $tim[1], $tim[0]);
print MAIL "\n";
print MAIL "----------------------------\n";
print MAIL "DateTime : $year/$mon/$tim[3] $t\n";
print MAIL "Host : $host\n";
}
# 添付ファイルを出力します。
print MAIL "--$boundary\n";
print MAIL "Content-Type: application/octet-stream; name=\"$ftitle\"\n";
print MAIL "Content-Transfer-Encoding: base64\n";
print MAIL "Content-Disposition: attachment; filename=\"$ftitle\"\n";
print MAIL "\n";
print MAIL "$base64filebody\n";
# メールの終わり
print MAIL "--$boundary--\n";
close MAIL;
return 1;
}
1;
出力する内容が違うので、別の関数として作成しました。 sendmail_attach という関数です。 引数の最初に、添付するファイル名と、 メールを受け取った人が見えるファイル名を指定します。 あとは、最初に研究した通りにメールの内容を出力していくだけでした。 ファイルの内容をBase64エンコードする、という部分については、 前にJcodeの研究をしたときに少しだけでてきた MIME::Base64というモジュールのencode関数を呼び出すだけでできてしまいました。 作る前は、ちょっと難しそうだなと思ったんですが、 便利な関数があったおかげで簡単でした (^^ でもどうせなら、最初から便利なメール送信関数が用意されていたらいいのに… と思ったりして。
|
Perl/CGI研究室 'PERL-LABO' TOPへ |
戻る(History.Back) |
| Copyright (c) 'PERL-LABO' All Rights Reserved. リンクフリーです。 |