フォームからのメール送信 ( sendmail )

《 INDEX 》    《 HOME 》   

■ 概要

 《 必要条件 》 

 《 完成版サンプル 》 


■ メールの送信

《 CGIソース 》


#!/usr/local/bin/perl

# 初期設定 -----------------------------------------------#

#
# sendmailへのパス
#
$sendmail = '/usr/lib/sendmail';

#
# jcode.plへのパス
#
$jcode = './jcode.pl';

#
# メールの送付先
#
$to = 'zzzz@xxxxxx.xx.xx';

#
# メールの題名
#
$subject = 'CGIメール送信サンプル';

#
# 確認ページより戻るでリンクされるURLを指定
#
$back = 'http://www.site-cooler.com/';

# 処理開始 -------------------------------------#

# //////////////////////////////////////////////#
#  事前処理
# //////////////////////////////////////////////#

# 文字コードライブラリの読込み
require $jcode;

# //////////////////////////////////////////////#
#  QUERY復元処理
# //////////////////////////////////////////////#

if($ENV{REQUEST_METHOD} eq "POST"){
    read(STDIN,$input,$ENV{CONTENT_LENGTH});
} else {
    $input = $ENV{QUERY_STRING};
}

foreach ( split('&', $input ) ){

    ($name, $value) = split('=',$_,2);
    $value =~ s/\+/ /g;
    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
    $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
    $html{$name} = $query{$name} = $value;

}

# //////////////////////////////////////////////#
# 送信データの作成
# //////////////////////////////////////////////#

# ---------- 送信者氏名 ---------- #
if ($query{name}){
    $mail_body = "\n《 お名前 》\n$query{name}\n";
}

# ---------- メールアドレス ---------- #
if ($query{mail}){
    $mail_body .= "\n《 メールアドレス 》\n$query{mail}\n";
}

# ---------- URL ---------- #
if ($query{url}){
    $mail_body .= "\n《URL 》\n$query{url}\n";
}

# ---------- コメント ---------- #
if ($query{comment}){
    $mail_body .= "\n《 コメント 》\n$query{comment}\n";
}

# //////////////////////////////////////////////#
# MAIL送信
# //////////////////////////////////////////////#

&jcode'convert(*mail_body,'jis');
&jcode'convert(*subject,'jis');

open(MAIL,"| $sendmail -t") || &error_exit("sendmailの起動に失敗しました");

# ヘッダ情報出力
print MAIL "To: $to\n";
print MAIL "From: $query{mail}\n";
print MAIL "Subject: $subject\n";
# 本文出力
print MAIL "$mail_body\n";

close(MAIL) || &error_exit("メールの送信に失敗しました");

# //////////////////////////////////////////////#
# HTML出力
# //////////////////////////////////////////////#

print "Content-type: text/html\n\n";
print '<HTML><HEAD>'."\n";
print '<TITLE>送信完了</TITLE>'."\n";
print '</HEAD><BODY>'."\n";
print '<P>'."\n";
print '<CENTER><H2>正常のに送信しました。</H2></CENTER>'."\n";
print '</P>'."\n";
print '<DIV ALIGN="right"><H3>';
print '<A HREF="' .$back. '">戻る</A>';
print '</H3></DIV>'."\n";
print '</BODY></HTML>'."\n";

exit;

# //////////////////////////////////////////////#
# サブルーチンの定義
# //////////////////////////////////////////////#

# エラー処理------------------------------------#
sub error_exit {

    print "Content-type: text/html\n\n";
    print '<HTML><HEAD>'."\n";
    print '<TITLE>Error Request</TITLE>'."\n";
    print '</HEAD><BODY>'."\n";
    print '<P>'."\n";
    print '<CENTER><H2>'.$_[0].'</H2></CENTER>'."\n";
    print '</P>'."\n";
    print '<DIV ALIGN="right"><H3>';
    print '<A HREF="javascript:history.back()">戻る</A>';
    print '</H3></DIV>'."\n";
    print '</BODY></HTML>'."\n";
    exit;

}



