MIME::Liteで普通にメールを生成すると、
Date: Mon, 23 Jul 2008 10:00:00 UT
ていうヘッダが入ってイヤだ、という話題。何がイヤだか、ていうと、日本標準時(JST)でないので、Dateヘッダをそのまま採用するMUA(Mozilla Thunderbirdなど)でプリントアウトすると時刻が直感的にわからんのです。
最近入稿システムのメール連絡を面倒だからといって今までMIME::EntityでプログラムしていたところをMIME::Liteで組んでみたら発生した。Liteたるゆえんか。
再現コードどうぞ。
use strict;
use warnings;
use utf8;
use Encode;
use MIME::Lite;
use HTTP::Date;
my $msg = MIME::Lite->new(
From => 'from@example.com',
To => 'to@example.com',
Subject => Encode::encode('MIME-Header-ISO_2022_JP', 'コンニチワ'),
# EncodeでMIME-Header-ISO_2022_JPが使えるのは
# Perl5.8.6以降同梱のもの
Type => 'text/plain; charset="ISO-2022-JP"',
Encoding => '7bit',
Data => encode('iso-2022-jp', '元気でやってるかー?'),
);
$msg->send();
上記コードではDateヘッダ入れていませんが、MIME::Liteで勝手に現在時刻から入れます。それが、UT(世界時)になってしまう罠。
というわけで、MIME::Liteには、Dateヘッダを自分で設定するためのオプションとして、Datestamp => 0 を指定する方法がありますので、自分で時刻文字列作ってしまうことで、DateヘッダがUT(世界時)になることを防げます。
use strict;
use warnings;
use utf8;
use Encode;
use MIME::Lite;
use HTTP::Date;
my $msg = MIME::Lite->new(
From => 'from@example.com',
To => 'to@example.com',
Subject => Encode::encode('MIME-Header-ISO_2022_JP', 'コンニチワ'),
# EncodeでMIME-Header-ISO_2022_JPが使えるのは
# Perl5.8.6以降同梱のもの
Type => 'text/plain; charset="ISO-2022-JP"',
Encoding => '7bit',
Data => encode('iso-2022-jp', '元気でやってるかー?'),
Datestamp => 0,
Date => 'Mon, 23 Jun 2008 20:00:00 +0900',
);
$msg->send();
なんてかんじにするとヘッダに好きな時刻を設定できます。
さて、時刻文字列を作る方法ですが、5つぐらい探しました。
#!/usr/bin/perl
use strict;
use warnings;
sub datestr0 {
# UNIXのdateコマンド使う方法
# dateコマンドの動作が違と動かない
(local $_ = `date -R`) =~ s/\n//sgo;
return $_;
}
sub datestr1 {
# モジュールを使わない方法
# via http://tech.bayashi.net/pdmemo/sendmailbyperl.html
my ( $sec, $min, $hour, $mday, $mon, $year, $wday )
= localtime( time );
my @week = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
my @month = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' );
my $d = sprintf( "%s, %d %s %04d %02d:%02d:%02d +0900",
$week[$wday], $mday, $month[$mon],
$year + 1900, $hour, $min, $sec,
);
return $d;
}
sub datestr2 {
# HTTP::Dateモジュールを使用
# via http://ja.doukaku.org/24/nested/
use HTTP::Date;
my $tz = +9;
( my $date = HTTP::Date::time2str( time + $tz * 3600 ) )
=~ s/GMT/sprintf( '%+03d00', $tz )/e;
return $date;
}
sub datestr3 {
# Date::Manipモジュールを使用
# via http://search.cpan.org/~sbeck/Date-Manip-5.54/lib/Date/Manip.pod
use Date::Manip;
return UnixDate('today', '%g');
}
sub datestr4 {
# DateTime::Format::Mailモジュールを使用
# via http://search.cpan.org/~sbeck/Date-Manip-5.54/lib/Date/Manip.pod
use DateTime;
use DateTime::Format::Mail;
return DateTime::Format::Mail->format_datetime(
DateTime->now(
time_zone => 'Asia/Tokyo',
)
);
}
print datestr0()."\n";
print datestr1()."\n";
print datestr2()."\n";
print datestr3()."\n";
print datestr4()."\n";
__END__
実行結果:
$ perl date.pl
Mon, 23 Jun 2008 19:49:23 +0900
Mon, 23 Jun 2008 19:49:23 +0900
Mon, 23 Jun 2008 19:49:23 +0900
Mon, 23 Jun 2008 19:49:24 +0900
Mon, 23 Jun 2008 19:49:24 +0900
$
それぞれの評価:
datestr0 | バッククオート演算子 | 危ないので使用禁止 |
datestr1 | Perlのみ | テッパン |
datestr2 | HTTP::Dateモジュール | 割と素直。環境依存しにくい |
datestr3 | Date::Manipモジュール | 一番楽だがWindowsだと動かない可能性あり |
datestr4 | DateTime::Format::Mailモジュール | プログラム内でDateTime使ってしまったときについでに使う。 |
こう書いていると、なんだか大がかりになってきたので、普通にMIME::Entity使った方が楽なんじゃないかという気にもなってきました。