Bashプログラミング
 Computer >> コンピューター >  >> プログラミング >> Bashプログラミング

BashスクリプトでAWS S3バケットからのメール取得と表示を自動化する方法

本記事では、メールサーバーでトラブルが発生したことをきっかけに、メール運用をAmazon Simple Email Service(SES)へ委託することにした筆者の経験を紹介します。

しかし、この構成にはひとつ問題がありました。SESが受信した新着メッセージをS3バケットに保存する設定にしていたのですが、AWSマネジメントコンソール上でS3バケット内のファイルを確認する作業は、繰り返すうちにすぐに非効率でストレスになるのです。

そこで筆者は、新しいメッセージの「ダウンロード」「適切な保存」「表示」という一連の流れを自動化するBashスクリプトを作成しました。

このスクリプトはUbuntu Linuxデスクトップ環境向けに書かれたものですが、多少の手直しでmacOSや、Windows Subsystem for Linux(WSL)を利用したWindows 10環境でも動作させることができます。

まずは完成形のスクリプト全体をご覧ください。全体像をつかんだ後、処理を一つずつ順番に解説していきます。

#!/bin/bash
# S3から新着メッセージを取得し、tmpemails/ディレクトリに保存する:
aws s3 cp \
   --recursive \
   s3://bucket-name/ \
   /home/david/s3-emails/tmpemails/  \
   --profile myaccount

