Postfix的投遞過程詳解
在我們討論本地郵件的投遞過程之前,先讓我們理清“本地”、“外地”、“虛擬”這三種郵件的定義以及相關的MDA.
Postfix的投遞代理程序
postfix依據來信地址來決定是否要收下郵件以及如何選擇適當的MDA來執行后續的投遞任務。postfix會收下三種網域的郵件,分別是本地(local)、轉發(relay)以及虛擬(virtual),它們的定義與相關的MDA,如下:
本地郵件
若郵件終點站是mydestination參數所列出的網域之一,postfix就視其為本地郵件,由local MDA(或是你指定的其他程序)執行投遞任務。本地郵件的收件者必須擁有本地系統(postfix server本身所在的主機)的用戶賬戶,或是其名稱被定義在別名文件(傳統上是/etc/aliases)。本地郵件會被投遞到系統的郵件存儲目錄(通 常是/var/spool/mail/),或個人主目錄下的郵件文件(~/mail/)。
轉發郵件
若郵件終點站是relay_domains參數所列出的網域之一,postfix就視其為轉發郵件,由relay MDA來執行投遞任務。一般而言,只有在postfix被當成局域網絡的郵件網關使用,而同網絡上還有其他網域的郵件服務器時,才會讓postfix收下 轉發郵件。也就是說,所謂的“轉發”,通常是指同局域網絡上的其他主機,而relay其實是smtp MDA的翻版,只不過被刻意設計成特別適合傳信給局域網絡上主機而已。
虛擬網域郵件
一臺郵件服務器通常只服務一個范圍網域 (canonical domain);如果要同時服務多個網域,則額外的網域稱為虛擬網域(virtual domain)。虛擬網域的郵件由virtual MDA負責投遞。依據用戶是否有服務器的系統賬號,虛擬網域的郵件還可分成“虛擬郵箱”與“虛擬別名”兩種。虛擬郵箱的收件人沒有系統賬戶,而且每一個虛 擬郵箱網域都有自己的郵箱目錄(mail spool),所有虛擬郵箱網域都必須列于virtual_mailbox_domains參數。另一方面,虛擬別名網域的收件人可以擁有本地或非本地系 統賬戶,postfix會改寫這類郵件的收件地址,然后交給smtp MDA遞送出去(如果新地址是非本地網域),或重新回到收件隊列(如果新地址是本地網域)。
郵箱格式
當postfix投 遞本地郵件時,郵件內容會被傳送到postfix系統上的適當郵箱。最常見的兩種郵箱格式,分別是傳統的mbox以及較新的 maildir。兩者都是使用一般的文件來儲存郵件內容,差別在于文件內部的組織安排有所不同。在postfix中,當你設定任何郵件文件或目錄參數時, 如果在路徑末端加注一個/符號,表示你想使用maildir格式的郵箱。
mbox格式
傳統上,unix系統將同一位用戶 的所有郵件都塞在同一個文件里,像這樣的郵箱格式通常稱為mbox。郵箱文件里的每一封郵件,其第一行的前五個字符必定是“from ”。習慣上,為了方便表示,我們通常將它寫成“from_“,以下劃線字符強調空格的存在請勿將mbox文件內用來分隔郵件的”from “字樣與郵件標頭里的”from:“字段混為一談。郵件在mbox文件里的最后一行必定為空格。因此,一行空格接著一個from_字樣,就可視為下一封信 的開始。
postfix將郵件寫入mbox文件之前,會先使用信封上的寄件人地址與當時的日期創建好from_文本行,并將該行字符串寫到 mbox文件的末端,然后才開始填入郵件內容。如果postfix發現郵件內容本身有任何以“from”開頭的文本行,它會在該文本行的開頭加一個 >符號,避免該文本行被誤以為下一封信的開頭。
當pop/imap server讀取mbox文件內的郵件時,第一步是掃描文件內容,找出代表郵件開頭的from文本行。在讀取郵件內容時,如果遇到下一個from_文本行 (或文件結尾),就可斷定當前的郵件已經讀完了。有些pop/imap server會主動恢復">from"的原狀,但有些不會。
由于 postfix和pop/imap server有可能會同時訪問同一個mbox文件,所有它們必須使用“文件鎖定機制”(file locking)來確保訪問權。在local投遞本地郵件之前,必須先將該文件加鎖,然后才能將郵件內容寫入mbox文件。postfix支持多種鎖定機 制,視系統平臺而定。利用postconf -l命令可查看你的系統提供了哪些鎖定機制可供postfix使用:
postconf -l
如果想知道postfix在你系統上列出的各種鎖定機制的詳細信息,請把鎖定機制的名稱告訴man:
man folck
如 果你的系統平臺支持flock和fcntl,應該就可以找到它們的在線說明文件,因為這兩者都是操作系統或函數庫提供的功能,而任何系統平臺都支持的 dotlock機制,很可能找不到說明文件,因為dotlock只是程序之間一種不成文協議,不需要額外的函數庫。dotlock的原理很簡單,舉個例子 就可以說明清楚。假設postfix要訪問user1郵件文件,它必須先檢查該文件的同目錄下是否存在一個.user1.lock文件,如果存在,表示 user1郵件文件當前被另一個進程占用;如果.user1.lock文件步存在,postfix就自己產生一個,讓其他進程知道user1文件當前正被 占用。在postfix關閉user1文件之后,要主動移除.user1.lock文件,讓其他進程可以使用user1郵件文件。dotlock鎖定機制 的缺點是它沒有強制性(任何進程都可以不檢查,user1.lock是否存在而徑直訪問user1文件),而且效率不佳。
通常你可以不必擔心鎖定機制的細節,也不必理會系統支持哪些類型的鎖定機制,因為postfix能自動做出最佳選擇。
maildir格式
maildir 郵箱格式不同于mbox之處,在于它使用目錄結構來存儲郵件。maildir的設計原意為了解決mbox格式的可能性與文件鎖定問題。例如,如果在郵件內 容還沒完全寫入mbox文件之前,系統就死機了,這時候可能只有部分內容在郵箱里。當系統恢復運行,MDA將郵件寫入郵箱時,新的內容會接在前次殘缺內容 的后面,因而造成問題。
mbox格式的另一個缺點,是發生在pop/imap server與smtp server試圖同時開啟同一個郵箱時。如果雙方沒有使用相同的鎖定機制,郵箱文件可能因此受損。先前說過,保護文件的鎖定機制有好幾種,但是并非所有郵 件程序都使用鎖定機制。但如果使用maildir格式,則可以不使用文件保護鎖,因為每一封郵件都是存放在單獨的一個文件里。因此,不用的郵件程序,不可 能同時訪問同一個文件。
一個maildir風格的目錄,其下有三個子目錄:tmp/、new/以及cur/。這些子目錄與它們的上層目錄必須位于同一個文件系統,習慣上,它們應該放在用戶的主目錄的郵件目錄下
在new/目錄下的郵件文件,是MDA已經送達但是尚未被用戶閱讀的信,文件本身的修改時間,就是收下郵件的時間。郵件文件通常包含RFC 2822格式的郵件,而且不需要“from_"。
用戶看過郵件之后,郵件文件會被轉移到cur/目錄。tmp/目錄供MDA將郵件內容存儲成文件,在確定全部內柔都寫入文件之后,郵件文件會被搬到new/目錄。
應該選擇mbox還是maildir?
這 個問題沒有簡單的答案。哪一種郵箱格式最適合你,取決于許多因素。mbox格式的好處是幾乎全世界都支持,但也正是因為它有文件鎖定問題,而導致了 maildir格式的出現。而maildir格式在規模適合性方面也頗受質疑,因為某些文件系統可能無法應付太多的郵件文件。在效率方面,兩種格式各有各 優缺點:搜索、訪問、刪除特定郵件時,maildir的速度比較快;但是就MDA的投遞工作效率而言,直接將郵件內容放入文本未(mbox格式)可能比較 快。實際上,你的選擇可能要看你所用的POP/IMAP SERVER而定,如果你架設的POP/IMAP SERVER只支持maildir格式,很顯然你沒有選擇的余地。postfix對兩種格式都支持,所以你只要考慮其他因素就行。如果你的環境讓你感覺到 為難,建議你測試兩種格式,盡量以接近實際的運行環境和工作量來實驗,依據實驗結果做出選擇。
#p#
本地郵件的投遞操作
若收件 地址的網域部分,是列在mydestination參數的所有網域之一,postfix就將其當成本地郵件交給local MDA進行投遞。你可以隨意在mydestination列出多個網域,但是本地的個別用戶會收到所有網域的郵件。舉例來說,如果 oreilly.com、ora.com和oreillymedia.com同時被列在mydestination參數,則寄給 kdent@ora.com、kdent@oreilly.com或kdent@oreillymedia.com的郵件,最后都是進入同一個本地郵箱。 為了避免收下不明用戶的郵件,所有本地收件人的名稱都必須列在local_recipient_maps參數所指的表中。此參數的默認值是指向unix系 統的密碼文件與別名表,所以你通常不需要修改它。
檢查郵件地址的人名部分時,postfix先檢查別名表。如果發現相符的別名,則以該別名對應的 名稱為新的收件人,重新提交郵件,當成新郵件處理;否則,就試著將郵件傳給系統上的用戶。postfix先檢查當地用戶是否設置了自己的.forward 文件,如果有,則依據其設定內容來轉寄郵件;乳溝沒有,則將郵件放入用戶的郵箱。
.forward文件
.forward 文件讓用戶可以設置自己的別名。.forward文件的格式與別名文件的RHS-VALUE部分的格式一樣,甚至比其更寬松。比方說,別名文件的RHS- VALUE可以有多個以分號隔開的值,.forward文件也沿用相同慣例,但同時也容許你將值分別寫在不同的行。
.forward文件的擁有權 限必須是收件人的系統賬戶,而且通常放在用戶的主目錄下。你可以用forward_path參數來改變.forward文件的存放路徑。postfix提 供下列8大變量讓你表示.forward文件的存放路徑,這些變量的實際值,由投遞時的系統環境決定:
$user 收件人得賬戶名稱(信息來源: /etc/passwd)
$home 收件人得主目錄(信息來源: /etc/passwd)
$shell 收件人得shell
$recipient 收件人得完整郵件地址
$extension 收件地址得人名部分得擴展部分(不一定有),以+之類得分隔符與人名部分風格開。以 user1+labs@example.com為例,$extension等于user1。
$domain 收件地址的網域部分。
$local 收件地址的完整人名部分(包括擴展部分在內--如果有的話)。以user1+ labs@example.com為例,$local等于user1+labs。
$recipient delimiter 收件地址得人名部分與擴展部分之間得分隔符(通常是+)如果你增加對一個非標準得.forward文件得支持,可以參考下面得設定;
forward_path = /home/$user/.forward /home/$user/other_forward
別名投遞操作
當 別名文件指定了一個命令或文件時,postfix必須先將自己得執行身份改成別名文件擁有者,然后以該身份得權限來執行命令,或將郵件內容寫入文件。唯一 的例外是別名文件擁有者為root時,這時候postfix使用default_privs參數所指定的賬戶(默認值為nobody)
郵箱投遞操作
當postfix 將郵件投遞給一位本地用戶時,它必須將郵件內容寫入該用戶在系統上的郵箱。postfix默認使用的郵箱格式是mbox,當你安裝postfix時,它會 依據你所用的Unix平臺類型來決定郵件存儲目錄的位置。mail_spool_directory參數可用來指定一個默認之外的目錄,而目錄路徑的指定 方式會影響pstfix選擇何種郵件格式。舉例來說,假如你這樣設定:
mail_spool_directory = /var/spool/mail
這表示postfix應該使用mbox格式將郵件存在/var/spool/mail目錄下。如果你想改用maildir格式,則必須在目錄名稱之后附加一個/符號:
mail_spool_directory = /var/spool/mail/
你也可以要求postfix將郵件放在用戶的主目錄下。設定一個相對路徑給home_mailbox參數,表示你想要哪一個文件來作為郵箱:
home_mailbox = mbox
在路徑名稱之后附加一個/符號,表示postfix應該使用maildir格式的投遞程序:
home_mailbox = maildir/
這會使得postfix將郵件投遞到用戶主目錄下的maildir/子目錄。
注意: 使用maildir格式時,postfix通常會自動創建必要的子目錄與文件--如果用戶的身份權限足夠的話。不過,基于安全上的考慮,如果上層目錄的權限模式為775,則local MDA不會創建任何額外的文件或目錄。
通過上面的文章詳細的描述,大家都應該知道了如何用Postfix進行投遞的過程。希望對你們有所幫助!
【編輯推薦】
- PostfixAdmin 配置過程講解
- Postfix的郵件隊列管理
- 如何安裝PostfixAdmin
- Postfixadmin安裝手冊
- 如何對Postfix進行資源控制
- Postfix中的地址操作大全
- 教你如何設置Postfixadmin的自動回復