对第五期电子邮件发送程序的完善
相关的例子:下载>>> 作者:zklhp 于2008-9-19上传 

我是汇编通讯的忠实读者,看汇编通讯一年了,也写个程序,也算是为杂志做点贡献吧。写的不好,还望各位高手指点。

看第五期时,我就对《用汇编语言写ESMTP电子邮件发送程序》很感兴趣。可程序提示发送成功后,并没有收到邮件,当时也没再深究,

后来再试,又能成功发送了,真是@#%。现在放假了,又想起那个程序,就研究了一下ESMTP发邮件的过程,顺便完善了一下谢平的程序。

image001.jpg (53002 字节)

 

帖一下我的写的发送线程函数吧。排版可能不太好,建议用masmplus直接看工程。

.code

_SendProc    proc uses ebx edi esi _Param:DWORD
    local    @hSocket:DWORD
    local    @stWsadata:WSADATA
    local    @stSin:sockaddr_in
    local    @szRcvBuffer[1024]:BYTE
    local    @szSend[4096]:BYTE
    local    @szBuffer[2048]:BYTE
   
    invoke    WSAStartup, 202h, addr @stWsadata
    invoke    socket, AF_INET, SOCK_STREAM, 0
    .if    eax == INVALID_SOCKET
        invoke    WSAGetLastError
        invoke    wsprintf,addr @szBuffer,CTXT('创建套接字出错 错误码 %x',0dh,0ah),eax
        invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szBuffer
        invoke     MessageBox,hWinMain,CTXT('发送失败!'),CTXT('错误'),0
        jmp    @exit
    .endif
    mov    @hSocket, eax
   
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('创建套接字成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @stSin,sizeof @stSin
    mov    @stSin.sin_family, AF_INET
    invoke    htons, 25    ;默认端口是25
    mov    @stSin.sin_port, ax
    invoke    gethostbyname,offset szSmtpAddr
    .if    eax
        mov    eax, [eax + hostent.h_list]
        mov    eax, [eax]
        mov    eax, [eax]
        mov    @stSin.sin_addr, eax
    .endif
   
    ;建立连接
    invoke    connect,@hSocket, addr @stSin, sizeof @stSin
    .if    eax == SOCKET_ERROR
        invoke    WSAGetLastError
        invoke     wsprintf,@szBuffer,CTXT('连接服务器出错 错误码 %x',0dh,0ah),eax
        invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szBuffer
        invoke     MessageBox,hWinMain,CTXT('发送失败!'),CTXT('错误'),0
        jmp    @exit
    .endif
   
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('连接到服务器成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer
    invoke    recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer
   
    ;发送“ehlo local”
    invoke    lstrlen,offset szEhlo
    invoke    send, @hSocket, addr szEhlo, eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 ehlo local 成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer
    invoke    recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer
   
    ;发送“auth login”
    ;好象大多数免费邮箱都支持login验证方式 支持cram-md5的却没找到~~~ 这里只用login吧
    invoke    lstrlen,addr szAuth
    invoke    send, @hSocket, addr szAuth, eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 auth login 成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer
    invoke    recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0
    lea    esi,@szRcvBuffer
    add    esi,4
    invoke    lstrlen,esi
    mov    edi,eax
    ;要把最后的\r\t除去
    dec    edi
    dec    edi
    ;貌似这样比 sub edi,2 省个字节 呵呵
    invoke    RtlZeroMemory,addr @szBuffer,sizeof @szBuffer
    invoke    _Base64Decode,esi,addr @szBuffer,edi
    invoke    wsprintf,addr @szRcvBuffer,CTXT('334 %s',0dh,0ah),addr @szBuffer    ;我们自己把他解码还原
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer
   
    ;发送用户名
    invoke    lstrlen,offset szUserName
    invoke    _Base64Encode,offset szUserName,addr @szBuffer,eax
    invoke    wsprintf,addr @szSend,CTXT('%s',0dh,0ah),addr @szBuffer
    invoke    lstrlen,addr @szSend
    invoke    send, @hSocket, addr @szSend, eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送用户名成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer
    invoke    recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0
    lea    esi,@szRcvBuffer
    add    esi,4
    invoke    lstrlen,esi
    mov    edi,eax
    dec    edi
    dec    edi    ;貌似这样比 sub edi,2 省个字节 呵呵
    invoke    RtlZeroMemory,addr @szBuffer,sizeof @szBuffer
    invoke    _Base64Decode,esi,addr @szBuffer,edi
    invoke    wsprintf,addr @szRcvBuffer,CTXT('334 %s',0dh,0ah),addr @szBuffer    ;我们自己把他解码还原
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer
   
    ;发送密码
    invoke    lstrlen,offset szPassWord
    invoke    _Base64Encode,offset szPassWord,addr @szBuffer,eax
    invoke    wsprintf,addr @szSend,CTXT('%s',0dh,0ah),addr @szBuffer
    invoke    lstrlen,addr @szSend
    invoke    send, @hSocket, addr @szSend, eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送密码成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer
    invoke    recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer
    invoke    StrStr,addr @szRcvBuffer,CTXT('235')
    .if    eax == 0    ;没有就是验证不通过
        invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('验证失败!',0dh,0ah)
        invoke    WSACleanup
        invoke     GetDlgItem,hWinMain,IDC_BTN_SEND
        invoke    EnableWindow,eax,TRUE
        xor    eax,eax
        dec    eax
        ret
    .endif
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('验证成功!',0dh,0ah)
   
    ;发送“mail from”
    invoke    GetDlgItemText,hWinMain,IDC_EDT_SENDADDR,addr @szBuffer,sizeof @szBuffer
    invoke    wsprintf,addr @szSend,addr szMailFrom,addr @szBuffer
    invoke    lstrlen,addr @szSend
    invoke    send, @hSocket, addr @szSend,eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 mail from 成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer
    invoke    recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer
   
    ;发送“rcpt to”
    invoke    GetDlgItemText,hWinMain,IDC_EDT_RCPTADDR,addr @szBuffer,sizeof @szBuffer
    invoke    wsprintf,addr @szSend,addr szRcptTo,addr @szBuffer
    invoke    lstrlen,addr @szSend
    invoke    send, @hSocket, addr @szSend,eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 rcpt to 成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer
    invoke    recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer
   
    ;发送“data”
    invoke    lstrlen,addr szData
    invoke    send, @hSocket, addr szData, eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 data 成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer
    invoke    recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer
   
    ;发送“from”
    invoke    GetDlgItemText,hWinMain,IDC_EDT_SENDADDR,addr @szBuffer,sizeof @szBuffer
    invoke    wsprintf,addr @szSend,addr szFrom,addr @szBuffer
    invoke    lstrlen,addr @szSend
    invoke    send, @hSocket, addr @szSend,eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 from 成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer
    invoke    Sleep,1000
   
    ;发送“to”
    invoke    GetDlgItemText,hWinMain,IDC_EDT_RCPTADDR,addr @szBuffer,sizeof @szBuffer
    invoke    wsprintf,addr @szSend,addr szTo,addr @szBuffer
    invoke    lstrlen,addr @szSend
    invoke    send, @hSocket, addr @szSend,eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 to 成功!',0dh,0ah)
   
    ;发送主题
    invoke    GetDlgItemText,hWinMain,IDC_EDT_SUB,addr @szBuffer,sizeof @szBuffer
    invoke    wsprintf,addr @szSend,addr szSubject,addr @szBuffer
    invoke    lstrlen,addr @szSend
    invoke    send, @hSocket, addr @szSend,eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送主题成功!',0dh,0ah)
   
    ;发送"Reply-TO"
    invoke    RtlZeroMemory,addr @szSend,sizeof @szSend
    invoke    RtlZeroMemory,addr @szBuffer,sizeof @szBuffer
    invoke    GetDlgItemText,hWinMain,IDC_EDT_SENDADDR,addr @szBuffer,sizeof @szBuffer
    invoke    wsprintf,addr @szSend,addr szReplyTo,addr @szBuffer
    invoke    lstrlen,addr @szSend
    invoke    send, @hSocket, addr @szSend,eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 Reply-TO 成功!',0dh,0ah)
   
    ;发送空行
    invoke    lstrlen,addr szCrLf
    invoke    send, @hSocket, addr szCrLf,eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送空行成功!',0dh,0ah)
   
    ;发送邮件正文
    invoke    RtlZeroMemory,addr @szSend,sizeof @szSend
    invoke    RtlZeroMemory,addr @szBuffer,sizeof @szBuffer
    invoke    GetDlgItemText,hWinMain,IDC_EDT_CONTENT,addr @szBuffer,sizeof @szBuffer
    invoke    wsprintf,addr @szSend,addr szContent,addr @szBuffer
    invoke    lstrlen,addr @szSend
    invoke    send, @hSocket, addr @szSend,eax, 0
   
    ;发送“.”
    invoke    lstrlen,addr szDot
    invoke    send, @hSocket, addr szDot, eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 . 成功!',0dh,0ah)
    invoke    RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer
    invoke    recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer
   
    ;发送“quit”
    invoke    lstrlen,addr szQuit
    invoke    send, @hSocket, addr szQuit, eax, 0
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 quit 成功!',0dh,0ah)
   
    ;断开连接
    invoke    closesocket, @hSocket
    invoke     SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('与服务器连接断开!',0dh,0ah)
    invoke    MessageBox,hWinMain,CTXT('发送成功!'),CTXT('提示'),0
   
@exit:
    invoke    WSACleanup
    invoke    GetDlgItem,hWinMain,IDC_BTN_SEND
    invoke    EnableWindow,eax,TRUE
   
    xor    eax,eax
    ret
_SendProc endp

 

开始,我以为验证时要用到CRAM-MD5 等算法,可用telnet一试才知道,免费邮箱大多支持login验证方式,就简化了这个函数,

用一种简单的方式判断验证成功,省了不少时间,呵呵。

其他的都不用说了,很简单,看代码都能看懂。

总结一下,这个程序的存在的缺点有:

1. 界面处理写的太烂,不怎么规矩。

2. 发送函数过于简陋,支持的验证方法少。

3. 对线程的处理不太好,对发送错误的情况考虑不太好。

4. 不支持发送附件。

 

我的汇编还很菜,程序中的错误还请各位高手指出。在程序的写作过程中得到了很多高手的无私帮助,在此一并表示感谢。也感谢

老罗和谢平为我的程序提供范例,为本程序的写作铺平道路。

最后,感谢Aogosoft为我们这些汇编爱好者提供这样一个交流的平台,希望高手们多多支持汇编通讯,让汇编通讯越办越好!

 

参考:

1. 罗云彬的《Windows环境下32位汇编语言程序设计》

2. 老罗的《用汇编语言编写ESMTP邮件发送程序》

3. 汇编通讯第五期《用汇编语言写ESMTP电子邮件发送程序》

4.http://hi.bccn.net/space-64405-do-blog-id-2002.html 在命令行下发送Email。

5.http://dev.csdn.net/article/19/19890.shtm ESMTP身份验证机制探索手记。

6.自己写的几个函数:

http://bbs.bccn.net/thread-227380-1-1.html BASE64编码函数。

http://bbs.bccn.net/thread-228639-1-1.html BASE64解码函数。

http://bbs.bccn.net/thread-227039-1-1.html CRAM-MD5算法实现函数,并没用上。

http://bbs.bccn.net/thread-226811-1-1.html MD5 算法实现函数,并没用上。



<<<上一篇
欢迎访问AoGo汇编小站:http://www.aogosoft.com
下一篇>>>