CGI プログラムからのメール送信 (2)

前へ << CGI プログラムからのメール送信 (1) サーバ設定と .htaccess >> 次へ

日本語の扱い

前項のスクリプトでは、メールヘッダ・サブジェクトに 英数字しか使っていませんでした。では、日本語を扱う場合は どうすればいいのでしょうか。

まず本文ですが、これは簡単です。JIS コード (ISO-2022-JP) にしてから送信すればよいのです。nkf を使う例と jcode.pl を使う例、2通りの方法を紹介しておきます。

nkf の場合は、

open(SENDMAIL,"| nkf -j | sendmail ...");
と nkf の出力を sendmail に渡すようにします。 このプログラムも CGI プログラムではないので、コマンドラインから実行して下さい。

mail-j-nkf.pl

    1: #!/usr/local/bin/perl
    2: 
    3: $sendmail = '/usr/sbin/sendmail';
    4: $nkf = '/usr/local/bin/nkf';
    5: 
    6: open(SENDMAIL,"| $nkf -j | $sendmail -t -i");
    7: 
    8: print SENDMAIL <<'END';
    9: From: from@foo.bar.com
   10: To: to@hoge.fuga.com
   11: Cc: aa@bb.cc,dd@ee.ff
   12: Subject: test
   13: 
   14: こんにちは。
   15: これはテストです。
   16: END
   17: 
   18: close(SENDMAIL);
jcode.pl を使う場合は、require 'jcode.pl' して、 &jcode::convert とし、それをそのまま sendmail に渡します。 このプログラムも CGI プログラムではないので、コマンドラインから実行して下さい。

mail-j-jcode.pl

    1: #!/usr/local/bin/perl
    2: 
    3: require 'jcode.pl';
    4: 
    5: $sendmail = '/usr/sbin/sendmail';
    6: 
    7: $body = <<END;
    8: こんにちは。
    9: これはテストです。
   10: END
   11: 
   12: &jcode::convert(\$body,'jis');
   13: 
   14: open(SENDMAIL,"| $nkf -j | $sendmail -t -i");
   15: 
   16: print SENDMAIL <<'END';
   17: From: from@foo.bar.com
   18: To: to@hoge.fuga.com
   19: Cc: aa@bb.cc,dd@ee.ff
   20: Subject: test
   21: 
   22: END
   23: 
   24: print SENDMAIL $body
   25: 
   26: close(SENDMAIL);

mime_pls

本文は nkf や jcode.pl を使えばいいのですが、 ヘッダはそう簡単にはいきません。 例えば Subject ヘッダに日本語を使うときは、 Subject ヘッダを MIME エンコードしなくてはいけません。 MIME エンコードというのは、
=?文字コード?エンコード形式?BASE64変換された文字列?=
という文字列のことです。コード形式というのは などがあります (もちろん日本語だけを対象とした規格ではありませんので、 各国の言語をエンコードすることもできます)。 BASE64 変換というのは、元の文字列を3バイト(=24ビット)ごとに区切り、 切り出した24ビットをさらに 6ビットごとに分割します。 6ビットですから、0から63までの数値を表せます。この数を 「ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/」に対応する文字 で置き換えます。 結果的に3バイトが、4文字の7ビットASCII文字に変換されるわけです。

ちなみに MIME には B エンコーディングと Q エンコーディングがあり、 それぞれ

という形式になっています。

かなり面倒なので、生田 昇さんという方が公開されている mime_pls というライブラリを利用しましょう。 http://www.cc.rim.or.jp/~ikuta/mime_pls/index.html ここから mimer.pl と mimew.pl という perl スクリプトを入手できます。 mimer.pl はデコード用、mimew.pl はエンコード用です。 今回はエンコードをしたいので、mimew.pl を使います。 使い方は簡単で、MIME エンコードしたい文字列を &mimeencode に 渡せば、エンコードした文字列を返してくれます。

#!/usr/local/bin/perl

require 'mimew.pl';

$subject = "ほげほげ";
$encoded_subject = &mimeencode($body);

print $encoded_subject;
実行結果は「ほげほげ」となります。

