利用Indy 10的IdSMTP控件制作可帶附件的郵件發(fā)送器
作者:Tuuzed(土仔) 發(fā)表于:2008年7月29日
版權(quán)聲明:可以任意轉(zhuǎn)載,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必以超鏈接形式標(biāo)明文章原始出處和作者信息及本聲明。
http://www.shnenglu.com/tuuzed/archive/2008/07/29/57477.html
Indy10中的IdSMTP控件比BCB6中自帶的NMSMTP支持更多的SMTP命令(支持RFC 821,RFC 1869 ,RFC 2197 ,RFC 2554),像國內(nèi)的網(wǎng)易、TOM、21CN等的SMTP都需要EHLO命令先進(jìn)行認(rèn)證才可使用。但是,目前很多大型的郵件服務(wù)商出于預(yù)防垃圾郵件的考慮,已經(jīng)開始取消或限制SMTP發(fā)信了,改為提供WebMail服務(wù),因此可用的SMTP服務(wù)器是少之又少了。有人說現(xiàn)在做SMTP郵件發(fā)送器意義已經(jīng)不大,可我認(rèn)為,動(dòng)手去做這個(gè)SMTP發(fā)送器可以更好的了解一封電子郵件的結(jié)構(gòu)和它的產(chǎn)生過程,管他別人愛說啥!
【郵件大致結(jié)構(gòu)】
先用DreamMail發(fā)一封測(cè)試信:由TestID@163.com發(fā)信給TestID2@21cn.com,其中掛載附件1.txt。信件從21CN收回來之后是這樣子的:
1
//服務(wù)器自動(dòng)添加的東西
2
HMM_SOURCE_IP:10.27.2.7:55493.2027099718
3
HMM_ATTACHE_NUM:0001
4
HMM_SOURCE_TYPE:SMTP
5
Received: from aisp7-mta?dg (dgproxy7.inner-hermes.com [10.27.2.7])
6
by 21cn.com (HERMES) with SMTP id 359B63813A
7
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 +0000
14
15
X-Original-MailFrom: TestID@163.com
16
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)
1
//大都是我們自己填寫的東西
2
//回復(fù)地址
3
Reply-To: TestID@163.com
4
5
From: "TestID" <TestID@163.com>
6
To: "TestID2" <TestID2@21cn.com>
7
Subject: Test Attachment
8
Date: Tue, 29 Jul 2008 22:31:07 +0800
9
//Dreammail的識(shí)別ID
10
Message-Id: <DreamMail__223107_76081071266@smtp.163.com>
11
MIME-Version: 1.0
12
//內(nèi)容類型及內(nèi)容“指針I(yè)D”
13
Content-Type: multipart/mixed;
14
boundary="----=_NextPart_08072922310693970267282_000"
15
//郵件優(yōu)先級(jí)
16
X-Priority: 3
17
//客戶端名稱
18
X-Mailer: DreamMail 4.4.1.0
19
X-Coremail-Antispam: 1Uf129KBjDUn29KB7ZKAUJUUUUUYxn0WfASr-VFAUDa7-sFnT
20
9fnUUIcSsGvfJTRUUUj_xYjsxI4VWUJwAYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1I0E4x80
21
FVCIwcAKzIAtM7C26IkvcIIF6IxKo4kEV4yl1IIY67AEw4v_Jr0_Jr4le4C267I2x7xF54
22
xIwI1l52xGzVA2a4k0FcxF6cIjj282cryl52xGzVA2a4k0FcxF6xCjrcI26cIUMc02F40E
23
57IF67AEF4xIwI1lYx0E2Ix0cI8IcVAFwI0_Jrv_JF1lYx0Ex4A2jsIE14v26r1j6r4UM4
24
xvF2IEb7IF0Fy264kE64k0F24lFcxC0VAYjxAxZF0Ex2IqxwAC62BYpTIE1TZKA3svLVAK
25
vSnIqfZI6r4lFVCF04k20xvEw2I207IF0wAKzVCY07xG64k0F24l7I0Y6sxI4wCY1Ik26c
26
xK620vw7xCY7Wlc7Ca8VAvwVCjb41lc7Ca8VAvwVCFzxkY4VA2I41lc2xSY4AK67AK6ry5
27
MxkI7II2jI8vz4v_Jr0_Jryl4x8a6c8ajcxJMI8E67AF67kF1VAFwI0_Jr0_JrylIxAIcV
28
C0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Jr0_Gr1lIxAIcVC2
29
z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVWUJVW8JbIYCTnIWIevJa73Uj
30
IFyTuYvjxUgg4SUUUUU
31
//ESet病毒防火墻添加
32
X-EsetId: 2080B02B6D6871693F86B07B643E31
1
//內(nèi)容開始了,對(duì)應(yīng)上面說的“指針I(yè)D”
2
------=_NextPart_08072922310693970267282_000
3
Content-Type: multipart/alternative;
4
boundary="----=_NextPart_08072922310693970267282_002"
5
6
//無控制符、無標(biāo)簽的文本內(nèi)容(BASE64編碼)
7
------=_NextPart_08072922310693970267282_002
8
Content-Type: text/plain;
9
charset="GB2312"
10
Content-Transfer-Encoding: base64
11
12
SGVsbG8gV29ybGQhDQo=
13
14
//有控制符、標(biāo)簽的HTML內(nèi)容(BASE64編碼)
15
------=_NextPart_08072922310693970267282_002
16
Content-Type: text/html;
17
charset="GB2312"
18
Content-Transfer-Encoding: base64
19
20
PEhUTUw+PEhFQUQ+PFRJVExFPk1haWw8L1RJVExFPg0KPE1FVEEgY29udGVudD0iS3NESFRNTEVE
21
TGliLm9jeCwgRnJlZVdhcmUgSFRNTCBFZGl0b3IgMS4xNjQuMiwgP0t1cnQgU2VuZmVyIiANCm5h
22
bWU9R0VORVJBVE9SPg0KPE1FVEEgaHR0cC1lcXVpdj1Db250ZW50LVR5cGUgY29udGVudD0idGV4
23
dC9odG1sOyBjaGFyc2V0PUdCMjMxMiI+PC9IRUFEPg0KPEJPRFkgc3R5bGU9IkZPTlQtU0laRTog
24
OXB0OyBGT05ULUZBTUlMWTogy87M5SIgbGVmdE1hcmdpbj01IHRvcE1hcmdpbj01ICNmZmZmZmY+
25
DQo8RElWPkhlbGxvIFdvcmxkITwhLS1BSURfU0VORFRPX0JFR0lOLS0+PC9ESVY+PCEtLURyZWFt
26
TWFpbF9BRF9CRUdJTi0tPjxESVY+PEZPTlQgZmFjZT0iQXJpYWwsc2Fucy1zZXJpZiIgc2l6ZT0y
27
Pl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
28
X19fX19fX19fX19fPEJSPjxFTT48U3Ryb25nPkRyZWFtTWFpbDwvU3Ryb25nPjwvRU0+Jm5ic3A7
29
PEZPTlQgZmFjZT0iQXJpYWwsc2Fucy1zZXJpZiIgc2l6ZT0yPi0gtdrSu7j21qez1tPKvP7AtNS0
30
uPrX2bXEtefX09PKvP6/zbuntssmbmJzcDs8L0ZPTlQ+PEZPTlQgZmFjZT0iQXJpYWwsc2Fucy1z
31
ZXJpZiIgY29sb3I9IzAwMDBmZiBzaXplPTI+PEEgaHJlZj0iaHR0cDovL3d3dy5kcmVhbW1haWwu
32
b3JnIj53d3cuZHJlYW1tYWlsLm9yZzwvQT48L0ZPTlQ+PC9GT05UPjwvRElWPjwhLS1EcmVhbU1h
33
aWxfQURfRU5ELS0+PC9CT0RZPjwvSFRNTD4NCg==
34
35
------=_NextPart_08072922310693970267282_002--
36
//附件的內(nèi)容
37
------=_NextPart_08072922310693970267282_000
38
Content-Type: text/plain;
39
name="1.txt"
40
Content-Transfer-Encoding: base64
41
Content-Disposition: attachment;
42
filename="1.txt"
43
44
MTIz
45
46
------=_NextPart_08072922310693970267282_000--
看完之后應(yīng)該對(duì)郵件結(jié)構(gòu)有個(gè)大致的印象了,其實(shí)不難,牛人通常都是把各種值自己填充完,然后用winsocket發(fā)出去的。只是都喜歡偷懶,Indy已經(jīng)幫忙包裝好了,只管用就OK。
【準(zhǔn)備工作】
準(zhǔn)備啥呢?已經(jīng)安裝好最新版Indy10的BCB6、一個(gè)可以使用SMTP端口的郵件帳號(hào)和一條可以上網(wǎng)的線路。
【了解所需的控件】
TIdSMTP中的屬性名稱都很清楚(服務(wù)器地址、端口、認(rèn)證類型、登錄超時(shí)等),無需再多說。發(fā)信最關(guān)鍵是要用到控件的兩個(gè)方法:Connect和Send。Connect(AnsiString ServerAddress, AnsiString ServerPort)方法實(shí)現(xiàn)的是登錄SMTP服務(wù)器和用戶名認(rèn)證;Send(TIdMessage *AMsg)方法實(shí)現(xiàn)的是認(rèn)證后的發(fā)信過程,AMsg指的是信件的內(nèi)容,也就是與上面所看到類似的信件源碼,它是Indy10中的TIdMessage類指針。
TIdMessage屬性大致歸兩類,一是郵件頭:就是寄信人、收信人、抄送、密送、主題、信件內(nèi)容編碼、附件編碼等;二是郵件內(nèi)容:包括無控制符無標(biāo)簽的純文本內(nèi)容(Plain)、帶控制符帶標(biāo)簽的網(wǎng)頁內(nèi)容(Html)、編碼后的附件(Attachment)。Indy10中,Plain和Html用TIdText類實(shí)現(xiàn),Attachment用TIdAttachmentFile實(shí)現(xiàn)。只要將兩個(gè)類實(shí)例化并掛載在TIdMessage下,就組成一個(gè)完整的郵件內(nèi)容了。
【開始動(dòng)手】
一個(gè)很簡陋的界面:

