利用Indy 10的IdSMTP控件制作可帶附件的郵件發送器
作者:Tuuzed(土仔) 發表于:2008年7月29日
版權聲明:可以任意轉載,轉載時請務必以超鏈接形式標明文章原始出處和作者信息及本聲明。
http://m.shnenglu.com/tuuzed/archive/2008/07/29/57477.html
Indy10中的IdSMTP控件比BCB6中自帶的NMSMTP支持更多的SMTP命令(支持RFC 821,RFC 1869 ,RFC 2197 ,RFC 2554),像國內的網易、TOM、21CN等的SMTP都需要EHLO命令先進行認證才可使用。但是,目前很多大型的郵件服務商出于預防垃圾郵件的考慮,已經開始取消或限制SMTP發信了,改為提供WebMail服務,因此可用的SMTP服務器是少之又少了。有人說現在做SMTP郵件發送器意義已經不大,可我認為,動手去做這個SMTP發送器可以更好的了解一封電子郵件的結構和它的產生過程,管他別人愛說啥!
【郵件大致結構】
先用DreamMail發一封測試信:由TestID@163.com發信給TestID2@21cn.com,其中掛載附件1.txt。信件從21CN收回來之后是這樣子的:
//服務器自動添加的東西2
HMM_SOURCE_IP:10.27.2.7:55493.20270997183
HMM_ATTACHE_NUM:00014
HMM_SOURCE_TYPE:SMTP5
Received: from aisp7-mta?dg (dgproxy7.inner-hermes.com [10.27.2.7])6
by 21cn.com (HERMES) with SMTP id 359B63813A7
for <TestID2@21cn.com>; Tue, 29 Jul 2008 22:20:12 +0800 (CST)8

9
Received: from m12-11.163.com([220.181.12.11])10
by aisp7-mta@dg(Knowledge-based Antispam Gateway 2.126n5(2008-07-01),59.36.102.56) with ESMTP id 11

12
mx23749.1217341212 for <TestID2@21cn.com>;13
Tue, 11 Jul 2008 22:20:13 +000014

15
X-Original-MailFrom: TestID@163.com16
Received: from ChinaPC (unknown [58.145.147.196])17
by smtp7 (Coremail) with SMTP id C8CowLCrpS8XJ49IDQBdEQ==.5964S2;18
Tue, 11 Jul 2008 22:20:07 +0800 (CST)
//大都是我們自己填寫的東西2
//回復地址3
Reply-To: TestID@163.com4

5
From: "TestID" <TestID@163.com>6
To: "TestID2" <TestID2@21cn.com>7
Subject: Test Attachment8
Date: Tue, 29 Jul 2008 22:31:07 +08009
//Dreammail的識別ID10
Message-Id: <DreamMail__223107_76081071266@smtp.163.com>11
MIME-Version: 1.012
//內容類型及內容“指針ID”13
Content-Type: multipart/mixed; 14
boundary="----=_NextPart_08072922310693970267282_000"15
//郵件優先級16
X-Priority: 317
//客戶端名稱18
X-Mailer: DreamMail 4.4.1.019
X-Coremail-Antispam: 1Uf129KBjDUn29KB7ZKAUJUUUUUYxn0WfASr-VFAUDa7-sFnT20
9fnUUIcSsGvfJTRUUUj_xYjsxI4VWUJwAYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1I0E4x8021
FVCIwcAKzIAtM7C26IkvcIIF6IxKo4kEV4yl1IIY67AEw4v_Jr0_Jr4le4C267I2x7xF5422
xIwI1l52xGzVA2a4k0FcxF6cIjj282cryl52xGzVA2a4k0FcxF6xCjrcI26cIUMc02F40E23
57IF67AEF4xIwI1lYx0E2Ix0cI8IcVAFwI0_Jrv_JF1lYx0Ex4A2jsIE14v26r1j6r4UM424
xvF2IEb7IF0Fy264kE64k0F24lFcxC0VAYjxAxZF0Ex2IqxwAC62BYpTIE1TZKA3svLVAK25
vSnIqfZI6r4lFVCF04k20xvEw2I207IF0wAKzVCY07xG64k0F24l7I0Y6sxI4wCY1Ik26c26
xK620vw7xCY7Wlc7Ca8VAvwVCjb41lc7Ca8VAvwVCFzxkY4VA2I41lc2xSY4AK67AK6ry527
MxkI7II2jI8vz4v_Jr0_Jryl4x8a6c8ajcxJMI8E67AF67kF1VAFwI0_Jr0_JrylIxAIcV28
C0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Jr0_Gr1lIxAIcVC229
z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVWUJVW8JbIYCTnIWIevJa73Uj30
IFyTuYvjxUgg4SUUUUU31
//ESet病毒防火墻添加32
X-EsetId: 2080B02B6D6871693F86B07B643E31
//內容開始了,對應上面說的“指針ID”2
------=_NextPart_08072922310693970267282_0003
Content-Type: multipart/alternative;4
boundary="----=_NextPart_08072922310693970267282_002"5

