CGI等でメールを送信する場合、サブジェクトが日本語の場合には、RFC2047 に従いエンコードする必要があります。このサブルーチンは、サブジェクトとなる文字列を格納したスカラー変数を引数として与えると、RFC2047に従いエンコードされたサブジェクトを返します。

■ サブルーチン名

EncodeSubject

■ 引数

  1. サブジェクト文字列

■ 戻値(配列)

  1. RFC2047に従いBASE64 Bエンコードされたサブジェクト

■ 使い方

以下のスクリプト例のように、メール送信をするCGIにおいて利用できます。このサブルーチンは、日本語文字コード変換ライブラリー「jcode.pl」が必要ですので、かならず、スクリプトで jcode.pl をインクルードしてください。

#!/usr/local/bin/perl

require "./jcode.pl";

#サブジェクトをスカラー変数 $String に格納
$Subject = "日本語サブジェクト";

#サブルーチン EncodeSubject を使って、
#サブジェクトをBase64 Bエンコード

$EncodeSubject = &EncodeSubject("$Subject");

#メールを送信
open(MAIL, "|/usr/lib/sendmail -t");
print MAIL "To: hoge@hoge.com\n";
print MAIL "From: foo\@bar\.com\n";
print MAIL "Subject: $EncodeSubject\n";
print MAIL "MIME-Version: 1.0\n";
print MAIL "\n";
print MAIL "test test test\n";
close(MAIL);

#結果をブラウザーに出力
print "Content-Type: text/html\n\n";
print "送信しました。\n";

 

■ 説明

 引数として日本語サブジェクトの文字列を格納したスカラー変数を与えると、RFC2047に従い、JISコードに変換し、Base64 Bエンコードされた文字列を返します。例えば、「日本語サブジェクト」という文字列を与えると、

=?ISO-2022-JP?B?GyRCRnxLXDhsJTUlViU4JSclLyVIGyhC?=

を返します。メール送信などのスクリプト上では、

print MAIL "Subject: $EncodeSubject\n";

のように、「Subject: 」と改行「\n」を付け加える必要がありますので、ご注意ください。

RFC2047では、エンコードされた状態で、全体の文字数が(「Subject: 」を含めて)76文字を超える場合には、改行する必要があります。このように長いサブジェクトにおいても、正しく改行した状態で値を返します。例えば、「長くて長くて長くて長くて長くて長くてとっても長〜い長〜い長〜い日本語サブジェクト」の場合には、

=?ISO-2022-JP?B?GyRCRDkkLyRGRDkkLyRGRDkkLyRGRDkkLyRGRDkbKEI=?= 
 =?ISO-2022-JP?B?GyRCJC8kRkQ5JC8kRiRIJEMkRiRiRDkhQSQkRDkbKEI=?= 
 =?ISO-2022-JP?B?GyRCIUEkJEQ5IUEkJEZ8S1w4bCU1JVYlOCUnJS8bKEI=?= 
 =?ISO-2022-JP?B?GyRCJUgbKEI=?=

を返します。2行目以降の最初には、半角スペースが入ります。

 

■ 制限事項

このサブルーチンは、RFC2047に完全には準拠していません。RFC2047では、ASCII文字列は、エンコードしないことを推奨していますが、このスクリプトでは、簡略化するために、すべてをエンコードしています。

例えば、「test 日本語サブジェクト」というサブジェクトの場合には、RFC2047では、

test =?ISO-2022-JP?B?GyRCRnxLXDhsJTUlViU4JSclLyVIGyhC?=

となることを推奨しています。「test」の部分がエンコードされていませんね。それに対して、このサブルーチンでは、以下のように、「test」を含めて一括でエンコードしています。

=?ISO-2022-JP?B?ZXN0IBskQkZ8S1w4bCU1JVYlOCUnJS8lSBsoQg==?=

RFC違反というわけではなく、ほとんどのメーラーでは問題なくデコードできますので、さほど大きな問題は発生しないかと思います。

 

■ サブルーチン

sub EncodeSubject {
	my($String) = @_;
	&jcode::convert(\$String, "euc");
	my($Base64Table) = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
	                      'abcdefghijklmnopqrstuvwxyz'.
	                      '0123456789+/';
	my($chunk, $ByteChunk, $PackedByteChunk, $DecimalNum, $EncodedString);
	my($SplitedWord, @SplitedWordList, $i, $Byte, $Buff);
	my($KI) = 0;
	my($KO) = 0;
	my($CharNum) = 0;
	my($CharType) = 0;
	my($LineLength) = 0;
	my($CharEndFlag) = 1;
	if($String =~ /[^a-zA-Z0-9\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\/\^\_\~ ]/) {
		$i = 0;
		@SplitedWordList = ();
		while($i < length($String)) {
			$Byte = substr($String, $i, 1);
			if($Byte =~ /[\x8E\xA1-\xFE]/) {
				unless($CharType eq 'K') {$KI ++;}
				$CharType = 'K';
				if($CharEndFlag) {
					$CharEndFlag = 0;
				} else {
					$CharEndFlag = 1;
				}
			} else {
				if($CharType eq 'K') {$KO ++;}
				$CharType = 'A';
				$CharEndFlag = 1;
			}
			$Buff .= $Byte;
			$CharNum += 1;
			$LineLength = 27 + ($CharNum*4/3) + (($KI+$KO)*4) + 2;
			if($CharType eq 'K') {$LineLength += 4;}
			if($CharEndFlag && $LineLength>=70) {
				&jcode::convert(\$Buff, "jis");
				push(@SplitedWordList, $Buff);
				$Buff = '';
				$CharNum = 0;
				$CharType = 0;
				$KI = 0;
				$KO = 0;
			}
			$i ++;
		}
		&jcode::convert(\$Buff, "jis");
		push(@SplitedWordList, $Buff);

		for $SplitedWord (@SplitedWordList) {
			$EncodedString .= '=?ISO-2022-JP?B?';
			$BitStream = unpack("B*", $SplitedWord);
			$i = 0;
			while($chunk = substr($BitStream, $i*6, 6)) {
				unless(length($chunk) == 6) {
					$chunk = pack("B6", $chunk);
					$chunk = unpack("B6", $chunk);
				}
				$ByteChunk = sprintf("%08d", $chunk);
				$PackedByteChunk = pack("B8", $ByteChunk);
				$DecimalNum = unpack("C", $PackedByteChunk);
				$EncodedString .= substr($Base64Table, $DecimalNum, 1);
				$i++;
			}
			if(length($SplitedWord) % 3 == 1) {
				$EncodedString .= '==';
			} elsif(length($SplitedWord) % 3 == 2) {
				$EncodedString .= '=';
			}
			$EncodedString .= '?='."\n ";
		}
		$EncodedString =~ s/\n $//;
	} else {
		$EncodedString = $String;
	}
	return $EncodedString;
}

■変更履歴

2001/10/31 サブジェクトに「0」が含まれるとそれ以降の文字が無効になってしまうバグを解消。

戻る

会社案内 | 特定商取引法に基づく表示 | プライバシーポリシー | 当サイトへのリンクについて | お問い合わせ