自己动手编写电子邮件软件 任晓磊 2000年 第1期   面对Outlook Express、Foxmail、Eudora、飞扬、亲笔信等琳琅满目的电子邮件软件,你是否也跃跃欲试,想自己编写一个呢?按下面步骤,你就可以实现这个愿望。 #1  一、先试试手工发信   在Foxmail的发信状态窗口中,常会显示一行不断变化的字符:比如MAIL FROM:、RCPT TO、DATA等等,表示工作状态。但是其内部机制是怎样的呢?让我们来“模拟”一下电子邮件软件发信的过程。   先运行Windows95/98中的TELNET.EXE。在其“终端/首选项”菜单中打开“局部回显”。打开“连接”菜单,选择“远程系统”菜单项,打开一个对话框。在“宿主名称”一栏填入你的发信服务器的地址,在“端口”一栏填上25,然后开始连接。   接通以后,会出现类似下列字符:   220 XXX Sendmail ...   其中220是SMTP服务器的返回码,表示已经准备好,准备发信,SENDMAIL是UNIX系统中负责发信的SENDMAIL进程,XXX是服务器的名字。   首先,必须向服务器表明自己的身份,以便系统自动撰写日志。该命令格式为:   HELO 你的主机名称   完成后,服务器返回250,表示接受。现在可以告诉服务器你的发信地址,以便对方回信或发送失败后退信。   MAIL FROM:你的电子邮件地址   注意其中的冒号不能省略。如果系统认可,同样返回250。这时,就可以告诉SMTP服务器你的信要发给谁。请输入:   RCPT TO:收件人的地址   这个命令如果多次使用,就表示把这封信同时发给多个收件人。收到返回的250代码以后,就可以开始传输数据了。打入DATA命令并回车,看见返回码354以后,即可开始输入邮件的内容。内容结束时,再在新的一行中单独打一个英文句号,再回车,就告诉服务器你的信输完了。这时可以收到服务器返回的250代码,表示OK。   最后,键入QUIT命令,终止这个TELNET会话。服务器返回221后,会主动断开连接。 #1  二、自己写个小程序   我们的目的是设计一个VB程序,让它来完成这一系列发信动作。因此,必须了解Visual Basic中的Winsock通信控件的使用方法。   打开VB5,新建一个“标准EXE”工程,在“工程/部件”菜单中,增加Microsoft Winsock Control 5.0控件。Winsock控件的LocalPort属性是用来设置本地主机使用的网络端口,一般是25。RemoteHost和RemotePort属性可以设置同哪台网络服务器的哪个端口进行通信,在这里我们把RemotePort设成25表示与SMTP服务器进行连接。Protocol属性设为0 -sckTCPProtocol,表示使用TCP协议。   Winsock有几个方法是我们所需要的。Connect方法,用于设置好上述四个属性后开始连接远程主机,Winsock收到数据时,产生DataArrival事件。在这个事件中你可以用GetData方法获取收到的数据。另外,也可以用SendData方法发送数据。   掌握了这些资料,我们就可以设计一个简单的发送程序。程序中用到的控件如下:   刚刚连通时和每个命令执行后,要检查服务器的返回码,所以必须把发送邮件的部分放在Winsock1_DataArrival事件中。实现此功能的代码如下:   Private Sub cmdSend_Click()   Winsock1.RemoteHost = txtServer.Text   Winsock1.Connect   End Sub   ---------------------- Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)   Dim Data As String   Winsock1.GetData Data   Select Case Val(Data) ′处理返回码    Case 220 ′如果是刚刚连通,则发送helo命令,并设置标志为helo,以便识别     Tag = ″helo″     Winsock1.SendData ″helo ″ & txtServer.Text & vbCrLf    Case 250   ′如果返回250(OK)     Select Case Tag  ′则判断执行命令时设置的标志,以区分刚执行了哪条命令    Case ″helo″     Winsock1.SendData ″mail from:″ & txtFrom.Text & vbCrLf     Tag = ″mail″    Case ″mail″  ′如果刚执行了MAIL命令,则执行RCPT命令   Winsock1.SendData ″rcpt to:″ & txtTo.Text & vbCrLf      Tag = ″rcpt″    Case ″rcpt″  ′如果刚执行了RCPT命令,则执行DATA命令     Winsock1.SendData ″data″ & vbCrLf      Tag = ″data″    Case ″data″  ′如果刚执行了DATA命令,则执行QUIT命令      Winsock1.SendData ″quit″ & vbCrLf      Tag = ″quit″   End Select    Case 251      Winsock1.SendData ″data″ & vbCrLf      Tag = ″data″    Case 354       Winsock1.SendData ″From:″ & txtFrom.Text & vbCrLf & ″To:″ & txtTo.Text & vbCrLf & ″Subject: ″ & txtSubject.Text & vbCrLf & ″Date:″ & Now()    Winsock1.SendData ″MIME-Version: 1.0″ & vbCrLf & ″Content-Type: text/plain;charset=″″gb2312″″″ & vbCrLf & ″Content-Transfer-Encoding: 8bit″ & vbCrLf & vbCrLf    Winsock1.SendData txtContent.Text    Winsock1.SendData vbCrLf & ″.″ & vbCrLf     Case 221 ′如果是QUIT命令的返回码,就清除命令执行标志,准备断开连接       Tag = ″″     Case Else  ′如果是其他返回码,就提示错误       Winsock1.SendData ″quit″ & vbCrLf       Tag = ″quit″       MsgBox ″错误″ & Data   End Select   End Sub #1  三、邮件头及编码   当你收到刚才给自己发的邮件,可能会发现,这封信既没有“发件人”、“收件人”,也没有“主题”和“日期”。这是由于刚才的程序中没有加入对邮件头部信息和邮件体编码的功能。一个典型的邮件头是这个样子:   From: ″cxx″   To:   Subject: =?gb2312?B?taW797TLtKbK5MjrytW8/sjL?=   Date: Mon,20 Dec 1999 16:46:58 +0800   MIME-Version: 1.0   Content-Type: text/plain;   charset=″gb2312″   Content-Transfer-Encoding: quoted-printable   在这个邮件头指定的编码方式是quoted-printable,实际上,中国大部分服务器都支持8位编码,所以无须再进行编码。经过修改的程序段如下:   Sub Winsock1_DataArrival()   ......   Case 354   Winsock1.SendData ″From:″ & txtFrom.Text & vbCrLf & ″To:″ & txtTo.Text & vbCrLf & ″Subject: ″ & txtSubject.Text & vbCrLf & ″Date:″ & Now()   Winsock1.SendData ″MIME-Version: 1.0″ & vbCrLf & ″Content-Type: text/plain;charset=″″gb2312″″″ & vbCrLf & ″Content-Transfer-Encoding: 8bit″ & vbCrLf & vbCrLf   Winsock1.SendData txtContent.Text   Winsock1.SendData vbCrLf & ″.″ & vbCrLf   ......   End Sub   到此为止,一个简单的电子邮件软件就编写成功了。各位感兴趣的读者可以根据需要对功能进行增减,使其满足自己的需要。