6
//無控制符、無標簽的文本內容(BASE64編碼)7
------=_NextPart_08072922310693970267282_0028
Content-Type: text/plain; 9
charset="GB2312"10
Content-Transfer-Encoding: base6411

12
SGVsbG8gV29ybGQhDQo=13

14
//有控制符、標簽的HTML內容(BASE64編碼)15
------=_NextPart_08072922310693970267282_00216
Content-Type: text/html; 17
charset="GB2312"18
Content-Transfer-Encoding: base6419

20
PEhUTUw+PEhFQUQ+PFRJVExFPk1haWw8L1RJVExFPg0KPE1FVEEgY29udGVudD0iS3NESFRNTEVE21
TGliLm9jeCwgRnJlZVdhcmUgSFRNTCBFZGl0b3IgMS4xNjQuMiwgP0t1cnQgU2VuZmVyIiANCm5h22
bWU9R0VORVJBVE9SPg0KPE1FVEEgaHR0cC1lcXVpdj1Db250ZW50LVR5cGUgY29udGVudD0idGV423
dC9odG1sOyBjaGFyc2V0PUdCMjMxMiI+PC9IRUFEPg0KPEJPRFkgc3R5bGU9IkZPTlQtU0laRTog24
OXB0OyBGT05ULUZBTUlMWTogy87M5SIgbGVmdE1hcmdpbj01IHRvcE1hcmdpbj01ICNmZmZmZmY+25
DQo8RElWPkhlbGxvIFdvcmxkITwhLS1BSURfU0VORFRPX0JFR0lOLS0+PC9ESVY+PCEtLURyZWFt26
TWFpbF9BRF9CRUdJTi0tPjxESVY+PEZPTlQgZmFjZT0iQXJpYWwsc2Fucy1zZXJpZiIgc2l6ZT0y27
Pl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f28
X19fX19fX19fX19fPEJSPjxFTT48U3Ryb25nPkRyZWFtTWFpbDwvU3Ryb25nPjwvRU0+Jm5ic3A729
PEZPTlQgZmFjZT0iQXJpYWwsc2Fucy1zZXJpZiIgc2l6ZT0yPi0gtdrSu7j21qez1tPKvP7AtNS030
uPrX2bXEtefX09PKvP6/zbuntssmbmJzcDs8L0ZPTlQ+PEZPTlQgZmFjZT0iQXJpYWwsc2Fucy1z31
ZXJpZiIgY29sb3I9IzAwMDBmZiBzaXplPTI+PEEgaHJlZj0iaHR0cDovL3d3dy5kcmVhbW1haWwu32
b3JnIj53d3cuZHJlYW1tYWlsLm9yZzwvQT48L0ZPTlQ+PC9GT05UPjwvRElWPjwhLS1EcmVhbU1h33
aWxfQURfRU5ELS0+PC9CT0RZPjwvSFRNTD4NCg==34

35
------=_NextPart_08072922310693970267282_002--36
//附件的內容37
------=_NextPart_08072922310693970267282_00038
Content-Type: text/plain; 39
name="1.txt"40
Content-Transfer-Encoding: base6441
Content-Disposition: attachment;42
filename="1.txt"43

44
MTIz45

