Postfix와 Sendmail
Spam Scanner는 두 가지 방식으로 Postfix와 연동합니다.
- milter로 연동(권장). Postfix는 SMTP 세션 중, 메시지를 수락하기 전에 각 메시지에 대해 Spam Scanner에 묻습니다. 스팸은 4xx 또는 5xx 응답으로 거부할 수 있으므로, 처리 책임은 수신 서버가 아니라 발신 서버가 집니다. Sendmail도 같은 프로토콜을 사용합니다.
- 콘텐츠 필터로 연동. Postfix가 메시지를 수락한 뒤
spamscanner filter로 파이프하면, 필터가 헤더를 추가하고 sendmail로 다시 넘겨줍니다. SMTP 세션 중에 거부되는 메일은 없습니다.
두 방식 모두 모든 메시지에 다음 헤더를 추가합니다.
X-Spam-Flag: YES
X-Spam-Score: 8.0
X-Spam-Level: ********
X-Spam-Status: Yes, score=8.0 required=5.0 tests=BAYES_99,DECEPTIVE_LINK version=7.0.0
X-Spam-Action: tag메시지에 이미 있는 X-Spam-* 헤더는 먼저 제거하므로, 발신자가 자기 메일을 정상으로 표시할 수 없습니다.
milter#
1. milter 실행#
npm install --global spamscanner
spamscanner milter --port 7831 --auth --subject-tag "[SPAM]" --verbose--reject를 사용하면 거부 임계값(15점)에 이른 메시지를 451 4.7.1 Message rejected as spam으로 거부합니다. 451은 일시적 오류이므로 발신 서버가 나중에 다시 시도하며, 잘못된 판정은 설정을 바꿔 바로잡을 수 있습니다. 결과가 적절해 보이면 --reject-code 550으로 영구 거부를 사용하십시오. --quarantine을 사용하면 스팸은 거부하는 대신 Postfix의 보류(hold) 큐로 보냅니다.
systemd 서비스로 실행하려면 /etc/systemd/system/spamscanner-milter.service에 다음을 작성합니다.
[Unit]
Description=Spam Scanner milter
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/spamscanner milter --port 7831 --auth --subject-tag [SPAM]
User=spamscanner
Group=spamscanner
Restart=on-failure
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
[Install]
WantedBy=multi-user.targetsudo useradd --system --no-create-home --shell /usr/sbin/nologin spamscanner
sudo systemctl daemon-reload
sudo systemctl enable --now spamscanner-milter2. Postfix에 milter 지정#
/etc/postfix/main.cf에 다음을 추가합니다.
smtpd_milters = inet:127.0.0.1:7831
milter_protocol = 6
# If the milter is down: accept mail unfiltered (accept) or ask senders to retry (tempfail).
milter_default_action = accept
# Long enough for a language model, if one is configured.
milter_content_timeout = 120ssudo postfix reloadsmtpd_milters는 SMTP로 도착하는 메일에 적용됩니다. sendmail 명령으로 제출한 메일도 검사해야 하는 경우가 아니라면 non_smtpd_milters는 비워 두십시오.
3. 테스트#
swaks로 테스트 메시지를 보냅니다. GTUBE는 모든 스팸 필터가 스팸으로 처리하는 테스트 문자열입니다.
swaks --to you@example.com --server 127.0.0.1 \
--body 'XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X'--reject 없이 실행하면 메시지는 X-Spam-Flag: YES와 표시가 붙은 제목으로 전달됩니다. --reject를 사용하면 swaks에 451 또는 550 응답이 표시됩니다.
콘텐츠 필터#
SMTP 세션 중에 메일을 절대 거부하면 안 되는 경우나, milter를 사용할 수 없는 서버에서 이 방식을 사용합니다.
/etc/postfix/master.cf에 필터 서비스를 추가하고 SMTP 리스너에서 사용하도록 설정합니다.
smtp inet n - n - - smtpd
-o content_filter=spamscanner:dummy
spamscanner unix - n n - 10 pipe
flags=Rq user=spamscanner null_sender=
argv=/usr/bin/node /usr/local/lib/node_modules/spamscanner/dist/esm/cli.js filter --subject-tag [SPAM] -f ${sender} -- ${recipient}Postfix는 거의 비어 있는 환경으로 필터를 실행하므로, argv에는 Node.js와 스크립트를 전체 경로로 지정합니다(command -v node와 npm root --global로 경로를 확인할 수 있습니다). 그다음 다음을 실행합니다.
sudo postfix reload필터는 sendmail -G -i로 메시지를 다시 넘겨줍니다. 이렇게 제출한 메일은 smtp 리스너를 다시 거치지 않으므로 두 번 필터링되지 않습니다.
종료 코드로 Postfix에 결과를 알립니다. 0은 전달, 69는 거부(--reject 사용 시 Postfix가 발신자에게 반송), 75는 일시적 실패(Postfix가 메시지를 보관하고 다시 시도)입니다. 검사나 전달에 실패하면 항상 75이므로, 설정이 잘못되어도 메일이 사라지거나 반송되지 않습니다.
Sendmail#
sendmail.mc에 다음을 추가합니다.
INPUT_MAIL_FILTER(`spamscanner', `S=inet:7831@127.0.0.1, F=T, T=S:30s;R:30s;E:5m')F=T를 지정하면 milter를 사용할 수 없는 동안 Sendmail이 일시적 실패로 응답합니다. 대신 필터링 없이 메일을 수락하려면 이 값을 빼십시오. sendmail.cf를 다시 빌드하고 Sendmail을 재시작합니다.
스팸을 Junk 폴더로 분류#
표시만 하면 스팸은 받은편지함으로 전달됩니다. Dovecot에서는 Sieve 규칙으로 스팸을 옮깁니다.
require ["fileinto"];
if header :is "X-Spam-Flag" "YES" {
fileinto "Junk";
stop;
}기타 메일 서버에서는 Dovecot, Exim, Haraka, procmail을 다루며, 학습에서는 사용자가 Junk 폴더로 옮기거나 Junk 폴더에서 꺼낸 메일로 학습하는 방법을 설명합니다.
테스트 현황#
저장소의 엔드투엔드 테스트는 실제 Postfix를 실행합니다. ham은 헤더와 함께 전달되고, 위조된 X-Spam-Flag는 제거되고, 스팸은 표시되고, GTUBE는 SMTP 세션 중에 550으로 거부되며, 콘텐츠 필터는 두 번째 포트에서 메일에 표시를 붙입니다. scripts/e2e-postfix.sh가 그 Postfix를 설정하고 test/e2e/postfix.test.js가 메일을 보냅니다.