如何使用 procmail 根据日期拆分现有邮箱

如何使用 procmail 根据日期拆分现有邮箱

我有一个巨大的邮箱,我想根据其内容的时间来管理:备份、存档或删除。我想按照这些邮箱所包含邮件的日期拆分这些邮箱。

对于邮箱:

${MAILDIR}/${TOPIC}

这是我想要跨越的新目录结构的方案:

${MAILDIR}/${YEAR}/${MONTH}/${TOPIC}

有没有办法在没有太多分叉命令的情况下实现这种拆分?

答案1

首先,需要澄清一些问题。标Date:头不太可靠,因为发送者可以将其设置为几乎任何内容。然而,其他选择也不是很有吸引力。一些邮件客户端实际上尝试解析Received:标头,但由于标头的内容未正确标准化,因此可能会失败。如果您的消息采用 Berkeley mbox 格式,则From_伪标头通常包含本地传递时间戳,但我想有些传递程序也忽略了这一点(而且看起来您无论如何都没有使用 mbox)。

那么,让我们看看如何在Date:不分叉的情况下解析 RFC822 标头。

另一个难题是并非所有发件人都在此标头中使用有效的 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

为了完成此任务,我使用了 shell 脚本和 procmailrc 文件。

shell脚本的核心只是一种分割巨大邮箱并使用调整后的procmailrc文件将其提供给procmail的方法:

$ cat <<eof >splitter.sh
#!/bin/sh

orig_mailbox=$1

formail -s <${orig_mailbox} procmail ${HOME}/src/splitter_procmailrc
eof

procmailrc 文件基于单个规则,该规则将用于date从标头中提取正确的字段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

第二条规则在这里是为了防止我在第一条规则上发现任何错误,以便能够对问题进行排序并调整 procmailrc 文件。

相关内容