跳轉至內容

LPI Linux 認證/郵件流量管理

來自 Wikibooks,開放世界中的開放書籍

詳細目標

[編輯 | 編輯原始碼]

權重:3

描述: 候選人應該能夠實施客戶端電子郵件管理軟體來過濾、排序和監控傳入的使用者郵件。

  • 關鍵知識領域
    • procmail 配置檔案、工具和實用程式
    • 在伺服器端和客戶端上使用 procmail
  • 以下是使用的檔案、術語和實用程式的部分列表
    • ~/.procmail
    • /etc/procmailrc
    • procmail

郵件流量管理

[編輯 | 編輯原始碼]

procmail 是由德國的 Stephen van den Berg 編寫的郵件處理實用程式語言。本文為中級 Unix 使用者提供了一些關於如何使用 procmail 的背景資訊。作為一種“小型”語言(使用學術術語),procmail 缺少傳統通用語言的許多特性和結構。它沒有“while”或“for”迴圈。但是,它“瞭解”很多關於 Unix 郵件傳遞約定和檔案/目錄許可權的資訊——特別是關於檔案鎖定的資訊。儘管可以使用大多數 Unix 系統上安裝的工具,用任何程式語言編寫自定義郵件過濾指令碼都是可能的——我們將展示 procmail 是系統管理員和高階 Unix 使用者的首選工具。

Unix 郵件系統由 MTA(郵件傳輸代理,如 sendmail、smail、qmail mmdf 等)、MDA(傳遞代理,如 sendmail、deliver 和 procmail)和 MUA(使用者代理,如 elm、pine、/bin/mail、mh、Eudora 和 Pegasus)組成。

在網際網路上的大多數 Unix 系統上,sendmail 被用作整合的傳輸和傳遞代理。sendmail 和相容的 MTA 能夠透過兩種機制之一(別名和 .forward)*透過*自定義過濾器或程式排程郵件。

別名機制使用單個檔案(通常為 /etc/aliases 或 /usr/lib/aliases)來重定向郵件。此檔案由系統管理員擁有和維護。因此,您(作為使用者)無法修改它。“.forward”機制是分散的。系統上的每個使用者都可以在其主目錄中建立一個名為 .forward 的檔案,該檔案包含一個地址、一個檔名或一個程式(過濾器)。通常,該檔案*必須*由使用者或 root 擁有,並且*不能*被其他使用者“寫入”(良好的 sendmail 版本出於安全原因會檢查這些因素)。

還可以使用某些版本的 sendmail 指定多個地址、程式或檔案,這些地址、程式或檔案用逗號分隔。但是,我們將跳過這方面的細節。郵件流量管理

您可以透過任何任意程式轉發您的郵件,該程式的 .forward 包含如下所示的行

"|$HOME/bin/your.program -and some arguments"

請注意引號和“管道”字元。它們是必需的。“Your.program”可以是 Bourne shell 指令碼、awk 或 perl 指令碼、已編譯的 C 程式或您想要編寫的任何其他型別的過濾器。

但是,“your.program”必須編寫為處理有關 sendmail 如何將訊息(標題和正文)傳遞給它的眾多詳細資訊,如何將返回值返回給 sendmail,如何處理檔案鎖定(如果郵件在“your.program”仍在處理一個郵件時到達,等等)。這就是 procmail 為我們提供的功能。

到目前為止,我們看到的是適用於所有 sendmail 相容 MTA/MDA 的一般資訊。郵件流量管理

因此,為了確保郵件被傳遞給 procmail 進行處理,第一步是建立 .forward 檔案。(在您執行任何 procmail 本身的配置之前,執行此操作是安全的——假設軟體包的二進位制檔案已安裝)。以下是 procmail 手冊頁中貼上的規範示例

"|IFS=' '&&exec /usr/local/bin/procmail -f-||exit 75 #YOUR_USERNAME"

如果您執行此操作且沒有其他操作,您的郵件基本上不會受到影響。procmail 將只查詢其預設配方檔案 (.procmailrc),如果找不到,它將對每條訊息執行其預設操作。換句話說,它會將新郵件追加到您的正常郵件池檔案中。

