Esmtp郵件發送程序

        發送郵件使用的是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

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章