中年プログラマーの息抜き

ブログをはじめました。気の向くままにプログラム関連ネタをメモしていきます。

メール受信からプログラムを実行し添付ファイル保存する

はじめに

レンタルサーバー(XSERVER)、メール受信をトリガーとし、プログラムを起動します。※Lambda Function的な...。
今回は、特定のアドレスがメール受信した時に、Perl5 のプログラム import_attachment.pl を実行する例を紹介します。

手順

トリガー設定(例)は、
 ⇒ Xserverレンタルサーバー|サーバーパネルから「メールの振り分け」をクリック
 ⇒ ドメイン選択画面から「設定対象のドメイン:選択する」をクリック
 ⇒ メール振り分け設定画面から「メール振り分け設定追加」をクリック

f:id:tm-b:20210906175202j:plain

・条件1(キーワード):特定のアドレス
・条件1(場所):あて先
・条件1(一致):内容を含む
・条件1(宛先):| /usr/bin/perl /home/(サーバID)/bin/import_attachment.pl
・処理方法(配送方法):転送

プログラム(import_attachment.pl)

/home/(サーバID)/bin/import_attachment.plを作りパーミッション「700」に設定すれば動くはず。

#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use Time::HiRes "gettimeofday";
use MIME::Parser;

my @accepts = ('受け付けるメール送信者:メールアドレス');
my $output = '添付ファイル保存先のフルパス';
my $log = '実行ログファイルのフルパス';
my ($es, $ms) = gettimeofday();
my ($S, $M, $H, $d, $m, $y) = localtime;
($y, $m, $d, $H, $M, $S, $ms) = ($y + 1900, sprintf("%02d", ++$m), sprintf("%02d", $d), sprintf("%02d", $H), sprintf("%02d", $M), sprintf("%02d", $S), sprintf("%06d", $ms));

open(LOG, ">>$log") || die;
flock(LOG, 2) || die;
print LOG "\n[$y/$m/$d $H:$M:$S.$ms] START, ";

my $mp= new MIME::Parser;
$mp->output_to_core(1);
$mp->tmp_to_core(1);
$mp->tmp_recycling(1);
$mp->use_inner_files(1);

my $mail= $mp->parse(\*STDIN);
my @from = $mail->head->get('From') =~ /<(.+)>/;
print LOG " from=$from[0], ";

@from = grep { $_ eq $from[0] } @accepts;
if (scalar(@from) > 0 && $mail->is_multipart) {
    my $count = $mail->parts;
    for (my $i = 0; $i < $count; $i++) {
        my $entity = $mail->parts($i);

        my $mime = $entity->head->mime_type;
        print LOG " mime=$mime, ";

        my $name = "$output/$y$m$d$H$M$S$ms".sprintf("%04d", rand(1000));
        if ($mime eq "image/jpeg") {
            $name .= ".jpg"
        } elsif ($mime eq "application/pdf") {
            $name .= ".pdf"
        } else {
            next;
        }
        print LOG " name=$name ";

        my $body = $entity->bodyhandle;
        my $IN = $body->open("r") || next;
        my $data = $IN->getline();
        if (defined($data)) {
            print LOG " (save)";
            open(OUT, ">$name") || next;
            eval {
                do {
                    print OUT $data;
                } while (defined($data = $IN->getline()));
                close(OUT);
                chmod 0600, $name;
            };
            if (my $e = $@) {
                print LOG "$e, ";
            } else {
                print LOG ", ";
            }
        } else {
            print LOG " (skip), ";
        }
        $IN->close;
    }
    print LOG " END ";
} else {
    print LOG " IGNORE ";
}

flock(LOG, 8);
close(LOG);

1;

まとめ

プログラムが異常終了したときは、メール送信者にその内容が自動送信されるようでした。。自前でログを書きだしていくのは大変ですね。しみじみ
「perl5」、どうかなって思いつつ、楽なので書き進めましたが、流行的にも気が向いたら同じ処理を「python3」で、書き直したいなとさ。