//Logo Image
作者:鄭智銘(2005-02-01);推薦:吳昌暉、徐業良(2005-04-28)

PIC_SERVER教材(11)-以SMTP發送E-mail

PIC_SERVER的應用中,可能有由「事件驅動(event driven)」主動向外發訊的需求,例如偵測到異常狀況時主動向特定住址發送E-mail,本文即在介紹PIC_SERVERSMTP向遠端郵件伺服器發送E-mail的方式。

1.     E-mail信件寄送流程

E-mail的寄件流程其實與一般實體信件寄件流程相似,圖1所示為住在台北的某甲寄信給住在桃園的某乙的流程:

(1)   甲將信件封面的收件人姓名住址、寄件人的姓名住址等資訊寫好。

(2)   甲交給台北郵局。

(3)   台北郵局轉交給桃園郵局。

(4)   桃園郵局將信件交給乙方。

1. 一般實體信件寄件流程

2所示則為一般E-mail的寄件流程,使用者A欲寄E-mail給使用者B,與一般實體信件寄件流程不同的是,寄發E-mail時必須符合SMTP(Simple Mail Transfer Protocol)傳輸協定,而收件時必須使用POP3(Post Office Protocol version 3)傳輸協定。一般E-mail的寄件流程如下:

(1)   A使用者利用「郵件用戶代理(Mail User Agent, MUA)」,一般常見如Outlook等程式,將所欲寄送的E-mail以符合SMTP傳輸協定的方式撰寫並傳送。這道程序就像是實體信件寄送前,我們必須在信封上填寫“符合郵局規格”的收件人姓名地址、寄件人姓名地址的程序一樣。

(2)   A方的「郵件傳送代理(Mail Transfer Agent, MTA)」,也就是Mail Server的功能,就像實體信件的台北郵局一樣,負責接收A方的E-mail,並且轉送給桃園的郵局。

(3)   B方收件者利用POP3通訊協定,向BMail Server查詢是否有信件,若有信件則收取E-mail,就像到桃園郵局領取實體信件一般。

一般MTA也就是郵件伺服器,寄件者使用SMTP通訊協定時,為了方便使用者,通常不需要經過認證程序(有些會限制網域或IP),但是收件者使用POP3通訊協定收件時,則必須要認證的程序。可以使用Outlook程式試試看,只要寄件SMTP伺服器填寫正確,隨便填寫錯誤的POP3伺服器與帳號密碼,E-mail還是一樣可以寄送出去,就像實體信件寄件時投入郵筒便可,但是領件時則必須確認你是本人才行。

2. 一般E-mail寄件流程

使用PIC_SERVER寄發E-mail的流程如圖3所示,PIC_SERVER取代了寄件者的MUA以及MTA,直接將E-mail以符合SMTP通訊協定的方式傳送到收件者的MTA郵件伺服器,重點便是如何使用PIC_SERVER寄發E-mail信件,發送符合SMTP通訊協定的信件格式,並且成功地被收件者的MTA所接受。

3. 使用PIC_SERVER寄發E-mail的流程

2.     SMTP通訊協定

SMTP稱為「簡易郵件傳輸協定」,傳輸規則非常簡單,使用TCP協定以Port 25作為通訊管道,傳送ASCII碼的信件文字。圖4所示為SMTP通訊協定標準的流程,使用者與SMTP主機連線後會有來回5次的問答過程,如果使用者能依序回答出SMTP可以認可的答案,使用者的E-mail就會被收件者的伺服器接受。

4. SMTP通訊協定使用者與SMTP server的對話過程

如圖4,連接SMPT主機、看到連線成功的回應後,回答遠端SMTP server的答案順序為:HELO 來源è寄件者來源è收件者位置è信件內容è離開。要注意E-mail內容的最後一行,必須要以句點“.”作為整個E-mail的結束標記,隨後SMTP server回應“Mail accepted”,此時信件已經被寄出。

