Email協議
SMTP協議:
1 信件體:在RFC822中,是一系列的文本行
2 信頭: 結構較複雜,總的來說是由一些欄位組成,這些欄位為使用者和程式提供了關於信件的資訊,瞭解信頭就是弄清楚信頭的各個欄位。每個信頭欄位由一行或多行組成,對於跨多行的欄位,附加行以一個空格開始作為續行。
Field-name(欄位名)由一系列可以列印的US-ASCII字元組成,除空格和":"外,大多數欄位名稱由一系列字母,數字,中間經常插入橫線符。
步驟:
1 用戶端程式發送郵件到SMTP伺服器
2 SMTP伺服器傳遞郵件到pop3接受伺服器
3 接受郵件用戶端從pop3上接受
(MPTP簡易郵件傳輸通訊協定,POP3郵局協議)
標準欄位:
1 from:表述產生這個信件的人,通常含有一個信箱(From:XX@CC.com)
2 sender:用於指示信件寄件者與信件建立者是否不同(From:XXX@CC.net and Sender:XXX@CC.net) 並不一 樣
3 Reply-To:用於控制信件要回複的目的地
4 To:信件的主要收信人
5 Cc:信件的輔收信人
6 Bcc:密件副本的縮寫
7 Message-IDL用於一個信件的唯一標誌,有SMTP伺服器產生
8 Date含有電子郵件的建立日期和時間
9 Received:為信件的一個特定的郵件投遞伺服器記錄
10重發欄位(Resent-*)
11Subject用於描述信件的主題
12Comments用於吧一個注釋添加到信件中
13擴充欄位..(X-Loop ,X-Mailer)
MIME對信頭欄位的擴充
MIME 對RFC822的欄位補充了一些信頭欄位,這些欄位通常是在寄送電子郵件的軟體在建立電子郵件時產生的,接受電子郵件的軟體提取其中的欄位得到有用的資訊
MIME補充的信頭欄位:
MIME-Version欄位用於標誌使用的MIME版本號碼,這是為了將來增加版本號碼解決相容的問題。該欄位是MIME信件唯一必須要求出現的欄位。
目前只有一個MIME版本在使用,一般加入一下欄位:
MIME-Version: 1.0
Content-Type是MIME中的主要欄位,描述特定MIME實體中包含的資料。
這個欄位有3部分:前兩部分組成媒體類型和1個可選分號分開的參數列表。如:
Content-Type:text/plain;charset="us-ascii"
其中text是媒體類型主類別,plain指媒體類型的附加層次類別。charset="us-ascii"是可選的參數列表。又如: Content-Type:text/html;charset=gb2312
指定媒體的主類型是text,但常值內容是HTML格式檔案。使用字元集是GB2312。
Content-Transfer-Encoding,許多資料格式可以包含在信件中允許的字元範圍之外的位元組值,而且含有超過允許長度的資料行。一些資料格式的定義甚至沒有行的概念。Content-Transfer-Encoding欄位解決這些問題.
該欄位有5個值:7bit,8bit,binary,base64和quoted-printable.每個值都不區分大小寫。符合MIME規範的郵件處理常式必須能對這些編碼正確處理
(1)7bit特點:
編碼長度不超過998位元組的資料,且該資料以Crlf結束的行組成 .為預設編碼,如果不提供Content-Transfer-Encoding欄位,就認為是7bit編碼
(2)8bit特點:
與7bit一樣但允許US-ASCII 0
(3)binary編碼用於任意二進位8位元據,對行長度和允許的字元沒有限制。在MIME信件實體裡包含這種資料是不合法的,它僅僅是告訴指定資料的資料類型,而資料不是給隨郵件作為郵件內容發送的。
(4)base64特點:
把位元據編碼成適合通過internet傳送的格式,在處理位元據作為郵件實體內容發送時,這種編碼方式應用的最為廣泛
在base64編碼過程中要注意:
1:編碼後的文本每行的長度:郵件的文本行每行應該控制在76個字元以內,如果超過需插入Crlf(斷行符號換行)。插入的Crlf不需要編碼
2填充字元
(1)quoted-printable編碼有文本組成的資料,在行超過80個字元的情況下很有用
(2)x-uuencode 常用在MIME實體中進行標誌
5 MIME 媒體類型
Connect-Type是用於在信頭中指定媒體類型的欄位,是MIME對RFC822擴充的主要信頭欄位
Connect-Type: 媒體類型主類別/媒體類型的附加層次類別+有可選分號分開的參數列表。
一共有8個頂層的媒體類型:Text,Image,Audio,Video,Application,Message和Multipart.這些主要類型為他們各自的資料提供了一個結構
(1)Text
Text類型用於指示基於文本的內容。這裡類別中任何子類型都不需要程式格式化資料而進行約定。參數有charset,用於指定Text所使用的字元集,預設時為US-ASCII.如:
Content-Type:text/plain;charset=us-ascii與Content-Type:text/plain是一樣的
Text的附加層次媒體類型還有:Plain, Enrich,Html等
1 TEXT:
text/plain 媒體類型標識有普通可列印字元組成,可以是US-ASCII,也可以是漢字,這些資料沒有經過格式化,直接瀏覽閱讀即可.
text/enrich 為建立有對齊,顏色和字型變化功能的文本提供了一個簡單的標記語言。
text/Html
2 Image,Audio和Video
這幾個媒體的主要類別是相當直觀的,資料通常是二進位的,採用base64編碼
Content-Type:Image/jpeg
Content-Transfer-Encoding:base64
3 Application: 該媒體類別含有與特定應用檔案格式有關的任何媒體類型。
幾種附加層次類別:
octet-stream ,Content-Type:Application/actet-stream
Application/actet-stream指示一個實體中含有任意資料,當內容未知或者對資料沒有定義媒體類型時,通常使用它
Postscript ,Content-Type:Application/Postscript
Application/Postscript媒體類型用於標識一個實體的內容是Postscript代碼。因為 Application/Postscript實體含有可執行代碼,他的內容必須毫無損失的到達目的地,也許是這個原因,通常使用quoted-printable編碼,是他不至於因為長度限制或在通過Internet網關時被破壞
Message 這個媒體類型的主類別指定信體組成的實體
RFC822,Content-Type:message/RFC822
message/RFC822類型提供在一個信件中打包另外一個信件的簡單方法。所有符合MIME的郵件處理常式都必須支援這種類型的分析
Partial,Content-Type:message/Partial
message/Partial媒體類型指定了一種方法,該方法把大的實體分成多個組件,每個組件可以分開傳輸在接受端組裝,在發送和傳輸郵件的伺服器之間有信件尺寸限制的情況下,這種方法可以傳送比較大的信件
External-body,content-type:message/External-body
message/External-body表示實體含有的資料並不在信件內容裡,而僅僅是描述了一種從外部取出資料的方式。
Multipart,Content-Type:mulipart/mixed
Multipart媒體類型的主類別表示多個實體打包到單個實體,多組件實體由一個可選的前置,一個或多個信件體組件(每個前面有一個邊界行)和一個可選的結尾組件組成。邊界行由兩個橫線後跟一個邊界字串組成。這個邊界字串由Content-Type欄位中的參數boundary的值指定
SMTP會話:
特點:
1 全過程發送文本完成,互動式請求接聽模式
2 命令是文本形式的命令
3 伺服器總返回一定的相應碼,表示用戶端的請求是否被正確的回答
4 會話過程有一定的順序
補充:
1 Email通訊是基於TCP/IP協議,要首先用WinSock建立和SMTP伺服器的串連
2 串連成功後,要進行會話,SMTP有其認識的一整套命令,當然是事先約定好的,SMTP協議的很重要的一 部分就是會話的標準命令
3 不過駭心命令不多,甚至幾個就能完成會話
一個簡單的會話 例子:
1:AfxSocketInit(NULL)
2:m_Socket.Create()
3:m_Socket.Connect(LPCSTR(temp),25)
4:virtual void OnReceive(int nErrorCode);等待伺服器回應接受m_Socket.Receive(sBuffer,sizeof (sBuffer));
5:發送m_Socket.Send("HELO smtp.sohu.com/r/n" ,len ) 返回4
6:發送m_Socket.Send("MAIL FROM: mmnihao_@sohu.com/r/n" ,len ) 返回4
7:發送m_Socket.Send("RCPT TO: mmnihao_@sohu.com/r/n" ,len ) 返回4
8:發送m_Socket.Send("DATA/r/n" ,len ) 返回4
9:發送m_Socket.Send("text/r/n/r/n./r/n" ,len ) 返回4 (注意".")
9:發送m_Socket.Send("QUIT/r/n" ,len ) 返回4
10 結束
程式:
1定義一個CESocket類 繼承於CSocket負責相應接受資料訊息,CESocket初始化Init
m_iCount 是一個命令發送的序號
//初始話
void CESocket::Init(CEmailSendDlg *dlg)
{
m_dlg=dlg;
m_iCount=0;
}
CESocket接受資料相應函數OnReceive,調用主對話方塊的接受訊息處理函數,同時增加m_iCount
//接受資料響應函數,調用主對話方塊的接受訊息處理函數,同時增加m_iCount
void CESocket::OnReceive(int nErrorCode)
{
m_dlg->ReceiveMessage(m_iCount);
m_iCount++;
CSocket::OnReceive(nErrorCode);
}
2:對話方塊的訊息處理函數:
void CEmailSendDlg::OnSend()
{
GetDlgItemText(IDC_SMTP_ADDRESS, m_sSendString[0]);
GetDlgItemText(IDC_FROM_ADDRESS, m_sSendString[1]);
GetDlgItemText(IDC_TO_ADDRESS, m_sSendString[2]);
m_sSendString[0].TrimLeft(" ");
m_sSendString[0].TrimRight(" ");
m_sSendString[1].TrimLeft(" ");
m_sSendString[1].TrimRight(" ");
m_sSendString[2].TrimLeft(" ");
m_sSendString[2].TrimRight(" ");
if(m_sSendString[0].IsEmpty())
{
AfxMessageBox("請輸入SMTP伺服器位址(IP)");
return;
}
if(m_sSendString[1].IsEmpty())
{
AfxMessageBox("請輸入你的EMail地址");
return;
}
if(m_sSendString[2].IsEmpty())
{
AfxMessageBox("請輸入收件者的EMail地址");
return;
}
m_sSendString[0]="HELO "+m_sSendString[0]+"/r/n";
m_sSendString[1]="MAIL FROM: "+m_sSendString[1]+"/r/n";
m_sSendString[2]="RCPT TO: "+m_sSendString[2]+"/r/n";
m_sSendString[3]="DATA/r/n";
GetDlgItemText(IDC_EMAIL_CONTENT,m_sSendString[4]);
m_sSendString[4]=m_sSendString[4]+"/r/n/r/n./r/n";
m_sSendString[5]="QUIT/r/n";
CString temp;
GetDlgItemText(IDC_SMTP_ADDRESS,temp);
if(m_Socket.Connect(LPCSTR(temp),25)==FALSE)
{
}
m_sReceivedData="";
}
當用戶端串連大SMTP伺服器後,smtp會發送一段歡迎碼然後用戶端和伺服器就可以按照SMTP命令進行會話
直到信件發送結束
void CEmailSendDlg::ReceiveMessage(int count)
{
if(count>=6)
{
AfxMessageBox("Unknown Received Data");
m_Socket.Close();
return;
}
char sBuffer[255];
int len=m_Socket.Receive(sBuffer,sizeof(sBuffer));
sBuffer[len]=NULL;
m_sReceivedData=m_sReceivedData+sBuffer;
m_sReceivedData=m_sReceivedData+m_sSendString[count];
m_Socket.Send(m_sSendString[count],m_sSendString[count].GetLength());
}
//----------------------------------------------
如何擷取從發信伺服器到網易MX伺服器的SMTP會話範例?字型: 小 中 大
利用telnet手工類比一次smtp會話過程,能提供許多有用的資訊,從而協助我們迅速定位您的問題。下面這個手工smtp會話測試過程可以在多個作業系統下運行,包括Windows、Unix、和Linux。
本協助講述了如果利用telnet來類比一次完整的發信。請將您的整個會話過程複製下來,並發送給我們。
2nn開頭的返回碼,表示會話是正常的。而5nn或者4nn開頭的返回碼則表示有錯誤發生。
注意:本測試過程必須在發信伺服器上進行。
下面是具體步驟:
1、開啟一個命令視窗,鍵入:
telnet mx.mail.126.split.netease.com 25
這條命令將建立一個到我們126郵件伺服器的串連。
2、 鍵入:
HELO yourdomain.com
這裡的yourdomain.com指您的網域名稱。
3、 鍵入:
MAIL FROM:< you@yourdomain.com >(無需空格)
這裡的you@yourdomain.com指您們域的一個郵箱名。
注意:郵箱名需要用<>括起來。
4: 鍵入:
RCPT TO:< postmaster >(無需空格)
這將發信到我們的postmaster郵箱。
注意:郵箱名需要用<>括起來。
5: 鍵入:
DATA
6: 輸入郵件的信頭和本文。
FROM:< you@yourdomain.com>(無需空格)
TO:< postmaster>(無需空格)
SUBJECT: yourdomain.com to netease
Hi!
It's from yourdomain.com. Just a test.
Bye.
7: 新起一個空行,鍵入:
.
然後按斷行符號,這將結束整封信,並發送給伺服器