發送郵件使用的是SMTP協議,也稱簡單郵件傳輸協議。現在在網上搜到的代碼或者例子大都是SMTP協議的,但是而今大多數郵件服務器都已經採用驗證式的STMP協議了,所以這些代碼或者例子常常得到無法調試成功的結果,這給了我們初學者一個不小的打擊。其實所謂驗證式的SMTP協議,只不過是在原來的SMTP協議的基礎上加上了一個用戶密碼驗證,驗證後的協議內容跟原來別無二致。這種新的驗證式SMTP協議稱爲ESMTP,也即擴展簡單郵件傳輸協議。
之所以要擴展SMTP協議,是爲了防止垃圾郵件的日益氾濫,阻止未經驗證的垃圾郵件製造者隨意使用這項服務。但我個人認爲ESMTP並沒達到目的(粗淺認識),現在的免費郵箱一大把,隨便註冊一個一樣可以發一大堆垃圾郵件啊。(不過由於是經過了驗證的,經過服務器的垃圾郵件過濾就可以把你這個郵箱帳號給~~,"反正是黑名單吧")。
ESMTP協議是一種C/S應答式協議,郵件客戶端發送一個請求,服務器返回相應的內容。
C:連接服務器... (通過connect函數)
S:220
C:HELO username
S:250
C:AUTH LOGIN
S:334
C:Base64(username) (經過Base64編碼後的用戶名)
S:334
C:Base64(password) (經過Base64編碼後的密碼)
S:235
C:MAIL FROM: <[email protected]> ()
S:250
C:RCPT TO: <[email protected]> ()
S:250
C:DATA
S:354
C:
S:250
C:
S:221
.386
.model flat, stdcall
option casemap:none
include /masm32/include/windows.inc
include /masm32/include/kernel32.inc
include /masm32/include/user32.inc
include /masm32/include/comdlg32.inc
include /masm32/include/wsock32.inc
includelib /masm32/lib/kernel32.lib
includelib /masm32/lib/user32.lib
includelib /masm32/lib/comdlg32.lib
includelib /masm32/lib/wsock32.lib
.const
IDI_MAIN equ 1
IDC_EDIT_ATTACHMENT equ 3008
IDC_BUTTON_BROWSE equ 3009
DlgMain equ 1
IDC_EDIT_SMTPSERVER equ 1
IDC_EDIT_USERNAME equ 2
IDC_EDIT_PASSWORD equ 3
IDC_EDIT_FROM equ 4
IDC_EDIT_TO equ 5
IDC_EDIT_SUBJECT equ 6
IDC_EDIT_CONTENT equ 7
IDC_BUTTON_SEND equ 8
IDC_VAl equ 9
TCP_PORT equ 25
MAIL_HELO equ 1
MAIL_LOGIN equ 2
MAIL_USER equ 3
MAIL_PASS equ 4
MAIL_FROM equ 5
MAIL_RCPT equ 6
MAIL_DATA equ 7
MAIL_DOT equ 8
MAIL_QUIT equ 9
.data
;下面是爲了方便調試,預設的各項參數:
sz1 db "smtp.163.com", 0
;sz2 db "zhangyuming123456", 0
;sz3 db "789789", 0
;sz4 db "[email protected]", 0
;sz5 db "[email protected]", 0
;sz6 db "最近如何?", 0
;sz7 db "你好嗎?", 0
szCaption db "ESMTP郵件發送程序",0
szServerIPErr db "SMTP服務器地址解析失敗!",0
szConnectErr db "連接服務器出錯!",0
szSendOK db "郵件發送成功!",0
szSendErr db "郵件發送失敗!",0
szHeloFmt db "HELO %s", 13, 10, 0
szLoginFmt db "AUTH LOGIN", 13, 10, 0
szUserPassFmt db "%s", 13, 10, 0
szFromFmt db "MAIL FROM: <%s>", 13, 10,0
szRcptFmt db "RCPT TO: <%s>", 13, 10, 0
szDataFmt db "DATA", 13, 10,0
szQuitFmt db "QUIT",13,10,0
szTextFmt db "From: <%s>", 13, 10
db "To: <%s>", 13, 10
db "Subject: %s", 13, 10
db "MIME_Version: 1.0", 13, 10
db "Content-type:text/plain;Charset=GB2312", 13, 10
db "Content-Transfer-Encoding:8bit", 13, 10, 13, 10
db "%s", 13, 10,13,10, ".",13, 10, 0
;Base64 -> ASCII mapping table
base64_alphabet db "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",0
szFmt db "%d",0
.data?
hInstance dd ?
hSocket dd ?
hWinMain dd ?
szServer db 256 dup (?)
szUser db 256 dup (?)
szPass db 256 dup (?)
szFrom db 256 dup (?)
szRcpt db 256 dup (?)
szSubject db 256 dup (?)
szText db 30000 dup (?)
szBuf1 db 65536 dup (?)
.code
Base64Encode proc uses ebx edi esi source:DWORD, destination:DWORD
LOCAL sourcelen:DWORD
invoke lstrlen, source
mov sourcelen, eax
mov esi, source
mov edi, destination
@@base64loop:
xor eax, eax
.if sourcelen == 1
lodsb ;source ptr + 1
mov ecx, 2 ;bytes to output = 2
mov edx, 03D3Dh ;padding = 2 byte
dec sourcelen ;length - 1
.elseif sourcelen == 2
lodsw ;source ptr + 2
mov ecx, 3 ;bytes to output = 3
mov edx, 03Dh ;padding = 1 byte
sub sourcelen, 2 ;length - 2
.else
lodsd
mov ecx, 4 ;bytes to output = 4
xor edx, edx ;padding = 0 byte
dec esi ;source ptr + 3 (+4-1)
sub sourcelen, 3 ;length - 3
.endif
xchg al,ah ;flip eax completely
rol eax, 16 ;can this be done faster
xchg al,ah
@@:
push eax
and eax, 0FC000000h ;get the last 6 high bits
rol eax, 6 ;rotate them into al
mov al, BYTE ptr [offset base64_alphabet + eax] ;get encode character
stosb ;write to destination
pop eax
shl eax, 6 ;shift left 6 bits
dec ecx
jnz @B ;loop
cmp sourcelen, 0
jnz @@base64loop ;main loop
mov eax, edx ;add padding and null terminate
stosd
ret
Base64Encode endp
_GetText proc uses ebx esi
invoke GetDlgItemText,hWinMain,IDC_EDIT_SMTPSERVER,addr szServer,256
invoke GetDlgItemText,hWinMain,IDC_EDIT_USERNAME,addr szUser,256
invoke GetDlgItemText,hWinMain,IDC_EDIT_PASSWORD,addr szPass,256
invoke GetDlgItemText,hWinMain,IDC_EDIT_FROM,addr szFrom,256
invoke GetDlgItemText,hWinMain,IDC_EDIT_TO,addr szRcpt,256
invoke GetDlgItemText,hWinMain,IDC_EDIT_SUBJECT,addr szSubject,256
invoke GetDlgItemText,hWinMain,IDC_EDIT_CONTENT,addr szText,30000
ret
_GetText endp
_EnableCtrl proc _State
local nID
mov nID,1
.while nID<=8
invoke GetDlgItem,hWinMain,nID
invoke EnableWindow,eax,_State
inc nID
.endw
ret
_EnableCtrl endp
_WaitFor proc _nNum
local @szBuf[1024]:BYTE
local @stFdSet:fd_set,@stTimeval:timeval
;local @nNum
mov @stFdSet.fd_count,1
push hSocket
pop @stFdSet.fd_array
mov @stTimeval.tv_sec,60
mov @stTimeval.tv_usec,0
invoke select,0,addr @stFdSet,NULL,NULL,addr @stTimeval
.if eax==0 || eax==SOCKET_ERROR
invoke MessageBox,hWinMain,addr szSendErr,addr szCaption,MB_OK
invoke _EnableCtrl,TRUE
invoke ExitThread,NULL
;郵件發送失敗
.endif
invoke recv,hSocket,addr @szBuf,sizeof @szBuf,0
invoke MessageBox,hWinMain,addr @szBuf,addr szCaption,MB_OK
mov BYTE ptr @szBuf[3],0
invoke SetDlgItemText,hWinMain,IDC_VAl,addr @szBuf
invoke GetDlgItemInt,hWinMain,IDC_VAl,NULL,FALSE
;mov @nNum,eax
;invoke wsprintf,addr @szBuf,addr szFmt,@nNum
;invoke MessageBox,NULL,addr @szBuf,NULL,MB_OK
;invoke wsprintf,addr @szBuf,addr szFmt,_nNum
;invoke MessageBox,NULL,addr @szBuf,NULL,MB_OK
;mov eax,@nNum
.if eax != _nNum
invoke MessageBox,hWinMain,addr szSendErr,addr szCaption,MB_OK
invoke _EnableCtrl,TRUE
invoke ExitThread,NULL
;郵件發送失敗
.endif
ret
_WaitFor endp
_SendCmd proc _StateID
mov eax,_StateID
.if eax==MAIL_HELO
invoke wsprintf,addr szBuf1,addr szHeloFmt,addr szUser
.elseif eax==MAIL_LOGIN
invoke lstrcpy,addr szBuf1,addr szLoginFmt
.elseif eax==MAIL_USER
invoke Base64Encode,addr szUser,addr szBuf1
;invoke MessageBox,NULL,addr @szBuf1,NULL,MB_OK
invoke wsprintf,addr szBuf1,addr szUserPassFmt,addr szBuf1
.elseif eax==MAIL_PASS
invoke Base64Encode,addr szPass,addr szBuf1
;invoke MessageBox,NULL,addr @szBuf1,NULL,MB_OK
invoke wsprintf,addr szBuf1,addr szUserPassFmt,addr szBuf1
.elseif eax==MAIL_FROM
invoke wsprintf,addr szBuf1,addr szFromFmt,addr szFrom
.elseif eax==MAIL_RCPT
invoke wsprintf,addr szBuf1,addr szRcptFmt,addr szRcpt
.elseif eax==MAIL_DATA
invoke lstrcpy,addr szBuf1,addr szDataFmt
.elseif eax==MAIL_DOT
invoke wsprintf,addr szBuf1,addr szTextFmt,addr szFrom,addr szRcpt,addr szSubject,addr szText
.else
invoke lstrcpy,addr szBuf1,addr szQuitFmt
.endif
invoke lstrlen,addr szBuf1
invoke send,hSocket,addr szBuf1,eax,0
invoke MessageBox,hWinMain,addr szBuf1,addr szCaption,MB_OK
.if eax==SOCKET_ERROR
invoke MessageBox,hWinMain,addr szSendErr,addr szCaption,MB_OK
invoke _EnableCtrl,TRUE
invoke ExitThread,NULL
;郵件發送失敗
.endif
ret
_SendCmd endp
_SendThread proc lParam
local @stSin:sockaddr_in
invoke _GetText
invoke _EnableCtrl,FALSE
invoke RtlZeroMemory,addr @stSin,sizeof @stSin
;invoke _GetHostIP,eax
invoke gethostbyname , addr szServer
mov eax, [eax + 12]
mov eax, [eax]
mov eax, [eax]
.if eax==0
invoke MessageBox,hWinMain,addr szServerIPErr,addr szCaption,MB_OK
JMP smtp_ERROR
;SMTP服務器地址錯誤
.endif
mov @stSin.sin_addr,eax
mov @stSin.sin_family,AF_INET
invoke htons,TCP_PORT
mov @stSin.sin_port,ax
invoke socket,AF_INET,SOCK_STREAM,0
mov hSocket,eax
invoke connect,hSocket,addr @stSin,sizeof @stSin
.if eax==SOCKET_ERROR
invoke MessageBox,hWinMain,addr szConnectErr,addr szCaption,MB_OK
JMP smtp_ERROR
;郵件發送失敗
.endif
invoke _WaitFor,220
invoke _SendCmd,MAIL_HELO
invoke _WaitFor,250
invoke _SendCmd,MAIL_LOGIN
invoke _WaitFor,334
invoke _SendCmd,MAIL_USER
invoke _WaitFor,334
invoke _SendCmd,MAIL_PASS
invoke _WaitFor,235
invoke _SendCmd,MAIL_FROM
invoke _WaitFor,250
invoke _SendCmd,MAIL_RCPT
invoke _WaitFor,250
invoke _SendCmd,MAIL_DATA
invoke _WaitFor,354
invoke _SendCmd,MAIL_DOT
invoke _WaitFor,250
invoke _SendCmd,MAIL_QUIT
invoke _WaitFor,221
invoke MessageBox,hWinMain,addr szSendOK,addr szCaption,MB_OK
invoke closesocket,hSocket
invoke _EnableCtrl,TRUE
ret
smtp_ERROR:
invoke MessageBox,hWinMain,addr szSendErr,addr szCaption,MB_OK
invoke _EnableCtrl,TRUE
ret
_SendThread endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL @stWsa: WSADATA
.if uMsg == WM_CLOSE
invoke WSACleanup
invoke EndDialog, hWnd, 0
.elseif uMsg == WM_INITDIALOG
push hWnd
pop hWinMain
invoke WSAStartup,101h,addr @stWsa
invoke LoadIcon, hInstance, IDI_MAIN
invoke SendMessage, hWnd, WM_SETICON, ICON_SMALL, eax
;下面是爲了方便調試,填入預設的各項參數:
invoke SetDlgItemText, hWnd, IDC_EDIT_SMTPSERVER, addr sz1
;invoke SetDlgItemText, hWnd, IDC_EDIT_USERNAME, addr sz2
;invoke SetDlgItemText, hWnd, IDC_EDIT_PASSWORD, addr sz3
;invoke SetDlgItemText, hWnd, IDC_EDIT_FROM, addr sz4
;invoke SetDlgItemText, hWnd, IDC_EDIT_TO, addr sz5
;invoke SetDlgItemText, hWnd, IDC_EDIT_SUBJECT, addr sz6
;invoke SetDlgItemText, hWnd, IDC_EDIT_CONTENT, addr sz7
invoke GetDlgItem,hWnd,IDC_VAl
invoke ShowWindow,eax,SW_HIDE
.elseif uMsg == WM_COMMAND
mov eax,wParam
.if ax==IDC_BUTTON_SEND
push ecx
invoke CreateThread,NULL,0,Offset _SendThread,0,NULL,esp
pop ecx
invoke CloseHandle,eax
.endif
.else
mov eax, FALSE
ret
.endif
mov eax, TRUE
ret
WndProc endp
Start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke DialogBoxParam, hInstance, DlgMain, 0, WndProc, 0
invoke ExitProcess, eax
end Start