ここまでやってきたことのまとめとして、 ヘッダを MIME エンコードし、ボディを nkf コマンドで JIS コードに 変換してからメールを送信するサンプルを示します。

mail-2.pl

    1: #!/usr/local/bin/perl
    2: 
    3: require 'mimew.pl';
    4: 
    5: $sendmail = '/usr/sbin/sendmail';
    6: $nkf      = '/usr/local/bin/nkf';
    7: 
    8: $from = '山田太郎 <taroh@foo.org>';         # 宛先の書き方1
    9: $to = 'tanaka@tanaka.hoge.org (田中次郎)';  # 宛先の書き方2
   10: $cc = '河田花子 <hanako@fuga.org>';
   11: 
   12: $subject = 'サブジェクト';
   13: 
   14: $body = <<END;
   15: 本文です。てすとてすと。
   16: ほげほげ。ふがふが。むにゃむにゃ。
   17: END
   18: 
   19: open(SENDMAIL,"| $nkf -j | $sendmail -t -i");
   20: 
   21: # &mimeencode で MIME エンコード
   22: $encoded_from    = &mimeencode($from);
   23: $encoded_to      = &mimeencode($to);
   24: $encoded_cc      = &mimeencode($cc);
   25: $encoded_subject = &mimeencode($subject);
   26: 
   27: print SENDMAIL "From: $encoded_from\n";
   28: print SENDMAIL "To: $encoded_to\n";
   29: print SENDMAIL "Cc: $encoded_cc\n";
   30: print SENDMAIL "Subject: $encoded_subject\n";
   31: print SENDMAIL "\n";
   32: print SENDMAIL "$body";
   33: 
   34: close(SENDMAIL);
このスクリプトを実行すると、
From: 山田太郎
To: tanaka@tanaka.hoge.org (田中次郎)
Subject: サブジェクト

本文です。てすとてすと。
ほげほげ。ふがふが。むにゃむにゃ。
というメールが送られます。

マルチパートメール

消えたエラーメール

ここまでを参考に CGI 経由でメールを送ってみて下さい。 大抵の場合はうまくいくでしょうが、存在しないメールアドレスに メールを送ってみると返信がこない場合があります。

普通は、もし宛先が存在しなかったら発信者にエラーメールが 返ってきます。しかし、CGI プログラムが nobody 権限で 動作するサーバだと、エラーメールは nobody 宛に返ってきます。 nobody 宛のメールは、root (そのサイトの管理者) に届く場合も ありますし、消えてしまう場合もあります。

このあたりはサイトの設定次第です。FreeBSD のデフォルトでは、 /etc/aliases に
nobody: root
と書いてあります。つまり、nobody 宛のメールは root に転送されます。 ここに
nobody: /dev/null
と書いてあるなら nobody 宛のメールは /dev/null に追加されます。 /dev/null というファイルにどれだけ書き込んでも /dev/null は常に 0バイトです。つまりメールは消えてしまうわけです。
こういう場合は、sendmail の -f オプションを使います。 あなたが hoge というユーザ名ならば
open(SENDMAIL,"| sendmail -t -i -f hoge");
とします。ただし、これは他人のメールアドレスをかたっていることに なります。例えば、このホストだと nobody@X68000.startshop.co.jp が hoge@X68000.startshop.co.jp というメールアドレスを偽称しているわけです。 そのため、X-Authentication-Warning というヘッダが付くことがあります。 「このメールは From エンベロープが偽称されている可能性がありますよ」 と宛先に知らせる意味があるわけです。
どうしても気になるなら、管理者にお願いして nobody を trusted user に してもらいましょう。具体的には /etc/aliases に Tnobody という行を 追加すればよいです。ただし、それをするくらいなら suExec を 有効にしてもらう方がいいと個人的には思います。

なお、

open(SENDMAIL,"| sendmail -t -i -f hoge\@fuga.com");
と完全なメールアドレスを指定すると、エラーメールはその メールアドレスに届きます。

前へ << CGI プログラムからのメール送信 (1) サーバ設定と .htaccess >> 次へ