Perlでメールを送る

by Hippo2000(2001/7/3,2001/3/18,
1999/1/20、1999/1/5、6、
1998/12/22+24)

「Perlを使ってメールを送信したい」という人は多いのではないでしょうか?

でもその方法がわかりにくかったりします。
私もまだまだ調査しているところなのですが、なんとか添付ファイル付のメールを送れるようになりました。
他の人たちのお役に立てればということで簡単なプログラム例を載せたいと思います。

99年1月5日 追加、修正
「本文やヘッダに日本語が入っている場合に問題がある」というご指摘をいただき、小林巧次郎さんからは
jcode.plを使ってJISコードに変換し、Content-Typeにcharsetを記述するという方法を教えていただきました。
さらにWin32::APIモジュールを使うことにより、Basp21ではなくDLLを呼び出すこともわかりました。
これらの点を加えました。

99年1月20日 追加
「添付ファイル名が日本語の場合、うまくメールの取得ができない」という指摘を受けて、調査したところ、送信段階でも、添付ファイル名をエンコードする必要があることがわかりました。
この点を加えました。

2001年3月18日 追加、修正
タイトルを「ActivePerlでメールを送る」から「Perlからメールを送る」に変更しました。
さらにHTMLメールの送信についても追加。
ときどき間違ったメールが届くので、メールアドレスを変更

