さくらのサーバ でお問合わせWEBページなど、CGIからメール送信したい場合、簡単な方法としてはunixのsendmailコマンドで用いることができます。当方では一旦fileに生成してsendmailにリダイレクトしていました。言語は Perl です。
use Fcntl;
use File::Basename;
use Jcode;
$my_email='自社メールアドレス';
$email_tmp="mailtmp.txt";
sysopen(MTMP, $email_tmp, O_CREAT|O_WRONLY, 0666)||die print "エラーが発生しました。(1)"||exit;
# 同時送信された場合のためのfile排他ロック
flock MTMP,LOCK_EX || die print "エラーが発生しました。(2)"||exit;
$subject_jis = Jcode::convert($user_subject, "utf8");
# mail編集
print MTMP "Content-Type: text/plain; charset=Shift_JIS\n";
print MTMP "From: $my_email\n";
print MTMP "To: $my_email\n";
print MTMP "Subject: $subject_jis\n";
print MTMP "\n"; # blank (必須)
print MTMP "送信したいメッセージ\n";
# ロック解除
flock MTMP, LOCK_UN || die print "エラーが発生しました。(3)"||exit;
close MTMP;
# mail実行
$cmd = "cat $email_tmp | /usr/sbin/sendmail $my_email";
system $cmd;
しかしこれでは平文で送信されてしまいます。ステータスなどの自動送信ならこれで良いですが、個人情報を扱う場合はまずいです。問合せユーザに写しを送りたい場合、gmail にも弾かれてしまいます。
そこで SSL(STARTLS) のメール送信を Perl CGIに仕込もうと記事1 、記事2 のサイトを参考にさせていただきました。しかし、投稿時期の違いか、契約プランの違いなのかうまくいきません。調査を開始しました。
【課題1】SMTPSパッケージが入っていない/入れられない
さくらのサーバ では、STARTLSを送信するためのパッケージ Net::SMTPS を use 文を書くと実行エラーとなります。当パッケージは入っていないようです。 さくらのサーバに Teraterm から ssh でログインして、Perlの cpan ユーティリティでインストールしてみると以下のように root権限無しでエラーになってしまいます。
cpan[8]> install Net::SMTPS
Running install for module 'Net::SMTPS'
Checksum for /home/motoplus4/.cpan/sources/authors/id/T/TO/TOMO/src/Net-SMTPS-0.10.tar.gz ok
Scanning cache /home/motoplus4/.cpan/build for sizes
............................................................................DONE
Configuring T/TO/TOMO/src/Net-SMTPS-0.10.tar.gz with Makefile.PL
:
中略
:
/usr/bin/make test -- OK
Running make install for TOMO/src/Net-SMTPS-0.10.tar.gz
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ERROR: Can't create '/usr/local/perl/5.26/lib/perl5/site_perl/5.26/Net'
Do not have write permissions on '/usr/local/perl/5.26/lib/perl5/site_perl/5.26/Net'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
at -e line 1.
*** Error code 13
しかし、sudo、su はスタンダードプランでは未対応で、VPSプランからのようです。usergrp コマンドもとおりません。そこで以下のようにしました。
- cpanユーティリティで、Getコマンドで Net::SNTPS をdonwload。
- Net-SMTPS-0.10.tar.gz を解凍し /Net/Lib/Net を丸ごと /hom/ドメイン/www/cgi-bin の下にコピー。
- Net::SMTP も SMTPS の基底クラスなので同様にコピー。
- Net::Cmd、Net::Config も SMTPS から引用しているので同様にコピー。
- 対象.cgiに ローカルlibのパスを以下のように追記。
use lib "/home/ドメイン/www/cgi-bin/lib/"; #追記
use Net::SMTP;
use Net::SMTPS;
- STMPS.pm、 STMP.pm にも ローカルlibのパスを以下のように追記。
use lib "/home/ドメイン/www/cgi-bin/lib/"; #追記
use Net::Cmd;
use Net::Config;
これで Net::SMTPS を使用可能になりました。
【課題2】SMTPインスタンス生成エラー
SMTPS内の new() から SMTPの new() をcallしてるので、先に基底クラスの Net::SMTP から順当に試そうとしましたが、new時点でインスタンスが空になりました。STMP.pm もローカルに置いたのでいじりやすくなってるので、print文を入れて追ってみましたが分からず。諦めて Net::SMTPS から直接やってみると上手くいきました。 不思議です。以下コードです。
# ここはメールサーバのホスト名。メアドではない。
# 独自ドメインでもとっちでもOK
#my $svr_name='www???.sakura.ne.jp';
my $svr_name='独自ドメイン.com';
my $smtps = Net::SMTPS->new( $svr_name, Port => '587', doSSL => 'starttls',
# Debug => 1
);
unless($smtps) {
die print "<br>メールサーバの検索に失敗しました。<br></body>\n";
}
【課題3】auth()メソッドでログインエラー
SMTPSの インスタンス生成後、auth() メソッドでfalseが返ります。これもSTMPS.pm、 STMP.pm にprint文を入れて追ってみました。基底クラスのSMTPの auth() メソッドにて パスワードをメールサーバに送ったところで、応答コード 535 でが返ってます。ユーザ名にドメイン名を付与すると通りました。メールサーバはユーザ名だけで通っていた記憶があったのですが、、、コードは以下のとおりです。
# usernameは、ドメイン名の付与も必要。
$smtps->auth( ユーザ名@ドメイン.sakura.ne.jp, 'パスワード', 'LOGIN' ) ||
die print "<br>メールサーバとの認証に失敗しました。<br></body>";
応答コードがSMTPS パッケージから見えにくいので状況判断しにくいです。STMP.pm の内部にて一通りチェックしてみると以下のとおりでした。
応答コード | 状態 |
220 | 通常コマンド受付 |
221 | 接続断 |
250 | 通常コマンド受付 |
334 | ユーザ名受付、認証方式受付 |
535 | ユーザ名 もしくは パスワード 不一致 |
あとはすんなり突破しました。以下コードです。Perlの文字連結は + は効かないんすね。
$subject_jis = Jcode::convert(メールタイトル, "utf8"); # sjisのでもOK
my $my_message = "";
$my_message .= "Content-Type: text/plain; charset=Shift_JIS\n";
$my_message .= "From: 送信元メアド\n";
$my_message .= "To: 送信先メアド\n";
$my_message .= "Subject: $subject_jis\n";
$my_message .= "\n";
$my_message .= メール本文";
$smtps->mail( 送信元メアド );
$smtps->to( 送信先メアド );
$smtps->data();
$smtps->datasend( $my_message );
$smtps->quit;
下図のようにgmailの受信もOKでした。