46
------=_NextPart_08072922310693970267282_000--
看完之后應該對郵件結構有個大致的印象了,其實不難,牛人通常都是把各種值自己填充完,然后用winsocket發出去的。只是都喜歡偷懶,Indy已經幫忙包裝好了,只管用就OK。
【準備工作】
準備啥呢?已經安裝好最新版Indy10的BCB6、一個可以使用SMTP端口的郵件帳號和一條可以上網的線路。
【了解所需的控件】
TIdSMTP中的屬性名稱都很清楚(服務器地址、端口、認證類型、登錄超時等),無需再多說。發信最關鍵是要用到控件的兩個方法:Connect和Send。Connect(AnsiString ServerAddress, AnsiString ServerPort)方法實現的是登錄SMTP服務器和用戶名認證;Send(TIdMessage *AMsg)方法實現的是認證后的發信過程,AMsg指的是信件的內容,也就是與上面所看到類似的信件源碼,它是Indy10中的TIdMessage類指針。
TIdMessage屬性大致歸兩類,一是郵件頭:就是寄信人、收信人、抄送、密送、主題、信件內容編碼、附件編碼等;二是郵件內容:包括無控制符無標簽的純文本內容(Plain)、帶控制符帶標簽的網頁內容(Html)、編碼后的附件(Attachment)。Indy10中,Plain和Html用TIdText類實現,Attachment用TIdAttachmentFile實現。只要將兩個類實例化并掛載在TIdMessage下,就組成一個完整的郵件內容了。
【開始動手】
一個很簡陋的界面:
堆上比較容易理解的代碼:
//main.cpp2
//---------------------------------------------------------------------------3

4
#include <vcl.h>5
#pragma hdrstop6

7
#include "Main.h"8
//---------------------------------------------------------------------------9
#pragma package(smart_init)10
#pragma link "IdExplicitTLSClientServerBase"11
#pragma link "IdSMTPBase"12
#pragma resource "*.dfm"13
TForm1 *Form1;14
//---------------------------------------------------------------------------15
__fastcall TForm1::TForm1(TComponent* Owner)16
: TForm(Owner)17


{18
}19
//---------------------------------------------------------------------------20
void __fastcall TForm1::btnSendClick(TObject *Sender)21


{22
//Mail23
TIdText *idBody, *idHtml;24
TIdAttachmentFile *idAtta;25
try26

{27

28
idMsg=new TIdMessage(Application);29
//Msg base header30
idMsg->From->Name=edtName->Text.Trim();31
idMsg->From->Address=edtMailaddr->Text.Trim();32
idMsg->ReplyTo->EMailAddresses="no_reply@163.com";33
idMsg->ContentType="multipart/alternative";34
idMsg->ContentTransferEncoding="base64";35
idMsg->AttachmentEncoding="MIME";36
idMsg->Encoding=meDefault;37
idMsg->CharSet="gb2312";38
idMsg->Subject=edtSubject->Text.Trim();39
idMsg->Recipients->EMailAddresses=edtTo->Text.Trim();40
idMsg->Priority=mpNormal;41

42
//msg body plain43
idBody=new TIdText(idMsg->MessageParts, idMsg->Body);44
idBody->CharSet="utf-8";45
idBody->ContentType="text/plain";46
idBody->ContentTransfer="base64";47
idBody->Body->Add(mmoContent->Text);48

49
//msg body html50
idHtml=new TIdText(idMsg->MessageParts, idMsg->Body);51
idHtml->CharSet="utf-8";52
idHtml->ContentType="text/html";53
idHtml->ContentTransfer="base64";54
idHtml->Body->Add("<HTML><HEAD><TITLE>Mail</TITLE></HEAD>");55
idHtml->Body->Add("<BODY>");56
idHtml->Body->Add(mmoContent->Text);57
idHtml->Body->Add("</BODY></HTML>");58

59
//msg body attachment60
if (edtAttach->Text.Trim()!="")61

{62
if (FileExists(edtAttach->Text.Trim()))63

{64
idAtta=new TIdAttachmentFile(idMsg->MessageParts, edtAttach->Text.Trim());65

66
idAtta->ContentType="application/octet-stream";67
idAtta->ContentDisposition="attachment";68
idAtta->ContentTransfer="base64";69
idAtta->FileName=ExtractFileName(edtAttach->Text.Trim());70
}71
else72

{73
edtAttach->Text="";74
}75
}76
}77
catch(Exception &exception)78

{79
//show Error!80
idMsg->Clear();81
delete idMsg;82
return;83
}84

85
//SMTP Server86
try87

{88
idSmtp->Username=edtUsername->Text;89
idSmtp->Password=edtPasswd->Text;90
idSmtp->HeloName="SMTP";91
idSmtp->MailAgent="DreamMail";92
idSmtp->UseEhlo=true;93
idSmtp->ReadTimeout=5000;94
idSmtp->Connect(edtServer->Text, StrToInt(edtPort->Text));95
idSmtp->Send(idMsg);96
}97
catch(
)98

{99
//Show error!100
idSmtp->Disconnect();101
delete idMsg;102
return;103
}104
idSmtp->Disconnect();105
delete idMsg;106
ShowMessage("Mail Sent!");107
}108
//---------------------------------------------------------------------------109
void __fastcall TForm1::idSmtpConnected(TObject *Sender)110


