Search A.I.
Menu
ホーム

メールマガジン ホームページプログラミングテク

Windowsテク
Javaアプレット サンプル
Java Q & A
JavaScript Q & A
Perl Q & A
Perl レッスン
PHP レッスン
PHPテク
MS-DOS コマンド集
UNIX コマンド集
SQL コマンド集
SEの基礎講座
WEBシステム開発受注します
]無料フォームメール送信サービス
リンク集
Perl レッスン

1. Perl の基礎
2. Perlの文法、条件式
3. Perlの文法、条件式 - 続き
4. 配列について
5. ハッシュ配列について
6. Perlの基礎 - 続き
7. 関数について
8. 関数について - 続き
9. 文字列操作関数
10. 配列操作関数
11. ファイル操作
12. ファイル操作 - 続き
13. パラメータの受け渡し
14. クッキーについて
15. 総合練習
16. メール送信
17. ファイルアップロード
18. パッケージの使用方法
19. MySQL
20. MySQL - 続き(1)
21. MySQL - 続き(2)
22. PostgreSQL
23. 総合練習
24. 総合練習解答



16. メール送信

今日は、メール送信についてご説明いたします。

■メール送信について
WEBサーバにメールを送信するプログラム(メールエージェントと言います)が
インストールされている場合、Perlからメールを送信することができます。
通常、レンタルサーバなどにはメール送信機能が組み込まれています。

メールエージェントには、SendMailやQMailなどの種類があります。
Perlでは、これらのメールエージェントを起動することで、メールを送信する
ことができます。

■メール送信方法
Pealでメールを送信するには、メールヘッダを作成し、ファイルをオープンする
要領で、メールエージェントを起動させ、ハンドルに本文を書きます。

-----------------------------------------------------------------
# メールエージェントのパスを設定
$mailer = '/usr/lib/sendmail';

# メールヘッダを作成
$mlhd = "From: from@test.co.jp" . "\n" . "To: to@test.co.jp" . "\n" . "Subject: 件名です" . "\n\n";

# メール書き込みを開始する
open(MAIL, "| $mailer -t") or exit;

# メールヘッダを記述
print MAIL $mlhd;

# メール本文を記述
print MAIL "メール本文です。\n";

# メールをクローズする
close(MAIL);
-----------------------------------------------------------------

まず、メールエージェントのパスは、サーバによって異なりますので、使用している
サーバを調べてみてください。レンタルサーバの場合は、大抵ホームページに掲載
されています。

次にメールヘッダですが、Perlの場合、メールヘッダは自分で作成しなければ
なりません。メールヘッダには、送信者のメールアドレス、受信者のメール
アドレス、件名、返信先のメールアドレス、エラー時に返されるメールアドレス
などを記述します。省略も可能ですが、あて先を省略した場合はメールが
届きません。

メールヘッダの記述は、HTTPヘッダと似ています。
それぞれ、「名称: 内容\n」のように記述し、ヘッダの最後には、改行を 2回
繰り返します。

次にメールエージェントを起動します。open関数でパスを指定し、ハンドルを
受け取ります。起動時に、オプションを指定することもできますが、これは
メールエージェントの種類によって変わりますので、必要であれば、そちらを
調べてみてください。

ハンドルを取得したら、print関数でメールヘッダと本文の書き込みを行います。

最後にファイルと同様、ハンドルをクローズします。

ここまででメールは送信できますが、実はこのままでは日本語が文字化けして
しまいます。

■メールの文字コードについて
一般的にインターネットに流れているメールは、ほとんどの場合、JISコードという
文字コードが書かれています。そして、WindowsはシフトJIS、UNIXはEUCという
コードが通常使われているため、Perlでそのままメールを送信すると文字化けして
しまうのです。

そこで、文字コードを変換するという処理を加える必要があります。

Perlは、日本語がサポートされていないので、"jcode.pl"というライブラリを
読み込み、日本語文字コード変換関数を持ってこなくてはなりません。

この"jcode.pl"ファイルは、インストーラーに含まれていないので、持っていない
場合は、ダウンロードしてください。
ftp://ftp.iij.ad.jp/pub/IIJ/dist/utashiro/perl/

