1. 程式人生 > >SMTP協議工作原理及原始命令碼

SMTP協議工作原理及原始命令碼

1.介紹
  簡單郵件傳輸協議(SMTP)的目標是可靠高效地傳送郵件,它獨立於傳送子系統而且僅要求一條可以保證傳送資料單元順序的通道。附錄A,B,C和D描述了不同傳送服務下SMTP的使用。在名詞表中還定義了本文件中使用的術語。
  SMTP的一個重要特點是它能夠在傳送中接力傳送郵件,傳送服務提供了程序間通訊環境(IPCE),此環境可以包括一個網路,幾個網路或一個網路的子網。理解到傳送系統(或IPCE)不是一對一的是很重要的。程序可能直接和其它程序通過已知的IPCE通訊。郵件是一個應用程式或程序間通訊。郵件可以通過連線在不同IPCE上的程序跨網路進行郵件傳送。更特別的是,郵件可以通過不同網路上的主機接力式傳送。

2.SMTP模型
  SMTP設計基於以下通訊模型:針對使用者的郵件請求,傳送SMTP建立與接收SMTP之間建立一個雙向傳送通道。接收SMTP可以是最終接收者也可以是中間傳送者。SMTP命令由傳送SMTP發出,由接收SMTP接收,而應答則反方面傳送。
一旦傳送通道建立,SMTP傳送者傳送MAIL命令指明郵件傳送者。如果SMTP接收者可以接收郵件則返回OK應答。SMTP傳送者再發出RCPT命令確認郵件是否接收到。如果SMTP接收者接收,則返回OK應答;如果不能接收到,則發出拒絕接收應答(但不中止整個郵件操作),雙方將如此重複多次。當接收者收到全部郵件後會接收到特別的序列,如果接收者成功處理了郵件,則返回OK應答。

SMTP提供傳送郵件的機制,如果接收方與傳送方連線在同一個傳送服務下時,郵件可以直接由傳送方主機傳送到接收方主機;或者,當兩者不在同一個傳送服務下時,通過中繼SMTP伺服器傳送。為了能夠對SMTP伺服器提供中繼能力,它必須擁有最終目的主機地址和郵箱名稱。
  MAIL命令引數是回覆路徑,它指定郵件從何處來;而RCPT命令的引數是轉發路徑的,它指定郵件向何處去。向前路徑是源路徑,而回復路徑是返回路徑(它用於發生錯誤時返回郵件)。
  當同一個訊息要發往不同的接收者時,SMTP遇到了向不同接收者傳送同一份資料的複製品的問題,郵件命令和應答有一個比較奇怪的語法,應答也有一個數字程式碼。在下面,例子中可以看到哪些使用實際的命令和應答。完整的命令和應答在第四節。

  命令與應答對大小寫不敏感,也就是說,命令和應答可以是大寫,小寫或兩者的混合,但這一點對使用者郵件名稱卻不一定是對的,因為有的主機對使用者名稱大小寫是敏感的。這樣SMTP實現中就將使用者郵箱名稱保留成初始時的樣子,主機名稱對大小寫不敏感。
  命令與應答由ASCII字母表組成,當傳送服務提供8位位元組傳送通道,每7位字元正確傳送,而最高位被填充為0。當指定一般的命令或應答格式後,引數會由一些類似於語言的字串表示出來,如"<string>"或"<reverse-path>",這裡尖括號表示這是一種類似於語言的變數。
3.SMTP過程
  本節提供了SMTP中的一些過程。頭一個說明的是基本傳送過程(定義為傳送操作)。下來描述向前傳送郵件,確認郵箱名稱和擴充套件郵件列表,傳送到終端和開啟關閉交換。在本節的最後是對中斷,郵件域的說明。本節的例子只是一部分命令和應答的序列,完整的例子見附錄F。