{111
btnSend->Enabled=false; 112
}113
//---------------------------------------------------------------------------114
void __fastcall TForm1::idSmtpDisconnected(TObject *Sender)115


{116
btnSend->Enabled=true;117
}118
//---------------------------------------------------------------------------119
void __fastcall TForm1::btnOpenfileClick(TObject *Sender)120


{121
try122

{123
TOpenDialog *opdGetfile=new TOpenDialog(Application);124
opdGetfile->Options.Clear();125
opdGetfile->Title = "Select attachment";126
opdGetfile->Options << ofFileMustExist;127
opdGetfile->InitialDir=ExtractFilePath(Application->ExeName);128
opdGetfile->Filter = "All files (*.*)|*.*";129
opdGetfile->FilterIndex = 2;130
if(opdGetfile->Execute())131

{132
if (FileExists(opdGetfile->FileName))133
edtAttach->Text=opdGetfile->FileName;134

135
}136
}137
catch(
)138

{139
return;140
}141

142

143
}144
//---------------------------------------------------------------------------145

//main.h2
//---------------------------------------------------------------------------3

4
#ifndef MainH5
#define MainH6
//---------------------------------------------------------------------------7
#include <Classes.hpp>8
#include <Controls.hpp>9
#include <StdCtrls.hpp>10
#include <Forms.hpp>11
#include "IdExplicitTLSClientServerBase.hpp"12
#include "IdSMTPBase.hpp"13
#include <IdBaseComponent.hpp>14
#include <IdComponent.hpp>15
#include <IdMessageClient.hpp>16
#include <IdSMTP.hpp>17
#include <IdTCPClient.hpp>18
#include <IdTCPConnection.hpp>19
#include <IdText.hpp> //TIdText needed20
#include <IdAttachmentFile.hpp> //TIdAttachment needed21
//#include <IdMessageCoderMIME.hpp>22
#include <IdCoderHeader.hpp>23

24
//---------------------------------------------------------------------------25
class TForm1 : public TForm26


{27
__published: // IDE-managed Components28
TGroupBox *grpServer;29
TEdit *edtServer;30
TEdit *edtPort;31
TEdit *edtUsername;32
TEdit *edtPasswd;33
TIdSMTP *idSmtp;34
TGroupBox *grpMail;35
TEdit *edtName;36
TEdit *edtMailaddr;37
TEdit *edtTo;38
TEdit *edtSubject;39
TMemo *mmoContent;40
TButton *btnSend;41
TEdit *edtAttach;42
TButton *btnOpenfile;43
TLabel *lbl1;44
TLabel *lbl2;45
TLabel *lbl3;46
TLabel *lbl4;47
TLabel *lbl5;48
TLabel *lbl6;49
TLabel *lbl7;50
TLabel *lbl8;51
TLabel *lbl9;52
void __fastcall btnSendClick(TObject *Sender);53
void __fastcall idSmtpConnected(TObject *Sender);54
void __fastcall idSmtpDisconnected(TObject *Sender);55
void __fastcall btnOpenfileClick(TObject *Sender);56
private: // User declarations57
TIdMessage *idMsg;58
//TIdMessageEncoderMIME *idMsg;59
public: // User declarations60
__fastcall TForm1(TComponent* Owner);61
};62
//---------------------------------------------------------------------------63
extern PACKAGE TForm1 *Form1;64
//---------------------------------------------------------------------------65
#endif66

完成后編譯試試!