回答遠端SMTP server的答案中,HELO後面的來源,其實隨便填什麼對方SMTP都會查詢的到你的IP,以元智使用者登入msa.hinet.net為例,對方會回應“Hello [140.138.40.129], pleased to meet you”,刮號內為使用者的IP位置,表示對方SMTP知道使用者寄件所使用的電腦IP來源。“MAIL FROM:”後面的E-mail位置也可隨便填,只要有@通常都會被SMTP接受。

5為使用telnet方式登入元智SMTP server對談,並寄發E-mail給元智s919204收件者的實際使用情況,可以清楚看到SMTP實際運作的機制。圖5中藍色底線標示的為使用者所下的命令,其他為SMTP server所回應的文字,圖6為收件者信箱所收到的E-mail內容。郵件伺服器的IP可在「開始」功能表中執行“ping”指令查出,例如“ping msa.hinet.net”

5. 使用telnet連線SMTP server

6. 收件者所收到E-mail的內容

5輸入的內容為“最精簡”能使SMTP寄發信件的方式,一封標準的E-mail內容還應包含標題與寄件者等資訊,在上述與SMTP對談的流程中,E-mail前面加上下列文字,則會發送如圖7所示包含標題與寄件者等資訊之標準E-mail

TO: s919204@mail.yzu.edu.tw

Subject: This E-mail is sent from PIC_SERVER

(這邊要空一行)

7. 一封標準E-mail包含標題與收件者的內容

3.     PIC_SERVER使用SMTP通訊協定寄發E-mail

如上一節所述,要以PIC_SERVER發送E-mail,必須要符合SMTP的通訊協定,包括收件者的Mail serverIP、使用TCPport 25、以及正確與SMTP server對答的過程。PIC_SERVER要寄發E-mail必須要達到的幾項功能整理如下:

(1)   指定收件者SMTP server設定:包含收件者SMTP serverIP、通訊埠,詢問各遠端電腦的卡號,包括PIC_SERVERTCPUDP SERVER等。

(2)   E-mail功能性參數:包括重寄次數、E-mail各欄位長度。

(3)   符合SMTP格式的E-mail內容:包括寄件者來源、收件者位置、E-mail內容、E-mail結束句號。

(4)   監看TCP port 25所收到遠端SMTP的回應內容。

(5)   使用SMTP通訊協定:流程為HELO 來源è寄件者來源è收件者位置èE-mail內容è離開。

本節中以範例程式ex_9_send_email.c,逐一介紹前述以PIC_SERVER寄發E-mail必須達到的功能。寄發E-mailTCP client功能的應用,請複習PIC_SERVER教材(9)(10)與範例程式ex_8_tcp_client.c。範例程式ex_9_send_email.cex_8_tcp_client.c不同之處,就在於寫在程式庫pic_SERVER_email.c裡面的負責執行SMTP傳輸協定的doSMTPsendEmail(),使用者無須修改。

具體來說,由PIC_SERVER寄發E-mail需要完成三項工作:相關參數設定(3.1節)、視需要修改寫在副程式sendEmail_to_SMTPserver()裡面的信件內容(3.3節),並撰寫呼叫發信副程式sendEmail_to_SMTPserver()的事件觸發條件程序(如3.2節圖11裡面的鍵盤測試),詳述如下。

3.1 指定收件者SMTP serverE-mail功能性參數設定

藉由ICP程式設定遠端收件者的SMTP server,如欲寄給元智的師生,其收件者SMTP server140.138.36.11,通訊埠為port 25,設定方式如圖8所示。詢問各遠端電腦的卡號則由主程式中bios_InitARPtable()所執行。

8. ICP軟體設定遠端SMTP server位置與通訊埠

9為範例程式前端的各項宣告,包含監看SMTP對話除錯、重寄次數、E-mail各欄位長度等各項設定。其中啟動I_WANT_EMAIL後會指定TCPport 25作為SMTP的通訊埠;啟動DEBUG_MAIL後,可藉由RS-232使用終端機監看SMTP serverPIC_SERVER間的對話,萬一E-mail發送失敗,可以以藉此瞭解是傳送過程中的哪個對話內容有問題。