このライブラリの中に、convert関数が用意されているので、文字コードをJISに
変換します。

-----------------------------------------------------------------
# ライブラリの読み込み
require "./jcode.pl";

# 件名をJISコードに変換
jcode'convert(*mlsb, "jis");

# メール本文をJISコードに変換
jcode'convert(*mlms, "jis");
-----------------------------------------------------------------

上のサンプルは、"jcode.pl"ライブラリをプログラムと同じディレクトリに
置いた場合です。

もともとの文字コードがシフトJISでもEUCでも、自動的に判別し、JISコードに
変換してくれます。

 

★今日のまとめサンプルプログラム
-----------------------------------------------------------------
#! /usr/local/bin/perl

print "Content-type:text/html\n\n";

print << "END_OF_HTML";
<HTML>
<BODY>
END_OF_HTML

# メールエージェントのパス指定
$mailer = '/usr/lib/sendmail';

# 送信者のメールアドレス
$mlfr = 'from@test.co.jp';

# 宛先のメールアドレス
$mlto = 'info@searchai.jp';

# 件名
$mlsb = '件名です';

# 本文
$mlms = 'テストメッセージです。';

# 日本語ライブラリの読み込み
require "./jcode.pl";

# JISコードへ変換
jcode::convert(\$mlsb, "jis");
jcode::convert(\$mlms, "jis");

# メールヘッダ作成
$mlhd = "From: $mlfr" . "\n" . "To: $mlto" . "\n" . "Subject: $mlsb" . "\n\n";

# メール送信処理
$err = 0;
open(MAIL, "| $mailer -t -f'$mlfr'") or $err = 1;
if ($err == 0) {
print MAIL $mlhd;
print MAIL $mlms;
print MAIL "\n";
close(MAIL);
print 'メール送信正常に処理しました。';
}
else {
print 'メール送信エラー';
}

print << "END_OF_HTML";
</BODY>
</HTML>
END_OF_HTML

exit;
-----------------------------------------------------------------

■解説
レッスンの中ででてきたサンプルを少し整理したものです。

始めにメールエージェントのパス、送信者、宛先、件名、本文などを準備し、
JISコードへの変換を行い、メール送信処理をしています。

メールの送信結果をHTML上に出力しているので、メール送信に成功したかどうかを
確認できます。

 

★課題
1. HTML上に、メール送信者(text)、件名(text)、本文(textarea)のフォームを
作成し、POST送信で受け取って、自分のメールアドレスへ送信されるプログラムを
作成してください。

 

★前回の課題の解答
1. 簡易的な掲示板を作成してください。

→下のサンプルを参照してください。

-----------------------------------------------------------------
#! /usr/local/bin/perl

$title = '簡易掲示板';

#// データファイル
$file_name = './dengon.txt';

#// 最大件数
$msmax = 20;

#// クッキー
$cknm = 'bbs';

#// パラメタ取得
%data = &GetPara();
$md = $data{'md'};
$hd = $data{'hd'};
$ms = $data{'ms'};

#// 掲示板ファイル読み込み
if (!open(FIL, "$file_name"))
{
exit;
}
@rec = <FIL>;
close(FIL);