3.1.MAIL
  在SMTP傳送操作中有三步,操作由MAIL命令開始給出傳送者標識。一系列或更多的RCPT命令緊跟其後,給出了接收者資訊,然後是DATA命令列出傳送的郵件內容,最後郵件內容指示符確認操作。

  過程中的第一步是MAIL命令,<reverse-path>包括源郵箱。

  MAIL<SP>FROM:<reverse-path><CRLF>

  此命令告訴接收者新的傳送操作已經開始,請復位所有狀態表和緩衝區。它給出反向路徑以進行錯誤資訊返回。如果請求被接收,接收方返回一個250OK應答。<reverse-path>中不止包括了郵箱,它包括了主機和源郵箱的反向路由,其中的第一個主機就是傳送此命令的主機。

  過程中的第二步是傳送RCPT命令。

  RCPT<SP>TO:<forward-path><CRLF>

  此命令給出向前路徑標識接收者,如果命令被接收,接收方返回一個250OK應答,並存儲向前路徑。如果接收者未知,接收方會返回一個550Failure應答。此過程可能會重複若干次。
  <forward-path>不僅包括郵件,它是主機和目的郵箱的路由表,在其中的第一個主機就是接收命令的主機。過程中的第三步是傳送DATA命令。

DATA<CRLF>

  如果命令被接收,接收方返回一個354Intermediate應答,並認定以下的各行都是信件內容。當信件結尾收到並存儲後,接收者傳送一個250OK應答。因為郵件是在傳送通道上傳送,因此必須指明郵件內容結尾,以便應答對話可以重新開始。SMTP通過在最後一行僅傳送一個句號來表示郵件內容的結束,在接收方,一個對使用者透明的過程將此符號過濾掉,以不影響正常的資料。
  注意:郵件內容包括如下提示:Date,Subject,To,Cc,From。

  郵件內容指示符確認郵件操作並告知接收者可以儲存和再發送資料了。如果此命令被接收,接收方返回一個250OK應答。DATA命令僅在郵件操作未完成或源無效的情況下失敗。

  上面所述的過程是一個傳送操作。這些命令只能以上面的順序使用。下例表示了在一個傳送操作中這些命令的使用。
  SMTP過程例子此例是在Alpha.ARPA主機的Smith傳送郵件給Beta.ARPA主機的Jones,Green和Brown的,這裡假定主機Alpha與主機Beta直接相連。

  S:MAILFROM:<[email protected]>
  R:250OK
  S:RCPTTO:<[email protected]>
  R:250OK
  S:RCPTTO:<[email protected]>
  R:550Nosuchuserhere
  S:RCPTTO:<[email protected]>
  R:250OK
  S:DATA
  R:354Startmailinput;endwith<CRLF>.<CRLF>
  S:Blahblahblah...
  S:...等等
  S:<CRLF>.<CRLF>
  R:250OK
  此信被前兩個人接收,而第三個人在此主機上沒有郵箱。
3.2.轉發
  下面是一些<forward-path>中目的地址不正確的,但接收者知道正確的目的地址的例子。在這些例子中,下列應答之一應該允許傳送方與獲得正確地址。

  251:使用者不在本地;將向前傳送到<forward-path>。

  這個應答意味著,接收方SMTP知道使用者的郵箱在另外的主機上,而且意味著將在未來使用正確的轉向路徑。請注意,主機或者使用者,或者它們兩者是不同的。接收方負責傳送訊息。

  551:使用者非本地,請嘗試<forward-path>

  這個應答意味著接收SMTP知道使用者的郵箱在另外的主機上,並意味著使用了正確的轉發路徑。注意請注意,主機或者使用者,或者它們兩者是不同的。接收方拒絕接收此使用者的信件,傳送者必須根據提供的資訊重新發送或者向原發送者返回錯誤資訊。下例顯示了這些響應的應用。

  轉發的例子
  S:RCPTTO:<[email protected]>
  R:251Usernotlocal;willforwardto<[email protected]>
  或者
  S:RCPTTO:<[email protected]>
  R:551Usernotlocal;pleasetry<[email protected]>