# ロケーション変数を設定:
tmp_file_location=/home/david/s3-emails/tmpemails/*
base_location=/home/david/s3-emails/emails/

# 今日のメッセージを保存する新しいディレクトリを作成:
today=$(date +"%m_%d_%Y")
[[ -d ${base_location}/"$today" ]] || mkdir ${base_location}/"$today"

# メッセージファイルに読みやすい名前を付ける:
for FILE in $tmp_file_location
do
   mv $FILE ${base_location}/${today}/email$(rand)
done

# 新しいファイルをGeditで開く:
for NEWFILE in ${base_location}/${today}/*
do
   gedit $NEWFILE
done

ステップ1:S3からメッセージをダウンロードする

最初は、S3バケット内に現在存在するすべてのメッセージをダウンロードする単一のコマンドです(なお、プライバシー保護のため、バケット名やファイルシステムのパス、認証情報などの詳細は変更しています)。

aws s3 cp \
   --recursive \
   s3://bucket-name/ \
   /home/david/s3-emails/tmpemails/  \
   --profile myaccount

もちろん、このコマンドが機能する前提として、ローカルシステムにAWS CLIがインストール・設定済みである必要があります。まだであれば、まずそこから始めましょう。

各要素の意味は次のとおりです。cpは「コピー(copy)」を表すコマンド、--recursiveは複数オブジェクトにも操作を適用するようCLIに指示します。s3://bucket-nameは対象のバケットを指し示します(実際のバケット名は環境ごとに異なります)。続く/home/david...の行は、メッセージのコピー先となる絶対パスです。そして--profile引数は、複数所有しているAWSアカウントのうちどれを使用するかをCLIに伝えます。

ステップ2:パスを変数にまとめる

次のセクションでは、スクリプトの残りの部分でファイルシステムの場所を簡単に指定できるよう、2つの変数を設定します。

tmp_file_location=/home/david/s3-emails/tmpemails/*
base_location=/home/david/s3-emails/emails/

tmp_file_location変数の値がアスタリスク(*)で終わっている点に注目してください。これはディレクトリそのものではなく、そのディレクトリ内のファイルを参照したいからです。

ステップ3:日付ごとの保存先ディレクトリを作成する

後からメッセージを探しやすくするため、.../emails/階層の中に恒久的な新しいディレクトリを作成します。このディレクトリ名には現在の日付を使用します。

today=$(date +"%m_%d_%Y")
[[ -d ${base_location}/"$today" ]] || mkdir ${base_location}/"$today"

まず、date +"%m_%d_%Y"コマンドの出力結果で満たされるtodayというシェル変数を作成します。dateコマンド単体では完全な日付/タイムスタンプが出力されますが、それに続く("%m_%d_%Y")によって、よりシンプルで読みやすい形式に整形されます。

次に、その名前のディレクトリが既に存在するかどうかをテストします。存在していれば、その日はすでにメールを受信しており、ディレクトリを再作成する必要はないということです。ディレクトリが存在しない場合(||)にのみ、mkdirが作成を実行します。このテストを行わないと、コマンドが毎回厄介なエラーメッセージを返す原因になります。

ステップ4:ファイルをリネームして移動する

Amazon SESは、S3バケットに保存した各メッセージに非常に分かりにくい名前を付けます。そこで、メッセージを新しい保存先(先ほど作成した日付付きディレクトリ)へ移動させると同時に、動的にリネームします。

for FILE in $tmp_file_location
do
   mv $FILE ${base_location}/${today}/email$(rand)
done

for...do...doneループは、$tmp_file_location変数が表すディレクトリ内の各ファイルを読み込み、それを今作成したディレクトリ($base_location変数と$todayの現在値で表される場所)へ移動します。

同じ操作の一環として、新しい名前も付けます。「email」という文字列に、randコマンドが生成した乱数を組み合わせたものです。乱数生成ツールが必要な場合はインストールしてください。Ubuntuであればapt install randで導入できます。

実は、このスクリプトの初期バージョンでは、forループ内でcount=1...count=$((count+1))というロジックを使って連番を振り、ファイル名を区別していました。これは同じ日に複数回に分けてメッセージを受信しない限り問題なく動作します。しかし、同じ日に複数バッチ受信すると、新しいメッセージがその日のディレクトリ内の古いファイルを上書きしてしまうのです。

数学的には、randコマンドが2つのファイルに重複する番号を割り当てる可能性もゼロではありません。ただ、randのデフォルト範囲は1〜32,576であるため、筆者はその程度のリスクを受け入れることにしました。

ここまでの処理で、新しいディレクトリにはemail3039やemail25343のような名前のファイルが、受信したメッセージごとに保存されているはずです。

実際に筆者のシステムでtreeコマンドを実行すると、02_27_2020ディレクトリに5件、02_28_2020に1件のメッセージが保存されていることが確認できます(これらのファイルは旧バージョンのスクリプトで生成されたため、連番になっています)。

tmpemailsディレクトリには現在何もありません。これはmvコマンドがファイルを新しい場所へ「移動」し、元の場所には何も残さないためです。

$ tree
.
├── emails
│   ├── 02_27_2020
│   │   ├── email1
│   │   ├── email2
│   │   ├── email3
│   │   ├── email4
│   │   ├── email5
│   └── 02_28_2020
│       └── email1
└── tmpemails

ステップ5:Geditで新着メッセージを開く

スクリプトの最終セクションでは、お気に入りのデスクトップテキストエディタ(Gedit)で各新着メッセージを開きます。ここでも同様のfor...do...doneループを使用し、今回は新しいディレクトリ内の各ファイル名を読み込んで("today"変数で参照)、Geditで開いています。ディレクトリパスの末尾に追加したアスタリスクに注目してください。

for NEWFILE in ${base_location}/${today}/*
do
   gedit $NEWFILE
done

仕上げ:S3バケットのクリーンアップ

最後にもうひとつ重要な作業があります。S3バケットを掃除せずに放置すると、スクリプトを実行するたびに蓄積された全メッセージがダウンロードされ、管理がどんどん難しくなってしまいます。

そこで、新しいメッセージのダウンロードに成功した後、次の短いスクリプトを実行してバケット内の全ファイルを削除しています。

#!/bin/bash
# 既存のメールをすべて削除 

aws s3 rm --recursive s3://bucket-name/ --profile myaccount
  1. Windowsでオフラインマップを使いこなす方法:ダウンロードから管理まで徹底解説

    「マップ(Maps)」アプリは、かつて「Windows マップ」と呼ばれていた、Microsoftが提供するGoogle Mapsの対抗馬ともいえる地図アプリです。ルート案内を手軽に取得できる便利なツールですが、常にインターネットに接続できる環境があるとは限りません。 そうした状況を考慮し、Microsoftはオフラインマップ機能を用意しています。これを活用すれば、インターネット接続がなくても目的地へのナビゲーションが可能になります。この記事では、Windowsでオフラインマップを活用・管理する最適な方法を詳しく解説します。 オフラインマップのダウンロード方法 Windowsでオフラインマップ

  2. AWSで動画ファイルを変換する方法|S3へのアップロードからMediaConvertでの変換まで徹底解説

    AWSで動画ファイルを変換する方法 動画編集は時間のかかる作業です。動画編集の経験がある方なら、完成した動画をさまざまなプラットフォームで再生できるように、複数の形式へ変換する際の難しさをよくご存じでしょう。 現在、企業や個人を問わず、かつてないほど多くの動画コンテンツが制作されており、その変換作業が大きな課題となっています。幸い、この問題には効果的な解決策があります。それがAmazon Web Services(AWS)です。 AWSを利用すれば、動画をクラウドにアップロードし、希望する形式へ変換できます。クラウドベースの変換の最大のメリットは、自分のPCへの負担を軽減しながら、手間をかけず