9. E-mail功能性參數設定

3.2 範例程式執行流程

10為範例程式程式碼。程式開始執行後,首先列印程式版本並在LCD上顯示PIC_SERVER IP,並以bios_InitARPtable()詢問遠端各電腦(包括PIC_SERVERTCPUDP SERVER等)的卡號,才有辦法寄送E-mail。隨後以disp_ARPtable()顯示各項資訊於終端機上,並設定E-mail內容各項資訊(副程式sendEmail_to_SMTPserver())

隨後在while迴圈中,不斷監看以下三項資訊:

(1)   此範例程式中PIC_SERVER發送E-mail的驅動事件為,是否有人以鍵盤輸入“m”,發生此驅動事件則開始執行E-mail發送程序。第一個動作就是呼叫sendEmail_to_SMTPserver(),設定E-mail信件內容於字串變數mail_data中(詳見3.3節的圖12)。

(2)   呼叫bios_EtherNetHandler(),查詢是否收到乙太網路訊息。若收到TCPserver寄來的訊息,就會自動呼叫回呼函數callback_TCPserverDataArrival(),若檢查得知遠端的TCPserver的發信窗口是SMTP_PORT(TCP port 25),即可確認是SMTP server傳來的答覆訊息,就呼叫doSMTPsendEmail()依照SMTP傳輸協定與SMTP server對談,最後將E-mail的本文(上一步驟中準備好的字串變數mail_data)用printf( nic_putc, “%s”, mail_data)的方式傳送出去。執行SMTP傳輸協定的副程式doSMTPsendEmail()寫在程式庫pic_SERVER_email.c裡面,使用者無須修改。

(3)   TCPE-mail發送次數是否超過限制(副程式doHouseKeeping()),超過限制便放棄。在pic_SERVER.h中可以看到TCP_TIMEOUT重送限制為10,而MAIL_TIMEOUT重送限制為20,也可以在圖9程式前端各項宣告中重新設定。

10. 主程式程式碼

3.3 副程式說明

11為副程式sendEmail_to_SMTPserver()程式碼。此副程式功能為設定E-mail信件內容,包含收發信人的帳號與郵件主機、E-mail主旨、E-mail本文等。注意圖12E-mail本文包括事件發生的時間和事件內容(類比輸入腳位之電壓值),用指令sprintf(mail_data, …)將各項內容寫入mail_data等字串變數,最後呼叫bios_ConnectRemoteHost()向遠端郵件伺服器請求連線。

如果要寫一封很長的信,就要用strcpy(temp_str, “something more to say,”); strcat(mail_data, temp_str); strcpy(temp_str, “Happy new year!”); strcat(mail_data, temp_str); …的方式擴增字串變數mail_data。注意CCS-C不能用strcat(mail_data, “something more …”)的方式,將常數字串擴增到字串變數mail_data後面,這是CCS-C與一般的C語言不同之處,請查閱CCS-C的線上輔助說明。

11. 副程式sendEmail_to_SMTPserver()程式碼

副程式doSMTPsendEmail()(圖12)位於在pic_SERVER_email.c中,其功能為依據遠端SMTP server回應內容,分別依據SMTP通訊協定順序,回答HELO localnetMAIL FROMRCPT TODATA等,傳送成功後QUIT結束。

副程式doHouseKeeping()(圖13)功能為控制TCPE-mail重發次數,其中呼叫的doTCPclientHouseKeeping()(圖14)位於pic_SERVER.c中,功能為控制TCPE-mail的重發次數。

12. 副程式doSMTPsendEmail()程式碼

13. 副程式doHouseKeeping()程式碼

14. 副程式doTCPclientHouseKeeping()程式碼

【實驗】

PIC_SERVER連接溫度感測器,以PIC_SERVER10分鐘發送一次E-mail給教授,連發10次,內容報告系統時間及當時溫度。若溫度超過攝氏40度,就發送E-mail給你自己,內容報告系統時間及當時溫度,並在課堂上展示此功能。