3.3.確認和擴充套件
  SMTP提供了另外的確認使用者名稱和擴充套件郵件列表的功能。這些功能由VREF和EXPN命令完成,它們都以字串為引數。對於VREF命令,字串引數指的是使用者名稱,對此命令的響應要包括使用者的命名和使用者的郵箱。對於EXPN命令,字串引數指的是郵件列表,對此命令的響應多於一個,它們要包括所有列表中使用者的命名和他們的郵箱。
  “使用者名稱”是一個多餘的專案,它是故意被加上的。如果主機採用VREF命令和EXPN命令,最後本地郵箱必須提供使用者名稱使它被主機確認。如果主機選擇由另外的字串作為使用者名稱,也是允許的。
  在一些主機中,郵箱列表和一個郵箱的代名有一點不清楚,因為一般的資料結構可能包括兩種型別的入口。如果要發出對郵件列表的確認,應該給出確定響應。在接收到這個訊息後,主機將把郵件傳送到列表上所有的地址上去,如果沒有接收到確定響應,就會報告錯誤。例如,"550Thatisamaillist,notausername"。如果請求用於擴充套件一個使用者名稱,可能通過返回包括一個名字的列表來形成確定響應,如果沒有接收到確定響應,就會報告錯誤。(例如,"550Thatisausername,notamailinglist")。
  在多個響應的情況下(通常是對於EXPN而言的),每個應答指定一個郵箱。在模糊請求的情況下,例如"VRFYSmith",這裡兩個Smith的響應必須是"553Userambiguous"。

  確認使用者名稱的情況如下例所示:例3:
  確認使用者名稱
  S:VRFYSmithR:250FredSmith<[email protected]>
  或者
  S:VRFYSmith
  R:251Usernotlocal;willforwardto<[email protected]>
  或者
  S:VRFYJones
  R:550Stringdoesnotmatchanything.
  或者
  S:VRFYJones
  R:551Usernotlocal;pleasetry<[email protected]>
  或者
  S:VRFYGourzenkyinplatz
  R:553Userambiguous.

  郵箱列表要求多個響應的情況如下例所示:
  S:EXPNExample-People
  R:250-JonPostel<[email protected]>
  R:250-FredFonebone<[email protected]>
  R:250-SamQ.Smith<[email protected]>
  R:250-QuincySmith<@USC-ISIF.ARPA:[email protected]>
  R:250-<[email protected]>
  R:250<[email protected]>
  或者
  S:EXPNExecutive-Washroom-List
  R:550AccessDeniedtoYou.

  VERF和EXPN命令的字串命令引數因為具體實現的不同而不能再加以限制了。在一些系統上,EXPN命令的引數可能是一個包含郵件列表的檔名,但是在Internet上有許多不同的檔案結構。
  VRFY和EXPN命令在最小實現中並不包括,當它們實現時,它們也不要求被在傳送間實現。 
3.4.傳送信件(mailing)和獲得信件(sending)
  SMTP的主要目的是將郵件傳送到使用者的郵箱中。由一些主機提供的類似的功能是把郵件送至使用者的終端(如果使用者正開啟終端)。將郵件送到使用者的郵箱中稱為傳送信件(mailing);而送至使用者終端則稱之為獲得信件(sending)。因為在一些主機上,這兩者的實現十分類似,所以它們同時被放入了SMTP中。然而,獲得信件命令在SMTP的最小實現中是沒有的。使用者應該具有控制向終端上寫資訊的能力。大部分主機允許使用者接受或者拒絕類似的資訊。
  下面三個命令被定義來支援獲得信件。它們被用於郵件命令而不是MAIL命令,指示接收SMTP這種操作的特殊意義:
  SEND<SP>FROM:<reverse-path><CRLF>
  SEND命令要求郵件內容直接傳送到使用者終端。如果使用者未開啟終端(或者未接收終端資訊),450響應將返回一個RCPT命令。如果資訊被成功傳送,此操作成功。 
  SOML<SP>FROM:<reverse-path><CRLF> 
  Send或者MaiL命令要求將郵件內容直接傳送到使用者的終端上(如果使用者在終端上)。如果使用者不在終端上,郵件內容直接進入郵箱。如果郵件被髮送到使用者終端或者使用者信箱,傳送操作成功。 
  SAML<SP>FROM:<reverse-path><CRLF>
  Send和MaiL命令要求郵件內容直接傳送到使用者終端上(如果使用者在終端上)。不管怎麼樣,信件都會進入信箱。如果信件進入信箱,傳送操作成功。
  用於MAIL命令的響應和這些命令的響應相同。 