《 解説 》

  1. ここではsendmailへのパスjcode.plへのパス宛先メールの題名戻るアドレス指定をそれぞれ指定します、ここは使用されている環境に合わせて値を変更して下さい。sendmailは大抵はこの場所にあると思いますが変更が必要であれば変更して下さい。メールアドレスはこのメールが送信される送信先になります。

    初期設定


  2. フォームからのPOST以外でもデータを引き取るようにしてみます。HTMLからスクリプトの後に?mail=knave@excite.co.jp&name=knave&comment=sampleのように呼び出します。

    if($ENV{REQUEST_METHOD} eq "POST"){
        read(STDIN,$input,$ENV{CONTENT_LENGTH});
    } else {
        $input = $ENV{QUERY_STRING};
    }


  3. jcode.plを使って7ビットjisコードへ変換します。ここでmail_bodyが《送信データの作成》で作成した本文、subjectが題名になります。又jcode.plは型グロブを引数として受け取りますのでこの変数はレキシカル変数ではエラーとなってしまいます。《 Perl講座参照 》

    &jcode'convert(*mail_body,'jis');
    &jcode'convert(*subject,'jis');


  4. 初期設定で指定したパスにあるsendmailをファイルハンドル"MAIL"で開きます、ファイル名の先頭に "|" を付けると、そのファイル名をコマンドとして解釈し、ファイルハンドルへの出力がパイプを通じて、そのコマンドへ入力されます。この時のファイルハンドルは任意で構いません。

    open(MAIL,"| $sendmail -t")


  5. メールヘッダを出力します。それぞれ《To:宛先》、《From:送信者》、《Subject:題名》を表わします。

    print MAIL "To: $to\n";
    print MAIL "From: $query{mail}\n";
    print MAIL "Subject: $subject\n";


  6. メール本文を出力しファイルハンドルを閉じます。今回は正常にファイルハンドルを閉じれなければエラーにします。

    print MAIL "$mail_body\n";

    close(MAIL) || &error_exit("メールの送信に失敗しました");


■ 入力データのチェック

未入力項目のチェック


# 名前------------------------------------------#
if(!$query{name}) {
    &error_exit("名前が入力されていません。");
}

# メールアドレス--------------------------------#
if(!$query{mail}) {
    &error_exit("メールアドレスが入力されていません。");
}

# コメント--------------------------------------#
if(!$query{comment}) {
    &error_exit("コメントが入力されていません。");
}


《 解説 》

  1. 環境変数の値が未定義で無い事を確認します。未定義であればエラーページを表示させます。

    if(!$query{*****}) {
        &error_exit("***が入力されていません。");
    }


不正な入力のチェック

【不正なメールアドレスの確認。(簡易版)】

正規表現を用いてメールアドレスの書式をチェックします。ただしこれは完全では無くあくまで簡易版です。メールアドレスはコメントをネストする事も出来るので確実な表現は出来ない?ようです。

# メールアドレスの形式確認----------------------#
if($query{mail} !~ /.+\@.+\..+/ || /,/){
    &error_exit("メールアドレスの書式が不正です");
}



【メール本文のピリオド"."だけの行を変更する】

これは《 Perl講座-Perlからメールを送信 》でも説明してありますが、メール本文にピリオド"."一つだけの行があるとその行で「メールの本文は終わりだよ」という意味になってしまい、メールを送信するとピリオド以降の本文は送信されません。ピリオドの後ろにもう一つをつける事によってピリオド一つだけの行にならないようにします。

# ---------- ピリオドだけの行を無くす ---------- #
$mail_body =~ s/\x0D\x0A|\x0D|\x0A/\n/g;
$mail_body =~ s/(\n)\.(\n)/\1\.\.\2/g;



■ 送信データの表示

《 完成版ソース 》


#!/usr/local/bin/perl

# 初期設定 -----------------------------------------------#

#
# sendmailへのパス
#
$sendmail = '/usr/lib/sendmail';

#
# jcode.plへのパス
#
$jcode = './jcode.pl';