#// 投稿処理開始
if ($md eq '1')
{
#// データチェック
$hd =~ s/ / /g;
$hd =~ s/</&lt;/g;
$hd =~ s/>/&gt;/g;
$hd =~ s/^\s+//;
$hd =~ s/\s+$//;
$ms =~ s/ / /g;
$ms =~ s/</&lt;/g;
$ms =~ s/>/&gt;/g;
$ms =~ s/^\s+//;
$ms =~ s/\s+$//;
if ($hd eq '')
{
# ハンドルネームが空
exit;
}
if ($ms eq '')
{
# メッセージが空
exit;
}

#// クッキーデータセット
$hdc = $hd;

#// 掲示板編集
($ss, $mn, $hh, $dd, $mm, $yy, $yb) = localtime(time);
$yy += 1900;
$mm++;
$dt = sprintf("%04d/%02d/%02d %02d:%02d:%02d", $yy, $mm, $dd, $hh, $mn, $ss);
$rec = $dt . '_~|~_' . $hd . '_~|~_' . $ms . "\n";

unshift @rec, $rec;
for ($i = $#rec; $i >= $msmax; $i--)
{
pop @rec;
}

if (!open(FIL, ">$file_name"))
{
exit;
}
#// 排他処理
flock(FIL, LOCK_EX);

print FIL @rec;

flock(FIL, LOCK_UN);
close(FIL);

#// 投稿処理終了
}
elsif ($ENV{'HTTP_COOKIE'})
{
#// クッキー取得
%cook_data = &GetCookie();
$cook_data{$cknm} =~ s/%20/ /g;
@w = split(/\,/, $cook_data{$cknm});
$hd = @w[0];

#// クッキーデータセット
$hdc = $hd;
}

#// クッキーセット
$hdc =~ s/\,/%2C/g;
$cooks = "$cknm=$hdc;";
&SetCookie($cooks, 5184000);

print "Content-type: text/html\n\n";
print << "END_OF_HTML";
<HTML>
<BODY>
<CENTER>
<P><FONT style="font-size=12pt"><B>◆ 簡易掲示版 ◆</B></FONT></P>
<FORM action="$ENV{'SCRIPT_NAME'}" id="FORM1" method="post" name="FORM1">
<INPUT TYPE="hidden" NAME="md" VALUE="1">
<TABLE bgcolor="#b0b0b0" border="0" cellPadding="3" cellSpacing="2">
<TBODY>
<TR bgcolor="#f0f0f0">
<TD nowrap><FONT style="font-size=9pt">ハンドル</FONT></TD>
<TD nowrap><INPUT name="hd" size="22" maxlength="40" value="$hd">
</TR>
<TR bgcolor="#f0f0f0">
<TD nowrap><FONT style="font-size=9pt">メッセージ</font></TD>
<TD nowrap><INPUT name="ms" size="62" maxlength="200">
</TR>
</TBODY>
</TABLE>
<BR>
<TABLE bgcolor="#b0b0b0" border="0" cellPadding="3" ccllPladding="2">
<TBODY>
<TR bgcolor="f0f0f0">
<TD nowrap><INPUT name="submit1" type="submit" value=" 投稿 "></TD>
<TD nowrap><INPUT name="reset1" type="reset" value="リセット"></TD>
</TR>
</TBODY>
</TABLE>
</FORM>
END_OF_HTML

if (@rec) {
#// 掲示板ファイルヘッド表示
print << "END_OF_HTML";
<TABLE bgcolor="#b0b0b0" border="0" cellpadding="3" cellspacing="2">
<TBODY>
<TR bgcolor="#d0d0d0">
<TD nowrap><FONT style="font-size=9pt">日付</FONT></TD>
<TD nowrap><FONT style="font-size=9pt">ハンドル</FONT></TD>
<TD><FONT style="font-size=9pt">メッセージ</FONT></TD>
</TR>
END_OF_HTML

#// 掲示板ファイルボディ表示
foreach (@rec)
{
@w = split(/\_\~\|\~\_/, $_);
$dt = substr(@w[0], 0, 16);
$hd = @w[1];
$ms = @w[2];
print '<TR bgcolor=#f0f0f0>';
print '<TD nowrap><FONT style="font-size=9pt">', $dt, '</FONT></TD>';
print '<TD nowrap><FONT style="font-size=9pt">', $hd, '</FONT></TD>';
print '<TD><FONT size=-1>', $ms, '</FONT></TD>';
print '</TR>';
}

#// 掲示板ファイルテイル表示
print << "END_OF_HTML";
</TBODY>
</TABLE>
END_OF_HTML

#// HTMLテイル表示
}
print << "END_OF_HTML";
</CENTER>
</BODY>
</HTML>
END_OF_HTML

#------------------------------------------------------------------
# 関数 : GetPara
# 概要 : パラメータ取得
# 引数 : なし
# 戻値 : パラメータハッシュ配列
#------------------------------------------------------------------
sub GetPara
{
my $self = shift;
my($query_string); #// エンコードされたパラメータ全体
my(@a, $a); #// エンコードされたパラメータを分解したもの
my($name, $value); #// デコードされたパラメータ
my(%in);

#// パラメータの読み込み
if ($ENV{"REQUEST_METHOD"} eq "POST")
{
#// POSTなら標準入力から読み込む
read(STDIN, $query_string, $ENV{"CONTENT_LENGTH"});
}
else
{
#// GETなら環境変数から読み込む
$query_string = $ENV{"QUERY_STRING"};
}

#// 「変数名1=値1&変数名2=値2」の形式をアンパサンド(&)で分解
@a = split(/&/, $query_string);

# パラメータの取得
foreach $a(@a)
{
#// =(イコール)で分解
($name, $value) = split(/=/, $a);
#// + や %8A などのデコード
$value =~ tr/+/ /;
$value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex( $1 ))/eg;
#// 後で使用するため,$in{'パラメータ名'} に代入しておく
$in{$name} = $value;
}

return %in;
}