3.5.開啟和關閉
  當開啟傳送通道時,要交換一些資訊以確定雙方的身份。以下的命令是用於開啟和關閉的:
  HELO<SP><domain><CRLF>
  QUIT<CRLF>
  在HELLO命令中,主機自己傳送命令,此命令可以被解釋為:“你好,我是XX"。

  開啟聯結的例子
  R:220BBN-UNIX.ARPASimpleMailTransferServiceReady
  S:HELOUSC-ISIF.ARPA
  R:250BBN-UNIX.ARPA

  關閉聯結的例子
  S:QUIT
  R:221BBN-UNIX.ARPAServiceclosingtransmissionchannel
3.6.轉發
  轉發路徑可能是如下格式:"@ONE,@TWO:[email protected]",在這裡,ONE,TWO和THREE是主機。這種格式用於強調地址和路徑的區別。郵箱是絕對地址,路徑是關於如何到達的資訊。這兩個概念不應該被混淆。
  概念上,轉發路徑的元素被移動到回覆路徑作為從一個SMTP伺服器到另一個SMTP伺服器的資訊。回覆路徑是一個反向資料來源路徑,例如從當前資訊的位置到發起者的位置。當一個SMTP伺服器從轉發路徑中刪除自己的標記並將它插入到回覆路徑中時,它必須使用它傳送環境能夠理解的名稱來進行,以防它的名稱在不同的環境中被理解為不同的名字。
  如果當SMTP接收到資訊的轉發路徑的第一個元素不是此SMTP的標記時,此元素不從轉發路徑中刪除,而被用來決定下一個應該傳送到的SMTP伺服器。在任何情況下,SMTP都將自己的標記加入反向路徑中。
  使用源路徑時,接收SMTP接收轉發的郵件併發送到另一接收SMTP伺服器上。接收伺服器可以接受或拒絕轉發本地使用者的郵件。接收SMTP通過將它自己的標記從轉發路徑移至回覆路徑的開始處來改變命令引數。這時,接收SMTP變成了傳送SMTP,也就建立了到下一個轉發路徑中SMTP的通道,然後,它向這個SMTP傳送郵件。
  在回覆路徑上的頭一個主機應是傳送SMTP命令的主機,在轉發路徑上第一個主機應是接收SMTP命令的主機。
  注意:轉發路徑和回覆路徑出現在SMTP命令和應答中,但不一定要出現在資訊中。也就是說,沒有必須要這樣的路徑特別這種格式出現在資訊頭的"To:","From:"和"CC:"等域中。
   如果SMTP伺服器接受了轉發任務,但後來它發現因為轉發路徑不正確或者其它原理無法傳送郵件,它必須建立一"undeliverablemail"訊號,將它此訊號送到此信的發主者那裡。
  此訊號必須是從此主機的SMTP服務上發出的,當然了,此伺服器不應該再報告出錯資訊的錯誤。一種阻止這種出錯報告迴圈的情況是在訊號的郵件命令的回覆路徑上置空。在傳送此資訊時,允許將回復路徑也置為空。一個MAIL命令後的回覆路徑為空表現為如下形式:
  MAILFROM:<>

  下例中顯示了不可傳送的郵件資訊。此資訊是對從HOSTW上的JOE發出的郵件經過在HOSTX需要經過HOSTZ到達HOSTY時出錯的迴應。我們看到的例子是在HOSTX和HOSTY之間發生的。

  不可傳送郵件資訊的例子
  S:MAILFROM:<>
  R:250ok
  S:RCPTTO:<@HOSTX.ARPA:[email protected]>
  R:250ok
  S:DATA
  R:354sendthemaildata,endwith.
  S:Date:23Oct8111:22:33
  S:From:[email protected]
  S:To:[email protected]
  S:Subject:MailSystemProblem
  S:
  S:SorryJOE,[email protected]
  S:HOSTZ.ARPAsaidthis:
  S:"550NoSuchUser"
  S:.
  R:250ok
3.7.域
  域是最近被引入ARPAInternet郵件系統的。使用域可以使地址空間從一個平面的普通字串主機名變成全域性地址的一個層次結構。主機由一個域名取代,起始主機是由一系列元串組成,它們由逗號按最特殊到一般的順序排列。
  例如,"USC-ISIF.ARPA","Fred.Cambridge.UK"和"PC7.LCS.MIT.ARPA"可能是主機-域識別符號。
  無論域名在SMTP中如何使用,只有正式的名稱才可以被使用,不可以使用假名或暱稱。