2001年7月3日 追加、修正
Bさんからの指摘を受けて、ActiveSateをAcitveStateに修正(^^;;;


目次

1.Perlの力でメールを送る
1.1 必要なパッケージをインストール
1.2 Net::SMTPだけで送信
1.3 MIME::Entityを使ってデータ作成
1.4 添付ファイル付のメールを送信する
1.5 日本語への対応
1.6 参考資料

2.Baspを使ってメールを送る
2.1 Baspとは
2.2 Baspを使ってメールを送る
2.3 Baspを使うときに注意したいこと
2.4 BSMTP.DLLを使ってメールを送る

3.まとめ

参考資料


1.Perlの力でメールを送る

perldocのperlfaq9にも書かれている通り、Perlからでもメールを送信することは簡単にできます。

よくある本にはsendmailなどのコマンドライン型プログラムにパイプを通してメールを送り込むようなものが多いですが、

Perlにはさまざまなパッケージが日々追加されています。
そのために非常にパワフルな言語となっています。
パッケージの力を利用すれば、インターネットメールも(なんとか)簡単に送ることができます。

また標準的なパッケージであれば、UNIXなど他の環境でそのまま使うことが可能です。

1.1 必要なパッケージをインストールする

ActivePerlではPPMというモジュールをインストールするためのユーティリティが使用できます。
インターネットメールを送信するためには、以下のパッケージが必要になります。

パッケージ名 説    明
libnet NET::SMTPなどのネットワーク関連のモジュールが入っています。
添付ファイルなしにメールを送るだけであれば、これだけでも可能です。
MIME-Base64 添付ファイルをエンコードするためのモジュール
ActivePerlでは標準で入っているはず
MIME-tools 添付ファイルを送信するためのMultipart/mixed形式を作成する
MIME::Entityが入っています。
MailTools MIME::Entityの親クラスであるMail::Internetが入っています。
IO-stringy MIME::Entityで使用します。

さらにJISコード変換のためのパッケージ(またはプログラム)が必要となります。
ここではJcodeを使います。(kconvパッケージやnkfでも同様だと思っていますが、確認はしていません)

1.2 Net::SMTPだけで送信

シンプルなメールであれば、Net::SMTPモジュールだけを使うと以下のように、簡単にメールを送ることができます。
かなり単純な

use Net::SMTP;
#オブジェクトの作成
$smtp = Net::SMTP->new(
             'smtpsrv',               #SMTPサーバ
             Hello=>"hoge.co.jp");    #SMTPサーバのドメインを指定
#ヘッダ部の組み立て
$smtp->mail('kawai@hogehoge.co.jp');#送信元の指定
$smtp->to('kawai@hogehoge.co.jp');  #宛先の指定

#データ部の組み立て
$smtp->data();
$smtp->datasend("From:kawai\n");      #送信元
$smtp->datasend("To:kawai\n");        #宛先(データ部)
$smtp->datasend("Subject:Simple Mail Sending\n"); #件名
$smtp->datasend("Content-Type: text/plain\n\n"); #タイプ
$smtp->datasend("Simle Mail\n"); #本文
$smtp->datasend("MailTest\n2gyoume\n");
# データの終わり、メール送信
$smtp->dataend(); 
#SMTP接続の終了
$smtp->quit; 

1.3 MIME::Entityを使ってデータを作成

MIME::Entityモジュールを使用すると、メールのデータをより見やすく作成することができます。

use Net::SMTP;
use MIME::Entity;
#オブジェクトの作成
$smtp = Net::SMTP->new(
             'smtpsrv',               #SMTPサーバ
             Hello=>"hoge.co.jp");    #SMTPサーバのドメインを指定
#ヘッダ部の組み立て
$smtp->mail('kawai@hogehoge.co.jp'); #送信元
$smtp->to('kawai@hogehoge.co.jp');   #宛先
#データ部の組み立て(MIME::Entityによるデータの作成)
$smtp->data();
$oMime = MIME::Entity->build(
	    From     => 'kawai',         #送信元(データ部)
             To       => 'kawai',	     #宛先(データ部)
             Subject  => "簡単なメールの送信",    #件名
	    Data	 => ["簡単なメール2\n",
		         "MailTest\n2行目も簡単\n"]);
			         	#本文
$smtp->datasend($oMime->stringify); #文字列に変換
# データの終わり、メール送信
$smtp->dataend(); 
#SMTP接続の終了
$smtp->quit; 

1.4 添付ファイル付のメールを送信する

添付ファイルをつけるには、コンテントタイプがmultipart/mixedなデータを作り、エンコードする必要があります。
MIME::Entityを使うと、multipart化やエンコードを簡単におこなうことができます。

以下の例ではこれまでのメールに「c:\hoge.jpg」という画像ファイルと「c:\autoexec.bat」というテキストファイルを添付して
送信します。

use Net::SMTP;
use MIME::Entity;
#オブジェクトの作成
$smtp = Net::SMTP->new(
             'smtpsrv',               #SMTPサーバ
             Hello=>"hoge.co.jp");    #SMTPサーバのドメインを指定
#ヘッダ部の組み立て
$smtp->mail('kawai@hogehoge.co.jp'); #送信元
$smtp->to('kawai@hogehoge.co.jp');   #宛先
#データ部の組み立て(MIME::Entityによるデータの作成)
$smtp->data();
$oMime = MIME::Entity->build(
	    From     => 'kawai',     #送信元(データ部)
             To       => 'kawai',	     #宛先(データ部)
             Subject  => "簡単なメールの送信",    #件名
	    Data	 => ["簡単なメール2\n",
		         "MailTest\n2行目も簡単\n"]);
			           #本文
#添付ファイルをつける
$oMime->attach(
	Path     => 'c:\\hoge.jpg',
	Type     => "image/jpeg",
	Encoding => "Base64"
);
$oMime->attach(
	Path     => 'c:/autoexec.bat', 
	Type     => "text/plain",
	Encoding => "-SUGGEST"
);
$smtp->datasend($oMime->stringify); #文字列に変換
# データの終わり、メール送信
$smtp->dataend(); 
#SMTP接続の終了
$smtp->quit; 

1.5 日本語への対応+HTMLメール

メールはもともと7ビット(つまりはASCIIコード)前提として作られていました。
そのために日本語をそのまま入れてしまっては、文字化けが発生するでしょうし、場合によっては届かないおそれがあります。

対応方法はまだ議論があるようですが、ここでは一般的な方法となっているヘッダのBエンコードと
日本語コードをISO-2022-JP(JIS)化で対応します。

ヘッダのBエンコードはMIME::Wordsモジュールによって簡単に実現できます。
また以下の例では、シフトJISからJISへのコード変換は、jcode.plを使ってみました。
コード変換についてはkconvモジュールやnkfでも同様のことが可能だと思いますが、確認をとっていません。

さらに添付ファイル名が日本語の場合、ファイル名をエンコードする必要があります。
AttachメソッドにFilenameをエンコードしたものを指定します。

use Net::SMTP;
use MIME::Entity;
use MIME::Words qw (:all);
require 'jcode.pl';
#===============================================================================
# jcode.plを使って、JISコードへ変換
#===============================================================================
sub ConvJis($) {
  local($sWk) =@_;
  &jcode'convert(*sWk, 'jis');
  return $sWk;
}
#===============================================================================
# メインルーチン
#===============================================================================
#オブジェクトの作成
$smtp = Net::SMTP->new(
             'smtpsrv',               #SMTPサーバ
             Hello=>"hoge.co.jp");    #SMTPサーバのドメインを指定
#ヘッダ部の組み立て
$smtp->mail('kawai@hogehoge.co.jp'); #送信元
$smtp->to('kawai@hogehoge.co.jp');   #宛先
#データ部の組み立て(MIME::Entityによるデータの作成)
$smtp->data();
$sTo   = encode_mimeword(&ConvJis('川合孝典'), 'B', 'iso-2022-jp') . '<GCD00051@hoge.ne.jp>';
$sFrom = encode_mimeword(&ConvJis('川合孝典'), 'B', 'iso-2022-jp') . '<kawai@hogehoge.co.jp>';
$sSubj = 'MIME' . encode_mimeword(&ConvJis('化した内容カナ文字入り'), 'B', 'iso-2022-jp');
$sData = &ConvJis("MIME化した簡単なメールの送信\nこんな風に改行もできます。\nまぁ当然ですが");
$oMime = MIME::Entity->build(
        To       => $sTo, 
        From     => $sFrom,
        Subject  => $sSubj,
        Type     => 'text/plain;charset="iso-2022-jp"', #後ろのcharsetがミソ
        Data     => $sData,
        Encoding => "7bit"                              #7bitエンコード
);
#添付ファイルをつける
$oMime->attach(
	Path     => 'c:/bnews.jpg',              #c:\\bnews.jpgとしても動きますが、
	Filename => 'hogehoge.jpg',              #他の名前を指定することができます
	Type     => "Application/octet-stream",  #メーラによってはTypeにあわせて
                                                   #拡張子が変わってしまうので
	Encoding => "Base64"
);
$oMime->attach(
	Path     => 'c:/見積情報.xls',          #実際に添付するファイルを指定
	Filename => encode_mimeword(&ConvJis('見積情報'), 'B', 'iso-2022-jp') . '.xls',
                                                  #Filenameにエンコードした名前を指定
	Type     => "Application/octetstream",
	Encoding => "base64"
);
$smtp->datasend($oMime->stringify);
# データの終わり、メール送信
$smtp->dataend(); 
#SMTP接続の終了
$smtp->quit; 

HTMLメールの例

use strict;
use Jcode;
use Net::SMTP;
use MIME::Entity;
use constant SMTPsvr => 'smtp.nifty.ne.jp';

#1. 送信用テキストの作成
my $sDataH=<<EOF;
<H1>HTMLメール</H1>
&nbsp;&nbsp;このようにして、本文を作成します。<BR>
<B>当たり前といえば当たり前ですか</B><BR>
河馬屋写真:<BR>
<img src="cid:temp1_jpg"/>
<BR>
きれいに見えますか?
EOF

#1.1 本文
my $oMime = MIME::Entity->build(
        Type    => 'multipart/related',
        To       => jcode('川合孝典')->mime_encode(). '<kawai@hogehoge.co.jp>',
        From     => jcode('河馬屋二千年堂')->mime_encode() . '<GCD00051@hoge.ne.jp>',
        Subject  => 'HTML' . jcode('メール')->mime_encode(),
);
$oMime->attach(
        Type     => 'text/html;charset="iso-2022-jp"', #後ろのcharsetがミソ
        Data     => jcode($sDataH)->jis,   #本文(HTML)をJIS変換
        Encoding => '7bit'                             #7bitエンコード
);
#1.2 添付ファイル
$oMime->attach(
    Path       => '河馬屋.jpg',              #添付するファイルを指定します
    Type       => 'application/octet-stream',#メーラによってはTypeにあわせて拡張子が
                                             #変わってしまうのでApplication/octet-stream
    Encoding   => 'Base64',                  #Base64でエンコード
   'Content-ID'=> 'temp1_jpg',               #
);
#2. SMTPによる送信
my $oSmtp = Net::SMTP->new(SMTPsvr);  		#SMTPサーバの指定
$oSmtp->mail('GCD00051@hoge.ne.jp');        #実際の送信元
$oSmtp->to('kawai@hogehoge.co.jp');         #実際の宛先
$oSmtp->data();                             #データの開始を通知
$oSmtp->datasend($oMime->stringify);        #MIME::Entityを利用したテキストの出力
$oSmtp->dataend();                          # データの終わり、メール送信
$oSmtp->quit;                               #SMTP接続の終了

1.6 参考資料

PPMでインストールすると各パッケージのインストールの際に、HTML形式のファイルが展開されます。
そのファイルに各モジュールの詳しい説明が載っています。


ファイルはActivePerlがインストールされたディレクトリ(通常はC:\Perl)の下のHTML\LIBまたは、
HTML\LIB\SITEに展開されます。

ここで扱った主なモジュールのファイル名を以下の表に示します。

パッケージ名 モジュール名 説    明
libnet NET::SMTP C:\Perl\html\lib\Net\SMTP.html
MIME-Base64 MIME::Base64 C:\Perl\html\lib\site\MIME\Base64.html
MIME-tools MIME::Words C:\Perl\html\lib\site\MIME\Words.html
  MIME::Entity C:\Perl\html\lib\MIME\Entity.html
MailTools Mail::Internet C:\Perl\html\lib\site\Mail\Internet.html

2.Basp21の力でメールを送る

ActivePerlにはOLEオートメーションを使えるという大きなメリットがあります。
そこでBasp21を使ってメールを簡単に(そりゃもう簡単に)送信することができます。

また前項で問題になった日本語コードにも対応しています。

2.1 Basp21とは

BASP21.DLLは、Babaqさんが作成したフリーウェアで、VBScriptVisual Basic、VBAWSHなどから使える汎用の
コンポーネントです。 ActivePerlからもWin32::OLEパッケージを使って利用することができます。
メールの送信、受信、プログラムの実行などさまざまなメソッドをサポートしています。

Basp21の内容については、詳しくはBaba Centerfolds http://www.hi-ho.ne.jp/babaq/ を参照してください。

2.2 Basp21を使ってメールを送る

Basp21はあらかじめダウンロードされ、インストールされている必要があります。
Basp21のオブジェクトを作成し、メール送信メソッドを使って送信します。

添付ファイルをつけないメールを送信するためには以下のようになります。

use Win32::OLE;
$oBasp = Win32::OLE->new('basp21');		#Basp21オブジェクトの作成
#メールの送信
$oBasp->SendMail("saturn", 			#SMTPサーバ
		'kawai@hogehoge.co.jp', 	#宛先
		'kawai@hogehoge.co.jp', 	#送信元
		"Basp21でメール", 		#件名
		"簡単なメール\nMailTest\n2行目も簡単\n",
						#本文
		""					#添付ファイルに""を指定
	);

上記1.4 添付ファイル付のメールを送信すると同じように添付ファイルをつけたメールを送信する
ためには以下のようになります。

use Win32::OLE;
$oBasp = Win32::OLE->new('basp21');		#Basp21オブジェクトの作成
#メールの送信
$oBasp->SendMail("saturn", 			#SMTPサーバ
		'kawai@hogehoge.co.jp', 	#宛先
		'kawai@hogehoge.co.jp', 	#送信元
		"Basp21でメール", 		#件名
		"簡単なメール\nMailTest\n2行目も簡単\n",
						#本文
		'c:\bnews.jpg' . "\t" . 'c:\autoexec.bat'
				#添付ファイル 複数あるときはタブ区切り
	);

2.3 Basp21を使うときに注意したいこと

Basp21をPerlから使う場合、陥りやすい穴が2つかあります。

  • 添付ファイルがない場合には、""を必ずつけること。
    →なくてもエラーになりませんが、メールは送信されません。
  • 添付ファイルの指定でディレクトリ区切りに「/」は使用できません。
    →エラーで吹っ飛びます。

2.4 BSMTP.DLLを使ってメールを送る

Basp21でのメール送信部分はBSMTP.DLLというDLLによって実現されています。
そこで、Win32::OLEではなく、Win32::APIパッケージを使用してDLLを直接呼び出すことにより、メールを
送信することができます。

use Win32::API;
$SndMail = new Win32::API("bsmtp",  "BSendMail", [P,P,P,P,P,P,P], I);
$sRes = " " x 80;
#メールの送信
$nRes = $SndMail->Call("saturn", 			#SMTPサーバ
		'河馬屋<kawai@hogehoge.co.jp>', 	#宛先
		'川合<kawai@hogehoge.co.jp>', 	#送信元
		"Basp21でメール", 		#件名
		"簡単なメール\nMailTest\n2行目も簡単\n",
						#本文
		'c:\bnews.jpg' . "\t" . 'c:\autoexec.bat',
				#添付ファイル 複数あるときはタブ区切り
		$sRes		#結果メッセージ
	);
print "$nRes: RES: $sRes";

3.まとめ

以上のようにPerlからでもにメールを送信することは可能です。

そのときモジュールを取るか、あるいはBaspをとるかは人によって違うでしょう。

Perlだけでできること、UNIXにポートしやすいということにメリットを感じればモジュールで、
ASPやVBなど他の言語でも使用する、Windows上しか使わないといった場合には、Basp21が便利なのではないでしょうか?


参考資料

この文書をつくるのにあたり、以下のサイトのお世話になりました.

 


ホーム Perlの小技

ご意見、ご質問はこちらの掲示板で受け付けています。
またメールは河馬屋(Nifty)にお願いします。