堆上比較容易理解的代碼:
1
//main.cpp
2
//---------------------------------------------------------------------------
3
4
#include <vcl.h>
5
#pragma hdrstop
6
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
//Mail
23
TIdText *idBody, *idHtml;
24
TIdAttachmentFile *idAtta;
25
try
26
{
27
28
idMsg=new TIdMessage(Application);
29
//Msg base header
30
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 plain
43
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 html
50
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 attachment
60
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
else
72
{
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 Server
86
try
87
{
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
try
122
{
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
1
//main.h
2
//---------------------------------------------------------------------------
3
4
#ifndef MainH
5
#define MainH
6
//---------------------------------------------------------------------------
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 needed
20
#include <IdAttachmentFile.hpp> //TIdAttachment needed
21
//#include <IdMessageCoderMIME.hpp>
22
#include <IdCoderHeader.hpp>
23
24
//---------------------------------------------------------------------------
25
class TForm1 : public TForm
26

{
27
__published: // IDE-managed Components
28
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 declarations
57
TIdMessage *idMsg;
58
//TIdMessageEncoderMIME *idMsg;
59
public: // User declarations
60
__fastcall TForm1(TComponent* Owner);
61
};
62
//---------------------------------------------------------------------------
63
extern PACKAGE TForm1 *Form1;
64
//---------------------------------------------------------------------------
65
#endif
66
完成后編譯試試!