3.8.改變角色
  TURN命令可以用來改變在傳輸通道上通訊的程式的角色。如果程式A現在是傳送SMTP,它傳送TURN命令並接到OK應答(250)後,它就變為接收SMTP了。同理,程式B也可以從接收SMTP變為傳送SMTP。若要拒絕改變角色,接收方可以傳送502作為應答。
  注意:此命令是可選的。在使用TCP的傳輸通道時,一般不使用此命令。然而,當建立傳輸通道的代價比較大時,此命令很有用。例如,此命令可以支援一般公共交換電話系統作為傳輸通道。
4.SMTP說明
4.1.SMTP命令
4.1.1.命令語法
  SMTP命令定義了郵件傳輸或由使用者定義的系統功能。它的命令是由<CRLF>結束的字串。而在帶有引數的情況下,命令本身由<SP>和引數分開,如果未帶引數可以直接和<CRLF>連線。郵箱的語法格式必須和接收站點的格式一致。下面討論SMTP命令和應答。
  傳送郵件操作涉及到不同的資料物件,它們由不同的引數相互連線。回覆路徑就是MAIL命令的引數,而轉發路徑則是RCPT命令的引數,郵件日期是DATA命令的引數。這些引數或者資料物件必須跟在命令後。這種模式也就要求有不同的緩衝區來儲存這些物件,也就是說,有一個回覆路徑緩衝區,一個轉發路徑緩衝區,一個郵件內容緩衝區。特定的命令產生自己的緩衝區,或使一個或多個緩衝的內容被清除。
  HELLO(HELO)
  此命令用於向接收SMTP確認傳送SMTP。引數域包括髮送SMTP的主機名。接收SMTP通過連線確認命令來向傳送SMTP確認接收SMTP。引命令和OK響應確認傳送和接收SMTP進入了初始狀態,也就是說,沒有操作正在執行,所有狀態表和緩衝區已經被子清除。
  MAIL(MAIL)
  此命令用於開始將郵件傳送到一個多個郵箱中。引數域包括回覆路徑。返回路徑中包括了可選的主機和傳送者郵箱列表。當有主機列表時,它是一個回覆路徑源,它說明此郵箱是由在表中的主機一一傳遞傳送(第一個主機是最後一個接收到此郵件的主機)過來的。此表也有作向傳送者返回非傳遞訊號的源路徑。因為每個傳遞主機地址都被加在此表起始處,它就必須使用傳送IPCE而不是接收IPCE(如果它們不是一個IPCE的話)清楚的名稱。一些出錯資訊的回覆路徑可能就是空的。
  此命令清除回覆路徑緩衝區,轉發路徑緩衝區和郵件內容緩衝區,並且將此命令的回覆路徑資訊插入到回覆路徑緩衝區中。
  RECIPIENT(RCPT)
  此命令用於確定郵件內容的唯一接收者;多個接收者將由多個此命令指定。轉發路徑中包括一個可選的主機和一個必須的目的郵箱。當出現主機列表時,這就是一個源路徑,它指明郵件必須向列表中的上一個主機發送。如果接收SMTP未實現郵件的傳遞傳送,就會返回如未知本地使用者(550)的資訊給使用者。
  當郵件被傳遞傳送時,傳遞主機必須將自己的名稱由轉發路徑的開始處移至回覆路徑的結束處。當郵件最終到達目的地時,接收SMTP將以它的主機郵件格式自己的名稱插入目標郵件中。例如,由傳遞主機A接收的帶有如下引數的郵件時,
  FROM:<[email protected]>
  TO:<@HOSTA.ARPA,@HOSTB.ARPA:[email protected]>
  將會變成如下形式:
  FROM:<@HOSTA.ARPA:[email protected]>
  TO:<@HOSTB.ARPA:[email protected]>.
  此命令導致它的轉發路徑引數加入轉發路徑緩衝區中。
  DATA(DATA)
  接收者將跟在命令後的行作為郵件內容。此命令導致此命令後的