Delphi讓你發送Flash電子郵件 |
|
jackkcg
站務副站長 發表:891 回覆:1050 積分:848 註冊:2002-03-23 發送簡訊給我 |
此為轉貼資料
http://www.pconline.com.cn/ Delphi讓你發送Flash電子郵件 無論Outlook XP還是最新的Foxmail 4.0,都只能在HTML格式的電子郵件中嵌入JPG、GIF格式圖片,而音色俱佳的Flash動畫卻只能作爲電子郵件附件發送給好友,你可曾感到遺憾? 經過一番實驗探索,我使用Delphi終於實現了將Flash動畫(.SWF格式)嵌入到電子郵件正文中發送的功能,Foxmail、Outlook均可以按照HTML格式的郵件查看,而且263、163等免費電子郵件還支援Web介面直接瀏覽。可惜的是,Sina、Sohu免費電子郵件的Web介面則不支援,只能將Flash動畫作爲附件提供。 一、程式原理 下面對本程式相關的重要理論知識做些解釋,幫助大家理解本程式的原理。更多的內容,限於文章篇幅,請參見相關的參考書、幫助文件。 1.TNMSMTP控制項 電子郵件發送過程都必須遵循SMTP協定。用戶端和伺服器通過該協定進行通信,由用戶端發送出電子郵件,SMTP伺服器通過網路上其他SMTP伺服器,最終將郵件傳遞到收信人的郵件伺服器。本程式作爲電子郵件用戶端程式,最基本的功能是要實現電子郵件發送,爲了簡化編程,使用了Delphi 5自帶的TNMSMTP控制項,該控制項封裝了對SMTP編程。由於該控制項繼承自TPowersock,因而必要時可以直接調用底層的Socket過程,又不失靈活性。 例如,雖然TNMSMTP不直接支援“SMTP伺服器認證功能”(請參考《電腦愛好者》2001年16期《製作支援“伺服器認證”的VB電子郵件程式》,包括下文“BASE64編碼”),但是,可以利用TNMSMTP的Connect事件和繼承自TPowersock的Transaction方法,實現SMTP伺服器認證。其原理在於,Connect事件發生在TNMSMTP與伺服器連接成功之時,此時,使用Transaction方法發出SMTP伺服器認證所規定的“AUTH LOGIN”命令,並輸入經過BASE64編碼後的用戶名和密碼,可以實現認證。因此,本程式實現了SMTP伺服器認證。 另外,TNMSMTP的SendStart事件在郵件發送開始時觸發,在該事件中,可以通過修改TNMSMTP的FinalHeader屬性值,實現修改電子郵件的郵件頭資訊。在本程式中需要修改郵件頭的Content-Type屬性,使接收嵌入Flash動畫電子郵件的用戶端軟體(如Foxmail)能正確處理郵件內容。 2.MIME協定 目前,幾乎所有的郵件伺服器和用戶端軟體都支援“多用途Internet郵件擴展”協定Multipurpose Internet Mail Extensions (MIME)。該協定的最新版由RFC2045(Internet消息體格式)、RFC2046(媒體類型)、RFC2047(無ASCII文本消息頭擴展)、RFC2048(註冊過程)、RFC2049(一致性標準和例子)等共同規定。該協定遵循了RFC822中規定的電子郵件內容只能包括簡單的ASCII文本字元(如字母、數位元、標點符號等),定義了在電子郵件中包括經過編碼的二進位文件的方法,編碼後的內容將只包括文本字元。目前,實現對二進位文件編碼的規範有很多,BASE64編碼規範也是其中之一。本程式使用TMemoryStream物件,實現了通用的BASE64編碼函數EncodeBASE64,能夠對SWF文件進行編碼。 通過MIME協定,電子郵件中不但可以添加附件,還可以添加HTML格式內容,包括圖片、聲音、動畫等。Outlook、Foxmail 4.0等軟體都可以編輯HTML格式的郵件,但是並不支援直接嵌入Flash動畫。事實上,正確利用MIME協定,可以在HTML格式的郵件中嵌入Flash動畫,並在郵件正文中顯示出來,其原理和在HTML格式郵件中顯示圖片、播放聲音是一樣的。在HTML格式郵件中嵌入Flash動畫與向網頁中添加動畫所需要的代碼是一樣的,同樣使用< OBJECT >、< EMBED >標記,感興趣的朋友可以查看一個包含Flash動畫的網頁源代碼,對比本程式。 在本程式中,設置郵件MIME消息頭的Content-Type屬性爲multipart/related; boundary="---SwfEmail by JDH",表示該郵件包括多個不同資料類型的部分,各個部分之間用"---SwfEmail by JDH"(不包括引號)區分。在郵件內容的這些部分中,根據每部分的內容不同,再爲其添加相應的MIME消息頭,具體可參見程式源代碼。
二、編程實戰 啓動Delphi 5,參考圖1在Form1上創建各種控制項。圖中黑色方框內標明了控制項名稱,其中txt字首表示TEdit控制項,mem字首表示TMemo控制項,chk字首表示TCheckbox控制項,btn字首表示TButton控制項,NMSMTP1是TNMSMTP控制項,OpenDialog1是TOpenDialog控制項。圖2列出了一部分控制項的某些關鍵屬性。現在添加代碼如下:{******Unit1.pas源代碼內容如下******}unit Unit1;interfaceusesWindows, Messages, SysUtils, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ExtCtrls, Psock, NMsmtp;typeTForm1 = class(TForm)Label1: TLabel;txtTo: TEdit;Label2: TLabel;txtFrom: TEdit;Label3: TLabel;txtSubject: TEdit;Label4: TLabel;memContents: TMemo;Label5: TLabel;txtUserName: TEdit;Label6: TLabel;txtPassword: TEdit;chkSmtpVerify: TCheckBox;btnSend: TButton;btnOpen: TButton;txtSwfFile: TEdit;Label7: TLabel;OpenDialog1: TOpenDialog;Label8: TLabel;txtSmtpServer: TEdit;NMSMTP1: TNMSMTP;Label9: TLabel;txtPort: TEdit;procedure btnOpenClick(Sender: TObject);procedure btnSendClick(Sender: TObject);procedure NMSMTP1SendStart(Sender: TObject);procedure NMSMTP1Connect(Sender: TObject);procedure chkSmtpVerifyClick(Sender: TObject);private{ Private declarations }public{ Public declarations }end;
var Form1: TForm1; function EncodeString(Decoded:string):String; function EncodeBASE64(Encoded: TMemoryStream {TMailText}; Decoded: TMemoryStream):
Integer; //編碼函數 implementation {$R *.dfm} {對參數TMemoryStrema中的位元組流進行Base64編碼,編碼後的結果 保存在Encoded中,函數返回編碼長度} function EncodeBASE64(Encoded: TMemoryStream ; Decoded: TMemoryStream): Integer; const _Code64: String[64] = ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /'); var I: LongInt; B: array[0..2279] of Byte; J, K, L, M, Quads: Integer; Stream: string[76]; EncLine: String; begin Encoded.Clear; Stream := ''; Quads := 0; {爲提高效率,每2280位元組流爲一組進行編碼} J := Decoded.Size div 2280; Decoded.Position := 0; {對前J*2280個位元組流進行編碼} for I := 1 to J do begin Decoded.Read(B, 2280); for M := 0 to 39 do begin for K := 0 to 18 do begin L:= 57*M 3*K; Stream[Quads 1] := _Code64[(B[L] div 4) 1]; Stream[Quads 2] := _Code64[(B[L] mod 4)*16 (B[L 1] div 16) 1]; Stream[Quads 3] := _Code64[(B[L 1] mod 16)*4 (B[L 2] div 64) 1]; Stream[Quads 4] := _Code64[B[L 2] mod 64 1]; Inc(Quads, 4); if Quads = 76 then begin Stream[0] := #76; EncLine := Stream #13#10; Encoded.Write(EncLine[1], Length(EncLine)); Quads := 0; end; end; end; end; {對以2280爲模的餘數位元組流進行編碼} J := (Decoded.Size mod 2280) div 3; for I := 1 to J do begin Decoded.Read(B, 3); Stream[Quads 1] := _Code64[(B[0] div 4) 1]; Stream[Quads 2] := _Code64[(B[0] mod 4)*16 (B[1] div 16) 1]; Stream[Quads 3] := _Code64[(B[1] mod 16)*4 (B[2] div 64) 1]; Stream[Quads 4] := _Code64[B[2] mod 64 1]; Inc(Quads, 4); {每行76個字元} if Quads = 76 then begin Stream[0] := #76; EncLine := Stream #13#10; Encoded.Write(EncLine[1], Length(EncLine)); Quads := 0; end; end; {“=”補位} if (Decoded.Size mod 3) = 2 then begin Decoded.Read(B, 2); Stream[Quads 1] := _Code64[(B[0] div 4) 1]; Stream[Quads 2] := _Code64[(B[0] mod 4)*16 (B[1] div 16) 1]; Stream[Quads 3] := _Code64[(B[1] mod 16)*4 1]; Stream[Quads 4] := '='; Inc(Quads, 4); end; if (Decoded.Size mod 3) = 1 then begin Decoded.Read(B, 1); Stream[Quads 1] := _Code64[(B[0] div 4) 1]; Stream[Quads 2] := _Code64[(B[0] mod 4)*16 1]; Stream[Quads 3] := '='; Stream[Quads 4] := '='; Inc(Quads, 4); end; Stream[0] := Chr(Quads); if Quads > 0 then begin EncLine := Stream #13#10; Encoded.Write(EncLine[1], Length(EncLine)); end; Result := Encoded.Size; end;
對參數Decoded字串進行Base64編碼,返回編碼後的字串} function EncodeString(Decoded:string):String; var mmTemp,mmDecoded:TMemoryStream; strTemp:TStrings; begin mmTemp := TMemoryStream.Create; mmDecoded:=TMemoryStream.Create; strTemp:=TStringList.Create; strTemp.Add(Decoded); strTemp.SaveToStream(mmTemp); mmTemp.Position := 0; {剔除mmTemp從strTemp中帶來的字元#13#10} mmDecoded.CopyFrom(mmTemp,mmTemp.Size-2); {對mmDecoded進行Base64編碼,由mmTemp返回編碼後的結果} EncodeBASE64(mmTemp,mmDecoded); {獲得Base64編碼後的字串} mmTemp.Position:=0; strTemp.LoadFromStream(mmTemp); {返回結果必須從strTemp[0]中獲得,如果使用strTemp.Text會 帶來不必要的字元#13#10} Result:=strTemp[0]; end; procedure TForm1.btnOpenClick(Sender: TObject); begin {打開對話方塊,選擇SWF文件} if OpenDialog1.Execute then begin end; end; procedure TForm1.btnSendClick(Sender: TObject); var mmSwfFile,mmEncoded:TMemoryStream; iResult:Integer; strsTemp:TStrings; strContents:TStringList; i:Integer; begin {驗證用戶輸入資訊} if txtTo.Text='' then begin ShowMessage('請輸入收信人!'); Exit; end; if txtFrom.Text='' then begin ShowMessage('請輸入發信人!'); Exit; end; if txtSmtpServer.Text='' then begin ShowMessage('請輸入SMTP伺服器!'); Exit; end; if txtPort.Text='' then begin ShowMessage('請輸入埠號!'); Exit; end; if txtSwfFile.Text='' then begin ShowMessage('請選擇SWF文件!'); Exit; end; {檢驗伺服器認證的用戶名和密碼} if chkSmtpVerify.Checked = True then if (txtUserName.Text='') or (txtPassword.Text='') then begin ShowMessage('您已選擇SMTP伺服器需要認證' #13#10 '請輸入用戶名和密碼!'); Exit; end; {設置SMTP伺服器地址、埠} NMSMTP1.Host:=txtSmtpServer.Text; NMSMTP1.Port:=StrToInt(txtPort.Text); {斷開原來的連接,保證TForm1.NMSMTP1Connect中伺服器認證的執行} if NMSMTP1.Connected then begin NMSMTP1.Disconnect; end;
{連接伺服器} NMSMTP1.Connect; {創建流} mmSwfFile:=TMemoryStream.Create; mmEncoded:=TMemoryStream.Create; {載入文件至流mmSwfFile} mmSwfFile.LoadFromFile(txtSwfFile.Text); {對mmSwfFile進行Base64編碼,mmEncoded爲編碼後內容} iResult:=EncodeBASE64(mmEncoded,mmSwfFile); strsTemp:=TStringList.Create; mmEncoded.Position:=0; strsTemp.LoadFromStream(mmEncoded); {----生成郵件內容----} strContents:=TStringList.Create; strContents.Add('--------------SwfEmail by JDH'); strContents.Add('Content-Type: text/html; charset=gb2312'); strContents.Add('Content-Transfer-Encoding: 8bit'); {注意:空行是郵件格式所必需的!} strContents.Add(''); strContents.Add('< HTML>< HEAD>< TITLE>SWFEMAIL< /TITLE>< /HEAD>'); strContents.Add('< BODY>'); {添加郵件正文內容} for i:=0 to memContents.Lines.Count-1 do begin strContents.Add(memContents.Lines[i] '< br>'); end; {添加SWF文件相關內容} strContents.Add('< object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/
swflash.cab#version=5,0,0,0">'); strContents.Add('< param name=movie value="cid:jdh_swfemail@001">'); strContents.Add('< param name=quality value=high>'); strContents.Add('< embed src="cid:jdh_swfemail@001" quality=high
pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"
type="application/x-shockwave-flash" >'); strContents.Add('< /embed>< /object>< /BODY>< /HTML>'); strContents.Add(''); strContents.Add('--------------SwfEmail by JDH'); strContents.Add('Content-Type: image/swf'); strContents.Add('Content-ID: < jdh_swfemail@001>'); strContents.Add('Content-Transfer-Encoding: base64'); strContents.Add('Content-Disposition: inline; filename="' ExtractFileName(txtSwfFile.Text) '"'
); strContents.Add(''); strContents.Add(strsTemp.Text); strContents.Add(''); {----生成郵件內容結束----} {設置郵件發送資訊} NMSMTP1.PostMessage.FromAddress := txtFrom.Text; NMSMTP1.PostMessage.FromName := txtFrom.Text; NMSMTP1.PostMessage.ToAddress.Text := txtTo.Text; NMSMTP1.PostMessage.Body.Text := strContents.Text; NMSMTP1.PostMessage.Subject := txtSubject.Text; {發送電子郵件} NMSMTP1.SendMail; ShowMessage('郵件發送成功!'); end; procedure TForm1.NMSMTP1Connect(Sender: TObject); var strUserName,strPassword:string; begin {如果SMTP伺服器需要認證,則進行認證} if chkSmtpVerify.Checked = True then begin {對用戶名和密碼進行Base64編碼} strUserName:=EncodeString(txtUserName.Text); strPassword:=EncodeString(txtPassword.Text); {進行認證,輸入編碼後的用戶名、密碼} nmsmtp1.Transaction('auth login'); nmsmtp1.Transaction(strUserName); nmsmtp1.Transaction(strPassword); end; end; procedure TForm1.NMSMTP1SendStart(Sender: TObject); begin {在郵件發送開始時修改郵件的消息頭,標明郵件爲多部分組成} NMSMTP1.FinalHeader.Values['Content-Type'] := 'multipart/related;
boundary="------------SwfEmail
by JDH"'; end; procedure TForm1.chkSmtpVerifyClick(Sender: TObject); begin {根據是否需要SMTP伺服器認證,改變用戶名、密碼狀態} if chkSmtpVerify.Checked = True then begin txtUserName.Enabled := True; txtUserName.Color:= clWindow; txtPassword.Enabled := True; txtPassword.Color:= clWindow; end else begin txtUserName.Enabled := False; txtUserName.Color:= clSilver; txtPassword.Enabled := False; txtPassword.Color:= clSilver; end; end; end. 三、程式運行 首先在Delphi 5中編譯運行,接著在對話方塊中輸入收信人、發信人、主題、正文內容以及SMTP伺服器,比如填寫“smtp.263.net”,埠號使用默認的25,選中“SMTP伺服器需要認證”,並根據發信人輸入用戶名、密碼。單擊“打開文件”按鈕,選擇要發送的Flash動畫文件,確認無誤後,單擊“發送”按鈕即可。發送成功後,會出現發信成功。 *********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好 Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind to make knowledge together!
希望能大家敞開心胸,將知識寶庫結合一起
------
********************************************************** 哈哈&兵燹 最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好 Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知 K.表Knowlege 知識,就是本站的標語:Open our mind |
cutehsu
一般會員 發表:1 回覆:2 積分:0 註冊:2003-07-02 發送簡訊給我 |
|
Blueberrug
一般會員 發表:14 回覆:50 積分:17 註冊:2005-05-22 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |