내용의 보존 기간(백업, 보관 또는 삭제)을 기준으로 관리하고 싶은 대용량 사서함이 있습니다. 나는 포함된 메시지의 날짜를 기준으로 이 편지함을 분할하고 싶습니다.
이메일의 경우:
${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
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
두 번째 규칙은 문제를 정렬하고 procmailrc 파일을 조정할 수 있도록 첫 번째 규칙에서 오류를 찾는 것을 방지하기 위한 것입니다.