#
# メールの送付先
#
$to = 'zzzzz@xxxxxx.xx.xx';

#
# メールの題名
#
$subject = 'CGIメール送信サンプル';

#
# 確認ページより戻るでリンクされるURLを指定
#
$back = 'http://www.site-cooler.com/';

#
# 呼出し元。チェックする時はhttpから始まるURLを指定
#
$referrer = '';

# 処理開始 -------------------------------------#

# //////////////////////////////////////////////#
#  事前処理
# //////////////////////////////////////////////#

# 文字コードライブラリの読込み
require $jcode;

# 呼出し元の確認
if(!(!$referrer || $referrer eq $ENV{HTTP_REFERER})){
    &error_exit("呼出し元が不正です");
}

# //////////////////////////////////////////////#
#  QUERY復元処理
# //////////////////////////////////////////////#

if($ENV{REQUEST_METHOD} eq "POST"){
    read(STDIN,$input,$ENV{CONTENT_LENGTH});
} else {
    $input = $ENV{QUERY_STRING};
}

foreach ( split('&', $input ) ){

    ($name, $value) = split('=',$_,2);
    $value =~ s/\+/ /g;
    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
    $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
    $html{$name} = $query{$name} = $value;

}

# //////////////////////////////////////////////#
# 入力データのチェック
# //////////////////////////////////////////////#

# 名前------------------------------------------#
if(!$query{name}) {
    &error_exit("名前が入力されていません。");
}
# メールアドレス--------------------------------#
if(!$query{mail}) {
    &error_exit("メールアドレスが入力されていません。");
}
# コメント--------------------------------------#
if(!$query{comment}) {
    &error_exit("コメントが入力されていません。");
}
# メールアドレスの形式確認----------------------#
if($query{mail} !~ /.+\@.+\..+/ || $query{mail} =~ /,/){
    &error_exit("メールアドレスの書式が不正です");
}

# //////////////////////////////////////////////#
# 送信・表示データの作成
# //////////////////////////////////////////////#

#
# 表示用データのデコード
#
&decode(\%html);

# ---------- 送信者氏名 ---------- #
if ($query{name}){
    $mail_body = "\n《 お名前 》\n$query{name}\n";
    $html_body = "<DT>《 お名前 》<BR>\n";
    $html_body .= "<DD>$html{name}<BR><BR>\n";
}

# ---------- メールアドレス ---------- #
if ($query{mail}){
    $mail_body .= "\n《 メールアドレス 》\n$query{mail}\n";
    $html_body .= "<DT>《 メールアドレス 》<BR>\n";
    $html_body .= "<DD>$html{mail} <BR><BR>\n";
}

# ---------- URL ---------- #
if ($query{url}){
    $mail_body .= "\n《URL 》\n$query{url}\n";
    $html_body .= "<DT>《 URL 》<BR>\n";
    $html_body .= "<DD>$html{url}<BR><BR>\n";
}

# ---------- コメント ---------- #
if ($query{comment}){
    $mail_body .= "\n《 コメント 》\n$query{comment}\n";
    $html_body .= "<DT>《 コメント 》<BR>\n";
    $html_body .= "<DD>$html{comment}<BR><BR>\n";
}

# ---------- ピリオド1つだけの行を無くす ---------- #
$mail_body =~ s/\x0D\x0A|\x0D|\x0A/\n/g;
$mail_body =~ s/(\n)\.(\n)/\1\.\.\2/g;

# //////////////////////////////////////////////#
# MAIL送信
# //////////////////////////////////////////////#

&jcode'convert(*mail_body,'jis');
&jcode'convert(*subject,'jis');

open(MAIL,"| $sendmail -t") || &error_exit("sendmailの起動に失敗しました");

# ヘッダ情報出力
print MAIL "To: $to\n";
print MAIL "From: $query{mail}\n";
print MAIL "Subject: $subject\n";
# 本文出力
print MAIL "$mail_body\n";

close(MAIL) || &error_exit("メールの送信に失敗しました");

