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

이 작업을 수행하기 위해 쉘 스크립트와 procmailrc 파일을 사용했습니다.

기본적으로 쉘 스크립트는 거대한 메일함을 분할하고 조정된 procmailrc 파일을 사용하여 이를 procmail에 공급하는 방법일 뿐입니다.

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

orig_mailbox=$1

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

dateprocmailrc 파일은 헤더에서 올바른 필드 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 파일을 조정할 수 있도록 첫 번째 규칙에서 오류를 찾는 것을 방지하기 위한 것입니다.

관련 정보