SMTPでメール送信 PERL版

smtpail-perl2

SMTPを使ったメール送信方法としては、主にNet::SMTPを使う方法と、Email::Sender::Simpleがある。

 

現状、PERL5.16.3のレンタルサーバーが多いため、Email::Sender::Simpleが標準モジュールとして入っているのがヘテムルとロリポのみなので今回はNet::SMTPを使った方法をメモ。

 

なお、Net::SMTPが入っていても、Authen::SASLが入っていないと正常にメール送信ができないようなので、Kagoyaでは動かない。(useする必要はない)

 

また、Net::SMTPは、バージョンによってはSTARTTLSには非対応なので、暗号化するなら、Net::SMTP::SSL、Net::SMTP::TLS などで別途対応が必要。(PERL5.30.3なら、Net::SMTPのバージョンが新しいので対応している)

 

Net::SMTPを使ってメール送信するサンプルプログラム

 

#!/usr/local/bin/perl

use Jcode;
use Net::SMTP;
use MIME::Base64;

my $mailhost     = 'SMTPサーバー名';
my $mailport     = 587;
my $mail_username = 'ユーザー名';
my $mail_password = 'パスワード';
my $from_mail     = '送信元メールアドレス';
my $to_mail       = '送信先メールアドレス';

my $subject = 'テスト';
my $message = 'テストメールです。';

# 本文を ISO-2022-JP に変換
Jcode::convert(\$message, 'jis');

# SubjectをMIMEエンコード (ISO-2022-JP + Base64)
&Jcode::convert(\$subject, 'jis', 'utf8');
$subject_encoded = jcode($subject)->mime_encode;

# ヘッダー作成
my $header = <<"EOF";
From: $from_mail
To: $to_mail
Subject: $subject_encoded
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit

EOF

# SMTP接続(TLS対応)
my $smtp = Net::SMTP->new($mailhost, Port => $mailport, Hello => 'localhost', Timeout => 30)
  or die "Could not connect to SMTP server.";

$smtp->starttls() or die "Could not start TLS session.";
$smtp->auth($mail_username, $mail_password) or die "SMTP authentication failed.";
$smtp->mail($from_mail);
$smtp->to($to_mail);
$smtp->data();
$smtp->datasend($header);
$smtp->datasend($message);
$smtp->dataend();
$smtp->quit;


print "Content-type:text/html; charset=UTF-8\n\n";
print "メールを送信しました。\n";

 

SubjectをMIMEエンコードする。(ISO-2022-JP + Base64)

本文は、ISO-2022-JPに変換する。

 

Hello => 'localhost'

通常はこのままで動くが、明示的にサーバー名を記入しても良い。

 

STARTTLS非対応サーバー(Xサーバー系)の場合、以下を削除して平文で送信するしかない。

$smtp->starttls() or die "Could not start TLS session.";

 

もしくは、依存モジュールがない、Net::SMTPSを use lib して使う手もある。

 

メールヘッダーで日本語を使う場合はMIMEエンコードする

Subjectと同様に、メールヘッダー内で日本語を使う場合は、MIMEエンコードする必要がある。

(MIMEエンコードしなくても問題ない場合は多いが、メールアドレスは隠せない)

 

例えば、$from_mailを、メールアドレスではなく、

風吹 <fubuki@nb-style.info>

として送信したい場合は以下のようにする。

my $from_name     = '風吹';
my $from_mail     = 'fubuki@nb-style.info';

&Jcode::convert(\$from_name, 'jis', 'utf8');
$from_name_encoded = jcode($from_name)->mime_encode;



From: $from_name_encoded <$from_mail>

 

もし、To: や Reply-To: などでも日本語名を使いたい場合は、同じように mime_encode() を使えばOK。

 

 

SMTPメール送信サブルーチン

sub SendMail {
    my ($from, $to, $subject, $body) = @_;

    eval {
        # 本文の文字コード変換
        Jcode::convert(\$body, 'jis');

        # 件名のエンコード(ISO-2022-JP + Base64)
        Jcode::convert(\$subject, 'jis', 'utf8');
        my $subject_encoded = jcode($subject)->mime_encode;

        # ヘッダー生成
        my $header = <<"EOF";
From: $from
To: $to
Subject: $subject_encoded
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit

EOF

        # SMTP送信処理
        my $smtp = Net::SMTP->new($mailhost, Port => $mailport, Hello => 'localhost', Timeout => 30)
          or die "SMTP接続失敗";

        $smtp->starttls()                  or die "TLS開始失敗";
        $smtp->auth($mail_username, $mail_password) or die "SMTP認証失敗";
        $smtp->mail($from);
        $smtp->to($to);
        $smtp->data();
        $smtp->datasend($header);
        $smtp->datasend($body);
        $smtp->dataend();
        $smtp->quit;
    };

    if ($@) {
        warn "メール送信エラー: $@";
        return;  # 偽(undef)を返す
    }

    return 1;  # 真を返す(成功)
}

 

SendMail($from_mail, $to_mail, $subject, $message);

 

使用例

if (SendMail($from_mail, $to_mail, $subject, $message)) {
    print "送信成功\n";
} else {
    print "送信失敗\n";
}

 

 

Net::SMTPSを使った場合のサブルーチン

Net::SMTPSは、特別な依存モジュールがないので、use lib してやれば使える。

Net::SMTPと互換性が高いのでほぼそのままのコードで動くのが良い。

$smtp->starttls() を削除して、Net::SMTPS->new()時に doSSL => 'starttls' してやるだけ。

 

use FindBin;
use lib "$FindBin::Bin/lib";
use Net::SMTPS;


sub SendMail {
    my ($from, $to, $subject, $body) = @_;

    eval {
        # 本文の文字コード変換
        Jcode::convert(\$body, 'jis');

        # 件名のエンコード(ISO-2022-JP + Base64)
        Jcode::convert(\$subject, 'jis', 'utf8');
        my $subject_encoded = jcode($subject)->mime_encode;

        # ヘッダー生成
        my $header = <<"EOF";
From: $from
To: $to
Subject: $subject_encoded
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit

EOF

        # Net::SMTPS で TLS接続
        my $smtp = Net::SMTPS->new(
            $mailhost,
            Port    => $mailport,
            Hello   => 'localhost',
            doSSL   => 'starttls',  # TLS有効化
            Timeout => 30,
        ) or die "SMTP接続失敗";

        $smtp->auth($mail_username, $mail_password) or die "SMTP認証失敗";
        $smtp->mail($from);
        $smtp->to($to);
        $smtp->data();
        $smtp->datasend($header);
        $smtp->datasend($body);
        $smtp->dataend();
        $smtp->quit;
    };

    if ($@) {
        warn "メール送信エラー: $@";
        return;  # 偽(undef)を返す
    }

    return 1;  # 真を返す(成功)
}

 

 

doSSL の値について

内容
'starttls' ポート587向け(STARTTLS)
'ssl' ポート465向け(SMTPS)
undef 暗号化しない