22 April 2013

(Linux) シェルスクリプトとsendmailで添付ファイル付きメールを送信する

ログ ファイルや監視データをメール送信するために、添付ファイル付きメールを送信するシェルスクリプトを作ってみる。

■ Perlスクリプト…

Perlでメール送信しようとすると、沢山のCPANライブラリをインストールする必要がある。非力な組み込みマシンなどでは記憶領域制限などで難しいかもしれない

(Perl) Email::Senderを使ってメール送信

■ 添付ファイル無しの場合

$ cat mailtext.txt | mail -s "subject here" rcpt@example.com

■ 添付ファイル付きの場合

まず、添付ファイルをbase64変換して

$ base64 test.txt > test.base64.txt

そのデータを送信用一時ファイルに格納する

mailbody.tmp.txt
From: Sender Name <Sender_Name@example.com>
To: Recpt Name <Rcpt_Name@example.com>
Subject: Test mail
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="1366539238.FF3cC710.14650"; charset="us-ascii"
Content-Transfer-Encoding: 7bit
 
--1366539238.FF3cC710.14650
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
 
This is test message.
from linux mail command
 
--1366539238.FF3cC710.14650
MIME-Version: 1.0
Content-Type: text/plain; name="test.txt"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="test.txt"
 
QXByIDIxIDE4OjI0OjE3IHM1MzUwLXVidW50dS0xMjA0IGRuc21hc3FbMzgxNl06IHN0YXJ0ZWQs
IHZlcnNpb24gMi41OSBjYWNoZSBkaXMKYWJsZWQK5pel5pys6Kqe5paH77yIVVRGOO+8ieOBjOWF
 
〜 略(base64変換した添付ファイルデータをここに貼り付ける) 〜
 
IGNoYW5nZWQgZnJvbSA4MSB0byA3NQpBcHIgMjEgMTg6NDY6MDEgczUzNTAtdWJ1bnR1LTEyMDQg
c21hcnRkWzE5OTFdOiBEZXZpY2U6IC9kZXYvc2RhLCBTTUFSVCBVc2FnZSBBdHRyaWJ1dGU6IDE5
NCBUZW1wZXJhdHVyZV9DZWxzaXVzIGNoYW5nZWQgZnJvbSAxOSB0byAyNQo=
 
--1366539238.FF3cC710.14650

この一時ファイルをsendmailコマンドに流し込み送信する

$ sendmail -t < mailbody.tmp.txt

■ 添付ファイル付きのsendmail用流しこみファイルを自動作成するperlスクリプト

make_mailbody.pl
#!/usr/bin/perl
 
# sendmailで添付ファイル付きメールを送信するための流しこみファイルを作成する
# 添付ファイルはあらかじめ base64 コマンドで変換しておくこと
#
# usage : make_mailbody.pl [file1] [file2] [file3] ...
 
use strict;
use warnings;
use utf8;
 
my $from_addr = 'Sender_Name@example.com';
my $to_addr = 'Rcpt_Name@example.com';
my $subj = "test mail";
my $multipart_boundary = "1366539238.FF3cC710.14650";
 
printf("From: <%s>\n".
        "To: <%s>\n".
        "Subject: %s\n".
        "MIME-Version: 1.0\n".
        "Content-Type: multipart/mixed; boundary=\"%s\"; charset=\"us-ascii\"\n".
        "Content-Transfer-Encoding: 7bit\n".
        "\n".
        "--%s\n".
        "MIME-Version: 1.0\n".
        "Content-Type: text/plain; charset=\"us-ascii\"\n".
        "Content-Transfer-Encoding: 7bit\n".
        "\n".
        "Log Transfer\n".
        "\n", $from_addr, $to_addr, $subj,
        $multipart_boundary, $multipart_boundary);
 
# 引数の添付ファイル数だけループする
for(my $i=0; $i<$#ARGV+1; $i++){
    unless (-r $ARGV[$i]){ next; }  # ファイルが読み込みできない場合、次の引数へ
    my @arr = split(/\//, $ARGV[$i]);   # File::Basename と同じ処理
    my $file_basename = $arr[$#arr];
    printf("--%s\n".
            "MIME-Version: 1.0\n".
            "Content-Type: text/plain; name=\"%s\"\n".
            "Content-Transfer-Encoding: base64\n".
            "Content-Disposition: attachment; filename=\"%s\"\n".
            "\n"
            , $multipart_boundary, $file_basename, $file_basename);
 
    # 添付ファイルを読み込んで出力
    open(FH, '<'.$ARGV[$i]) or die;
    while(<FH>){
        print $_;
    }
    close(FH);
 
    print("\n");
}
 
printf("--%s\n", $multipart_boundary);

例えば、syslogをメール転送するには、シェルコマンドで次のようにする

$ base64 /var/log/syslog > /tmp/syslog.txt
$ perl make_mailbody.pl /tmp/syslog.txt > /tmp/mailbody.tmp
$ sendmail -t < /tmp/mailbody.tmp