PerlでSMTP over TLSはNet::SMTPだけでOKになっていた。

今まで、PerlでSMTP over TLSするときはNet::SMTP::TLSを使っていたが、2006年製と古く、いちいちTLS.pmに修正が必要だった。Fedora 23にはNet::SMTPSというのもあったが、SSL/TLSのオプション指定をどのようにするか、ドキュメントに書かれておらず、怪しかった。

Fedora 23のパッケージでインストールされたNet::SMTPには、starttls()とauth()があるので、その2つのAPIを足せば、普通のSMTPのスクリプトが動くようになっていた。次のようにしてgmailに対するSMTP over TLS対応にした。

starttls()で独立してTLSのオプションを指定できるのでわかりやすくなったかもしれない。TLSオプションの内容としては、TLS 1.2を使う、サーバー証明書は検証する、OCSPで証明書の失効検証をサーバーにお願いする、OCSPが失敗したらTLS接続しない、smtp.gmail.comについてサーバー証明書を検証する、暗号スイートはシステム設定(Fedora の/etc/crypto-policies) ということなのだけれも、ちゃんと動いているかどうかは未確認。SMTPサーバーにOCSPってあるのか? 少なくともsmtp.gmail.comはOCSPリクエストには、応答がなかった。OCSPをSSL_OCSP_MUST_STAPLEにすると、gmai.comも、smtp.gmail.comも、httpsとsmtpsの両方ともTLS接続できなかった。

メール送信中の通信を暗号化するstarttlsを信じてはいけないによれば、暗号化なし通信で転送するサーバーが多いと指摘している。

#!/usr/bin/perl
use strict;
use Net::SMTP;		# SMTP接続後、starttls()を使う
use IO::Socket::SSL;	# SSLとあるけれどもTLSしか使わない
use Authen::SASL;	# SASLはSMTPに認証手順

my $smtp = Net::SMTP->new(
        'smtp.gmail.com',
        Hello   =>      'sshida.com',
        Port    =>      587,
        #Debug   =>      1 
);
die "Error" unless $smtp;

$r = $smtp->starttls(
  SSL_version=>TLSv12", 
  SSL_verify_mode=>SSL_VERIFY_PEER,
  SSL_ocsp_mode=>SSL_OCSP_TRY_STAPLE,
  SSL_ca_path=>etc/ssl/certs',
  SSL_ca_file=>etc/ssl/certs/ca-bundle.crt',
  SSL_verifycn_name => 'smtp.gmail.com', # defaults to PeerHost
  SSL_verifycn_schema => 'smtp',
  SSL_hostname => 'smtp.gmail.com', # SNI support
  SSL_cipher_list =&g; 'PROFILE=SYSTEM',
);
die "Error" unless $r;
$r = $smtp->auth( '__my_username__', '__my_password__' );
die "Error" unless $r;

$_ = <>
$r = $smtp->mail($from);
$r = $smtp->to($to);
$r = $smtp->data();
$r = $smtp->datasend("\n\n" . $_);
$r = $smtp->dataend();
$r = $smtp->quit;