# //////////////////////////////////////////////#
# HTML出力
# //////////////////////////////////////////////#
&jcode'convert(*subject,'sjis');
&jcode'convert(*html_body,'sjis');

print "Content-type: text/html\n\n";
print '<HTML><HEAD>'."\n";
print '<TITLE>送信完了</TITLE>'."\n";
# ---------- 本文の開始 ---------- #
print '</HEAD><BODY>'."\n";
print '<BLOCKQUOTE>'."\n";
print '<DIV ALIGN="left"><H2>次の内容で正常に送信しました。</H2>'."\n";
print '<BR><HR><BR>'."\n";
print '<DL>'."\n";
print $html_body ;
print '</DL>'."\n";
print '<BR><HR><BR>'."\n";
print '<DIV ALIGN="right"><H3>';
print '<A HREF="' .$back. '">戻る</A>';
print '</H3></DIV>'."\n";
print '</BLOCKQUOTE>'."\n";
print '</BODY></HTML>'."\n";

# //////////////////////////////////////////////#
# サブルーチンの定義
# //////////////////////////////////////////////#

# エラー処理------------------------------------#
sub error_exit {

    print "Content-type: text/html\n\n";
    print '<HTML><HEAD>'."\n";
    print '<TITLE>Error Request</TITLE>'."\n";
    print '</HEAD><BODY>'."\n";
    print '<P>'."\n";
    print '<CENTER><H2>'.$_[0].'</H2></CENTER>'."\n";
    print '</P>'."\n";
    print '<DIV ALIGN="right"><H3>';
    print '<A HREF="javascript:history.back()">戻る</A>';
    print '</H3></DIV>'."\n";
    print '</BODY></HTML>'."\n";
    exit;
}

# デコード処理----------------------------------#
sub decode {

    $tmp = shift;

    foreach $key ( keys( %$tmp ) ) {

        $$tmp{$key} =~ s/\&/\&amp;/g;
        $$tmp{$key} =~ s/</\&lt;/g;
        $$tmp{$key} =~ s/>/\&gt;/g;
        $$tmp{$key} =~ s/"/\&quote;/g;
        $$tmp{$key} =~ s/\x0D\x0A|\x0D|\x0A/<BR>/g;

    }
}


《 解説 》

  1. 今回も前回と同じく環境変数『HTTP_REFERER』を使用して、呼出し元を限って処理を行うチェックを行えます、この変数『referrer』に何も代入されていなければこのチェックは行われません。

    #
    # 呼出し元。チェックする時はhttpから始まるURLを指定
    #
    $referrer = '';

    if(!(!$referrer || $referrer eq $ENV{HTTP_REFERER})){
        &error_exit("呼出し元が不正です");
    }


  2. フォームからのデータを二つのハッシュで取得します。%htmlがブラウザに表示させる為のハッシュです。

        $html{$name} = $query{$name} = $value;



  3. これが今回とても重要となる部分です。ユーザからの入力データをそのまま表示してしまうと、ユーザがタグを入力してきた場合にコマンドが実行されるなどのセキュリティホールになる可能性があり、その為にタグをそれに対応する特殊文字に変換する必要があります。ブラウザに表示させるので《<、>、&、"、改行》をそれぞれ《&lt;、&gt;、&amp;、&quot;、<BR>》に変換します。

    &decode(\%html);

    # デコード処理----------------------------------#
    sub decode {

        $tmp = shift;

        foreach $key ( keys( %$tmp ) ) {

            $$tmp{$key} =~ s/\&/\&amp;/g;
            $$tmp{$key} =~ s/</\&lt;/g;
            $$tmp{$key} =~ s/>/\&gt;/g;
            $$tmp{$key} =~ s/"/\&quote;/g;
            $$tmp{$key} =~ s/\x0D\x0A|\x0D|\x0A/<BR>/g;

        }
    }


  4. HTMLに表示します。Shift-JISコードへ変換します。

    HTML出力



■ 完成版のダウンロードと設置法



《 INDEX 》    《 HOME 》   

Copyright (C) 2000-2004 Knave
http://www.site-cooler.com/