
コンテンツの保存期間(バックアップ、アーカイブ、または削除)に基づいて管理したい大容量メールボックスがあります。私は含まれているメッセージの日付に基づいてこのメールボックスを分割したいと思います。
メールの場合:
${MAILDIR}/${TOPIC}
私が拡張したい新しいディレクトリ構造のスキームは次のとおりです。
${MAILDIR}/${YEAR}/${MONTH}/${TOPIC}
あまりにも多くの分岐命令なしでこの分割を達成する方法はありますか?
答え1
まず、いくつかの説明が必要です。Date:
送信者はヘッダーにほぼすべての項目を設定できるため、ヘッダーの信頼性が低下します。しかし、代替案もあまり魅力的ではありません。一部のメールクライアントは実際にヘッダーを解析しようとしますReceived:
が、ヘッダーの内容が正しく正規化されていないため、失敗する可能性があります。メッセージがBerkeley mbox形式の場合、From_
疑似ヘッダーには通常ローカル配信タイムスタンプが含まれていますが、一部の配信プログラムではこれを無視すると思います(とにかくmboxを使用していないようです)。
Date:
それでは、RFC822ヘッダをフォークせずに解析する方法を見てみましょう。
もう1つの問題は、すべての送信者がこのヘッダーに有効なRFC822日付を使用していないことです。スパムを分類しないと仮定すると、スパムを分類している通信事業者の代替パターンを識別できます。ここではそのワームを無視します。 (スパムを処理しながらこのような現象に触れましたが、日本IIRCから送られるメールではかなり一般的なようです。)
あなたは毎月何日であるかは関係ありませんが、他の人がこの情報が役に立つと思う場合に備えてここにも含めます。
# Poor man's associative array... Remove leading zeros if desired
# (but then also change the MONTH regex below, as per comment there)
MONTHS='Jan 01
Feb 02
Mar 03
Apr 04
May 05
Jun 06
Jul 07
Aug 08
Sep 09
Oct 10
Nov 11
Dec 12'
:0
* ^Date:[ ]*[A-Z][a-z][a-z], \/[ 0-3][0-9] [A-Z][a-z][a-z] [12][0-9][0-9][0-9]
{
RDATE=$MATCH
:0
* RDATE ?? ^ *\/[1-9][0-9]?
{ DAY=$MATCH }
:0
* RDATE ?? () \/[12][0-9][0-9][0-9]
{ YEAR=$MATCH }
:0
* RDATE ?? () \/[A-Z][a-z][a-z]
{ MON=$MATCH }
:0 # Adjust if you don't want leading zeros -- $MON \/[1-9][0-9]?
* $ MONTHS ?? $MON \/[01][0-9]
{ MONTH=$MATCH }
:0 # Assume TOPIC is set by caller, or somehow determined above
$YEAR/$MONTH/$TOPIC
}
上記の設定を確認するために\/
特別なタグを使用すると、その後に一致するすべてのエントリがキャプチャされMATCH
(Procmailには正しい逆参照がない)、条件の前にプレフィックスを追加すると、条件が変数のVAR ??
値に適用されます。VAR
メッセージヘッダ。最後に、$
条件に変数の拡張値(通常は$
改行文字のみを示す)を含めたい場合は、それを使用する必要があります。ああ、そしていつものように、スペースは[ ]*
タブとスペースでなければなりません。
上記のレシピは、主に単一のメッセージを解析するためのものです。メールボックスを日付別に分割したい場合は、各メッセージを個別に解析してから、そのメッセージをその場所に保持するのを回避する方法を知りません。
最適化を圧縮し、限られた時間内にメッセージを受信するには、次のように扱いたい月ごとに正規表現を列挙できます。
for month in 2014/11 2014/12 2015/01 2015/02 2015/03; do
printf ':0\n* ^Date:[ \t]*[A-Z][a-z][a-z], [ 0-3][0-9] %s\n%s/$TOPIC\n' \
"$(date -d "${month%/*}-${month#*/}-01" +'%b %Y')" "$month"
done >months.rc
しかし、これが実際にサイクルを節約できるとは全く確信していません。 (必要なら測定してください!:-)
答え2
これを行うには、シェルスクリプトとprocmailrcファイルを使用しました。
デフォルトでは、シェルスクリプトは巨大なメールボックスを分割し、調整されたprocmailrcファイルを使用してそれをprocmailに供給する方法です。
$ cat <<eof >splitter.sh
#!/bin/sh
orig_mailbox=$1
formail -s <${orig_mailbox} procmail ${HOME}/src/splitter_procmailrc
eof
date
procmailrcファイルは、ヘッダーから正しいフィールドDate:
(クリーンなオペレーティングシステムではシステム生成フィールド)を抽出するために使用される単一の規則に基づいています。フォーマットの必須フィールドdate
も出力されます。YYYY/MM
"+%Y/%m"
cat <<eof >${HOME}/src/splitter_procmailrc
MAILDIR=${HOME}/Mail/tmp
LOGFILE=${HOME}/Mail/tmp/procmail.log
:0 w
* ^Subject: TOPIC
* ^Date: \/.*$
| ( ;\
ORIG_MONTH_DIR=`date -j -f "%a, %d %b %Y" "${MATCH}" "+%Y/%m"` ;\
[ -d ${ORIG_MONTH_DIR} ] || mkdir -p ${ORIG_MONTH_DIR} ;\
cat >>${ORIG_MONTH_DIR}/TOPIC ;\
)
:0 E
Error
eof
2番目のルールは、問題を並べ替え、procmailrcファイルを調整できるように、最初のルールでエラーが見つからないようにすることです。