您可以將 procmail 作為 sendmail/postfix 中的本地傳遞代理在系統範圍內進行設定。完成此操作後,您可以跳過關於使用 .forward 檔案的整個部分——或者您也可以繼續使用它。例如,在 sendmail 中,可以透過以下方式更改 sendmail.mc 來完成此操作

MAILER_DEFINITIONS
dnl # MAILER(`local')dnl <- comment this one out with dnl
MAILER(`procmail')dnl
MAILER(`smtp')dnl

在 postfix 中,可以根據postfix 常見問題解答來完成此操作。基本上,只需使用以下內容編輯 /etc/postfix/main.cf 並重新載入 postfix 即可。

/etc/postfix/mail.cf:
mailbox_command = /path/to/procmail

無論哪種情況,自動化郵件處理的下一步是在您的主目錄中建立一個 .procmailrc 檔案。您實際上可以將此檔案命名為您想要的任何名稱——但隨後您必須將名稱顯式地放入 .forward 檔案中(正好在“||”運算子之前)。幾乎每個人都只使用預設值。

到目前為止,我們討論的只是所有內容如何路由到 procmail——這主要涉及 sendmail 和 Bourne shell 的語法。幾乎所有 sendmail 都配置為使用 /bin/sh(Bourne shell)來解釋別名和 .forward“管道”。

因此,這是一個非常簡單的 .procmailrc 檔案

:0c:
$HOME/mail.backup

這只是將所有傳入郵件的額外副本追加到您主目錄中名為“mail.backup”的檔案中。請注意,為您預設了許多環境變數。有人建議您應該顯式設定 SHELL=/bin/sh(或系統上可用的最接近 Bourne Shell 的派生版本)。我從未擔心過這個問題,因為我大多數系統上使用的 shell 已經與 Bourne 相容。

但是,csh 和其他 shell 使用者應該注意,我見過的所有 procmail 配方示例都使用 Bourne 語法。

:0 行標誌著“配方”(過程、子句,無論什麼)的開始。:0 後面可以跟隨許多“標誌”。組合這些標誌的方式不勝列舉。我們在本示例中使用的標誌是“c”,表示“複製”。

此行上的第二個冒號標誌著標誌的結束和鎖定檔名稱的開始。由於沒有給出名稱,procmail 將自動選擇一個。

這有點複雜。郵件可能會成批到達。如果在您的指令碼仍在忙於處理上一條郵件時到達了一條新郵件,您將擁有多個 sendmail 程序。每個程序都將處理一條郵件。這本身並不是問題。但是,如果這兩個程序可能嘗試同時寫入一個檔案,它們很可能會以不可預測的方式混淆(結果將不是格式正確的郵件資料夾)。

因此,我們提示 procmail 它將需要檢查並建立鎖定檔案。在本例中,我們不關心鎖定檔案的名稱是什麼(因為我們不會讓*其他*程式寫入備份檔案)。因此,我們將最後一個欄位(冒號之後)留空。然後,procmail 將選擇它自己的鎖定檔名。

如果我們從配方標題行中刪除 :(完全省略最後一個欄位),則不使用鎖定檔案。當我們打算僅從配方中的檔案讀取時,或者當我們打算僅按任意順序(如日誌檔案條目)向檔案寫入簡短的單行條目時,這適用。procmail 的工作方式是

它從 sendmail(或某些 sendmail 相容的 MTA/MDA)接收一條訊息。由於新郵件可能到達的速度快於處理速度,因此當前可能正在執行多個 procmail 處理。它開啟其配方檔案(預設為 .procmailrc 或在其命令列上指定),並從第一個到最後一個解析每個配方,直到訊息被“傳遞”(或“處理”)。

任何配方都可以是訊息的“處理”或“傳遞”。一旦訊息被“傳遞”,procmail 就會關閉其檔案、刪除其鎖並退出。

如果 procmail 到達其 rc 檔案(以及所有包含的檔案)的末尾而沒有“處理”訊息,則訊息將追加到您的郵件池檔案(對您和所有“郵件使用者代理”(如 Eudora、elm 等)來說,這看起來像正常的傳遞)。

這解釋了為什麼 procmail 在您*沒有*.procmailrc 時非常寬容。它只是將您的郵件傳遞到郵件池,因為它已到達所有配方的末尾(沒有配方)。“c”標誌會導致配方對訊息的“副本”進行操作——這意味著該配方採取的任何操作都不被視為訊息的“處理”。

如果沒有“c”標誌,此配方將捕獲所有傳入訊息,並且所有郵件都將最終儲存在 mail.backup 中。其中沒有任何郵件會進入您的郵件池檔案,並且不會解析其他任何配方。

此示例配方中的下一行只是一個檔名。與 sendmail 的別名和 .forward 檔案一樣,procmail 識別三種對任何訊息的處理。您可以將其追加到檔案、轉發到其他郵件地址或透過程式對其進行過濾。

實際上,procmail 處理了一種特殊的“傳遞”或“處理”形式。如果您為它提供目錄名(而不是檔名),它會將訊息作為單獨的檔案新增到該目錄中。該檔案的名稱將基於您不必擔心的幾個相當複雜的因素,除非您使用 Rand MH 系統或其他一些相對模糊和“奇特”的郵件代理。

procmail 配方通常由三個部分組成——開始行(帶有某些標誌的:0)、一些條件(以“*”(星號)字元開頭的行)和一個“傳遞”行,該行可以是檔案/目錄名稱或以“!”(感嘆號)字元或“|”(管道)字元開頭的行。

以下是一個示例

:0
* ^From.*someone.i.dont.like@somewhere.org
/dev/null

這是一個簡單的示例,不包含任何標誌、一個條件和一個簡單的檔案傳遞。它只是丟棄來自“我不喜歡的人”的任何郵件。(Unix 下的 /dev/null 是一個“位桶”——一個用於丟棄不需要的輸出的無底洞,DOS 有類似的概念,但它並不像 Unix 下的那麼方便)。

以下是一個更復雜的示例

:0
* !^FROM_DAEMON
* !^FROM_MAILER
* !^X-Loop: myaddress@myhost.mydomain.org
| $HOME/bin/my.script

它由一組否定條件組成(請注意,所有條件都以“!”字元開頭)。這意味著:對於任何不是來自“守護程式”(某些自動化程序)且不是來自“郵件傳送程式”(某些其他自動化程序)並且不包含任何形式為“X-Loop: myadd…”的頭行的郵件,將其透過我的 bin 目錄中的指令碼進行處理。

我可以直接將指令碼放在 rc 檔案中(大多數 procmail 使用者大部分時間都是這麼做的)。這個指令碼可能會對郵件做任何事情。在這種情況下——無論它做什麼,最好是好的,因為 procmail 方式會認為任何這樣的郵件都被投遞了,並且此後的任何規則只會收到來自 DAEMON、MAILER 和郵件頭中具有該特定 X-Loop: 行的郵件。

這兩個特定的 FROM_ 條件實際上是“特殊的”。它們由 procmail 預設,實際上指的是幾個相當複雜的正則表示式,這些表示式經過精心設計以匹配大多數來自守護程序和郵件傳送器的郵件頭中發現的內容。

X-Loop: 行是一個正常的 procmail 條件。在 RFC822 文件(定義了電子郵件頭在網際網路上應是什麼樣子)中,任何以 X- 開頭的行都是“自定義”頭。這意味著任何想要新增的郵件程式都可以新增幾乎任何 X- 行。

一個常見的 procmail 習慣用法是在我們傳送出的任何郵件的標題中新增 X-Loop: 行——並在傳送任何內容之前檢查我們自己的 X-Loop: 行。這是為了防止“郵件迴圈”——我們的郵件被轉發或“退回”給我們,而我們無限期地回覆它。

因此,這是一個關於如何使用 procmail 自動回覆特定人員的郵件的詳細示例。我們從規則頭開始。

:0

…然後我們新增一個條件(郵件似乎來自相關人員)

* ^FROMharasser@spamhome.com

FROM 是 procmail 的一個“魔法”值——它檢查 from、resent-by 和類似的標題行。您也可以使用 ^From:——它只會匹配以字串“From:”開頭的標題行。

^(打嗝或更專業的“脫字元號”) 是一個“正則表示式錨”(一個技術術語,意思是“它指定模式必須在何處才能匹配”。有一整本書講正則表示式(O'Reilly & Associates)。“正則表示式”滲透到許多 Unix 實用程式、指令碼語言和其他程式中。每個應用程式的“正則表示式”語法略有不同。但是,'grep' 或 'egrep' 的手冊頁是瞭解更多資訊的絕佳場所。

在這種情況下,打嗝表示模式必須出現在一行的開頭(這在 grep、ed/sed、awk 和其他上下文中是它的常用含義)。

…我們新增幾個條件以避免迴圈並避免回覆自動系統

* !^FROM_DAEMON
* !^FROM_MAILER

(這兩個是更多“魔法”值。手冊頁顯示分配給這些關鍵字的確切正則表示式——如果您好奇或需要調整類似於這兩個之一的特殊條件)。

…以及另一個防止棘手迴圈的條件

* !^X-Loop: myaddress@myhost.mydomain.org

(所有這些模式都以“感嘆號”(感嘆號)開頭,因為條件是標題的*任何*行都不以這些模式中的任何一個開頭。在這種情況下(以及大多數其他正則表示式上下文)中的“感嘆號”會“否定”或“反轉”模式的含義)。

…現在我們新增一個“處理方式”——自動回覆。

| (formail -rk \
-A "X-Loop: yourname@youraddress.com" \
-A "Precedence: junk"; \
echo "Please don't send me any more mail";\
echo "This is an automated response";\
echo "I'll never see your message";\
echo "So, GO AWAY" ) | $SENDMAIL -t -oi 

這非常複雜——但以下是它的工作原理:| 字元告訴 procmail 它應該啟動一個程式並將訊息饋送到它。左括號是 Bourne shell 結構,它以一種將所有輸出組合成一個“流”的方式對一組命令進行分組。

‘formail’ 命令是一個方便的程式,包含在 procmail 包中。它根據其命令列開關和輸入“格式化”郵件頭。-rk 告訴 'formail' 格式化“回覆”並“保留”郵件正文。使用這些開關,formail 期望輸入標題和正文。

-A 引數告訴 formail “新增”下一個引數作為標題行。提供給 -A 開關的引數必須用引號括起來,以便 shell 將整個字串(包括空格)視為單個引數。每行末尾的反斜槓告訴 procmail 郵件將下一行視為此行的一部分。因此,所有以反斜槓結尾的行都被作為一行長行傳遞給 shell。

這個“尾隨反斜槓”或“行延續”字元是許多程式語言和配置檔案格式中常見的 Unix 習慣用法。分號告訴 shell 執行另一個命令——它們允許在同一命令列上發出多個命令。

每個 echo 命令都應該相當容易理解。如果我們想的話,我們可以使用 'cat' 命令並將我們的文字放入一個檔案中。我們也可以在這裡呼叫其他程式——比如 'fortune' 或 'date',它們的輸出將與其餘部分結合起來)。

現在我們到了右括號。這標誌著我們組合的命令塊的結束。所有這些的輸出都饋送到下一個管道——它啟動本地 sendmail 副本(請注意,這是 procmail 為我們預設的另一個變數)。

sendmail 上的 -t 開關告訴它從其輸入的標題('formail -r' 放置的位置)獲取“To:”地址,-oi 開關啟用 sendmail 的“選項”以“忽略”僅由“點”組成的行(不要擔心這方面的細節)。

理解 procmail 的大部分困難與 procmail 本身無關。正則表示式的複雜性(那些奇怪的 '*'——條件行)以及 shell 引號和命令語法,以及如何格式化 sendmail 可以接受的回覆標題('formail' 和 'sendmail' 內容)是需要如此多解釋的部分。

有關 procmail 的更多資訊,請參閱 Era Eriksson 的“迷你常見問題解答”。在http://www.iki.fi/~era/procmail/mini-faq.html或幾個映象之一,如http://www.zer0.org/procmail/mini-faq.htmlhttp://www.dcs.ed.ac.uk/home/procmail/faq/mini-faq.html

關鍵詞、檔案和實用程式:Procmail .procmailrc


華夏公益教科書