#------------------------------------------------------------------
# 関数 : SetCookie
# 説明 : クッキー設定
# 引数 : 保存する文字列
# : クッキーの有効時間(秒)
# 戻値 : なし
#------------------------------------------------------------------
sub SetCookie
{
my($data, %data, $str_cookie, $cookie_time);
my($sec, $min, $hour, $mday, $mon, $year, $wday);
my(@mons, @week, $dt);

$str_cookie = @_[0];
$cookie_time = @_[1];

#// 文字列のエスケープ
$str_cookie =~ s/\,/%2C/g;
$str_cookie =~ s/ /%20/g;
$str_cookie =~ s/;//g;
$str_cookie =~ s/([^\w\=\& ])/'%' . unpack("H2", $1)/eg;

#// 有効期限設定
($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime(time + $cookie_time);
@mons = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
@week = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
$dt = sprintf("%s\, %02d-%s-%04d %02d:%02d:%02d GMT", $week[$wday], $mday, $mons[$mon], $year+1900, $hour, $min, $sec);

#// ヘッダ出力
print "Set-Cookie: $str_cookie expires=$dt;\n";
}

#------------------------------------------------------------------
# 関数 : GetCookie
# 概要 : クッキー取得
# 引数 : なし
# 戻値 : クッキーの値
#------------------------------------------------------------------
sub GetCookie
{
my($cookie) = $ENV{'HTTP_COOKIE'};
my($key, $val, %data);
my(@cookie);

#// クッキー取得
@cookie = split(/ /, $cookie);
foreach(@cookie)
{
($key, $val) = split(/=/);

#// 文字列をデコードする
$val =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C",hex($1))/eg;
$val =~ s/%2C/\,/g;
$val =~ s/%20/ /g;
$data{$key} = $val;
}

#// 戻り値セット
return %data;
}

exit;
-----------------------------------------------------------------

■解説
少し長いですが、使用している関数も全て記述しました。

まず、掲示板データファイルを読み込みます。そして、投稿の処理でなければ
クッキーを取得してからHTMLを表示します。

<FORM>のACTIONに$ENV{'SCRIPT_NAME'}を指定していますが、これは環境変数から
現在のファイル名を取り出しますので、自分自身へPOST送信することになります。

<FORM>タグの中にHIDDENの属性で、"md"を 1 として渡し、POSTで"md"に 1 が送られて
きた場合に、ファイルに登録する処理を行っています。

ファイル登録は、ファイルデータ配列の最後に投稿されたデータを追加し、その
配列をファイルに書き込みます。

また、この処理は課題にないですが、最大件数を決め、最大件数を超えると、古い
データが削除されるようにしています。

ファイル書き込み時には、簡易的ではありますが、ファイルロックも行っています。

エラー処理でexitしてしまっていますが、できればエラー処理を関数化して、エラー
メッセージを表示するようにすると良いでしょう。

 




前の章へ 次の章へ


このエントリーをはてなブックマークに追加


OfficeLance

お問い合わせはこちらから