Gmail の SMTP サーバを使ってメールを送るのに四苦八苦したメモ。次のサイトを参考にして書いてみた。
Gmail の SMTP を利用して Perl からメール送信(添付ファイル付) – memo.mzt
http://d.hatena.ne.jp/mzt/20080219/p1
Encode モジュールでの MIME Encode
http://www.ksknet.net/perl/encodemime_enco.html
ただ送るだけなら割と簡単なのだが、文字化けを防いだり、第三、第四水準といった最新の文字セットを含めようとすると結構複雑。この本が大変参考になった。
プログラマのための文字コード技術入門
http://www.amazon.co.jp/dp/477414164X/
最終的な完成型はこれだ1。
#!/usr/bin/perl use utf8; use strict; use warnings; use feature qw! say !; use Encode; use MIME::Entity; use Net::SMTP::SSL; # SMTPサーバの設定 my %smtp = ( Server => "smtp.gmail.com", Port => "465", User => '[email protected]', Password => "パスワード", ); # メールヘッダの設定 my %mail = ( From => '送信元 <[email protected]>', To => '宛先 <[email protected]>', Subject => "テスト件名", ); # ヘッダをB符号化 $_ = encode( "MIME-Header-ISO_2022_JP", $_ ) for values %mail; # 文字コードを指定 $mail{Type} = "text/plain; charset=utf-8"; # Base64符号化 $mail{Encoding} = "base64"; # メールの本文 $mail{Data} = <<EOD; テスト本文 丸数字その1 : ①~⑩ 丸数字その2 : ㊵㊶㊷㊸㊹㊺ BMP外の文字 : 𡚴(山/女 U+216B4) 𣘺(木+高の変形 U+2363A) EOD # メールを作成 my $mime = MIME::Entity->build( %mail ); say $mime->stringify; # メールを送信 my $s = Net::SMTP::SSL->new( $smtp{Server}, Port => $smtp{Port} ); $s->auth( $smtp{User}, $smtp{Password} ); $s->mail( $mail{From} ); $s->to( $mail{To} ); $s->data; $s->datasend( $mime->stringify ); $s->dataend; $s->quit;
$ perl testGmail.pl Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: base64 MIME-Version: 1.0 X-Mailer: MIME-tools 5.428 (Entity 5.428) From: =?ISO-2022-JP?B?GyRCQXc/Ljg1GyhC?= <[email protected]> To: =?ISO-2022-JP?B?GyRCMDhAaBsoQg==?= <[email protected]> Subject: =?ISO-2022-JP?B?GyRCJUYlOSVIN29MPhsoQg==?= 44OG44K544OI5pys5paHCuS4uOaVsOWtl+OBneOBru+8kSA6IOKRoO+9nuKR qQrkuLjmlbDlrZfjgZ3jga7vvJIgOiDjirXjirbjirfjirjjirnjiroKQk1Q 5aSW44Gu5paH5a2XIDoKICAgIPChmrTvvIjlsbEv5aWzIFUrMjE2QjTvvIkK ICAgIPCjmLrvvIjmnKgr6auY44Gu5aSJ5b2iIFUrMjM2M0HvvIkK
Outlook 2007 での表示例
Y.Oz Vox で配布されている YOzFontNF フォントを使った。
以下、今回勉強した点を纏めてみる。
1. ヘッダを MIME エンコードする
$header = encode( "MIME-Header-ISO_2022_JP", $utf8 );
送信元、宛先、件名に ASCII 以外の文字を使うときは ISO-2022-JP にエンコードした上で B 符号化することが望ましい。それにはエンコーディング名として MIME-Header-ISO_2022_JP
を指定する必要がある2。
Encode::MIME::Header – search.cpan.org
http://search.cpan.org/~dankogai/Encode-2.39/lib/Encode/MIME/Header.pm
2. メール本文のエンコード方法
メール本文に ASCII 以外の文字を使うときは決められた方式でエンコードしないといけない。Gmail その他のウェブメールは割合融通が利くように作られているのだが、古くからのメーラーは RFC に則った実装しかされていない場合がほとんどだ。正しいメールの送り方としては次の 2 通りが考えられる。
(1) ISO-2022-JP でエンコードする
一番単純で古くから使われているやり方だ。Content-Type
ヘッダに文字コードとして ISO-2022-JP を指定してやればよい。元来メール本文は 7bit のエンコーディング(日本語なら ISO-2022-JP)しか想定されていないので、特に指定がなければこの方式だとみなされる3。
Content-Type: text/plain; charset=iso-2022-jp メール本文
これはどんなメーラーでも 100% 通じる方式なのだが、ISO-2022-JP というのはサポートしている文字が少ない。第三、第四水準の漢字は勿論、丸数字のような一般的な文字さえ使えないのだ4。
(2) UTF-8 でエンコードする
そこで Unicode を使う。これなら今利用されているメーラーのほとんどが対応可能である。だが、8bit エンコーディングである UTF-8 を使うならばちょっとした手順が必要だ。
Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: base64 44Oh44O844Or5pys5paH
Content-Transfer-Encoding
ヘッダを指定し、メール本文を Base64 符号化している。後は Unicode に対応したフォントさえあれば良いわけだ。
もっとも、Base64 符号化は必須ではない。次のようにしても多くのメーラーはきちんと表示してくれる。
Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit メール本文
以下、参考書籍からの引用。
8 ビットデータをそのまま通す「8bit」と「binary」を用いる場合は、通信経路が 8 ビットに対応している必要があります。もし 8 ビットを通さないシステムを経由するときは、7 ビットで表現可能な base64 や quoted-printable に変換されます。
“8 ビットを通さないシステム”というのが未だに存在するのかは知らないが、大事を取って Base64 符号化するのが最善だろう。
ちなみに、MIME::Entity
の初期値は「binary
」である。この場合、Gmail や iPhone では読めたものの、Outlook 2007 では盛大に文字化けしてしまった。
Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: binary メール本文
3. SSL over SMTP(STARTTLS)を使用して送信する
今回のメール送信には Gmail を使ったが、ここの SMTP サーバは SSL over SMTP でないと利用できない。Perl で SSL over SMTP を利用するには Net::SMTP::SSL
モジュールを使うといい。Linux や Mac OS X ならば、
$ sudo cpan -i Net::SMTP::SSL
だけでインストールできる5のだが、Windows(ActivePerl)では少し複雑。サードパーティのレポジトリを PPM に追加する必要がある。
後は例に挙げた通りである。文字コードでつまずいたものの、手順自体は単純なものだった。
- 以下のリストには BMP 外の文字が含まれているので、環境(古い Windows XP 環境など)によっては一部文字化けしているかも知れない。 ↩
-
Encode::MIME::Header
モジュールで推奨されているのは、単にMIME-Header
として UTF-8 文字列のまま B 符号化する方式だ。この方法なら件名などに BMP 外の文字を書くことも可能だろう。しかし今回は後述のように、ヘッダ部は ISO-2022-JP、本文は UTF-8 という変則的な運用をしている。件名に丸数字が載せられなくても困ることは少ないが、本文がそれでは実用上不便だろうという考えだからだ。両方ともを UTF-8 にしても仕様上間違いではないのだが、送信元が文字化けしてしまうのは、本文の文字化けよりも悲惨であろうからやはり避けたい。 ↩ - 便宜上、一部のメールヘッダだけを表示している。以下同様。 ↩
- 丸数字が使えているように見えることもあるが、全てのプラットフォームで同じように見えているとは限らない。 ↩
- 事前に OpenSSL のインストールが必要。 ↩