// MySmtp.cpp: implementation of the MySmtp class.
//
/**///////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MailExam.h"
#include "MySmtp.h"
#include "ZBase64.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define COPYRIGHT "Smtp Client" // 版權信息
#define BOUNDARY "www.hust.edu.cn" // 邊界字符串
/**///////////////////////////////////////////////////////////////////////
// Construction/Destruction
/**///////////////////////////////////////////////////////////////////////
MySmtp::MySmtp()
{
}
MySmtp::~MySmtp()
{
}
bool MySmtp::CreateSocket() //創建一個Socket
{
if(WSAStartup(0x0101, &m_WSADATA) != 0) //至此socket版本是2.2,第一個參數也可以是MAKEWORD( 2, 2 )
{
ReleaseSocket();
return false; //創建失敗
}
if( (m_SOCKET= socket(AF_INET,SOCK_STREAM, 0)) == INVALID_SOCKET){
ReleaseSocket();
return false;
}
return true;
}
//通過和比較碼比較來發現是否響應成功
bool MySmtp::CheckResponse(const char* RecvCode)
{
//將收到的和對應的碼字比較,判斷是否發生錯誤
char buf[1024] = {0};
if(recv(m_SOCKET,buf,1024,0) == SOCKET_ERROR)
return false;
else
{
return buf[0] == RecvCode[0] && buf[1] == RecvCode[1]
&&buf[2] == RecvCode[2] ? true : false;
}
}
bool MySmtp::Connect(const string SmtpAddr,const int Port)
{
if(!CreateSocket())
return false;
//得到主機(要發送給的SMTP地址如smtp.sina.com.cn)地址,并將相應的信息寫入m_HOSTENT,
//就是在那個字符串中查找到相應信息并且構造一個結構體HOSTENT(這個記錄了很多信息,不僅僅是地址)
if((m_HOSTENT = gethostbyname((SmtpAddr.c_str()))) == NULL) //將傳入的主機參數給m_HOSTENT
return false;
// AfxMessageBox(m_HOSTENT->h_name); //調試用的,找到HOSTENT的結構內容
// AfxMessageBox(*m_HOSTENT->h_aliases);
if(m_HOSTENT->h_addr_list[0] == NULL) //地址列表為空
{
ReleaseSocket();
return false;
}
// AfxMessageBox(m_HOSTENT->h_addr_list[0]);
// AfxMessageBox(m_HOSTENT->h_addr_list[1]);
memset(&m_SOCKADDR_IN,0,sizeof(m_SOCKADDR_IN));
//將這個SOCKET和主機地址聯系起來,其實WinSoket中,m_HOSTENT 和m_SOCKADDR_IN都是表示的主機地址,也就是目的地的地址
//
m_SOCKADDR_IN.sin_family = AF_INET;
m_SOCKADDR_IN.sin_addr.S_un.S_addr = *(ULONG *) m_HOSTENT->h_addr_list[0];
m_SOCKADDR_IN.sin_port = htons(Port);
// u_long tmp = *(ULONG *) m_HOSTENT->h_addr_list[0];
// char newstring[30];
// sprintf(newstring,"%d",tmp);
// AfxMessageBox(newstring);
//進行連接
if(connect(m_SOCKET,(sockaddr *)&m_SOCKADDR_IN,sizeof(m_SOCKADDR_IN)) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
if(!CheckResponse("220")) return false; //服務準備就緒
//向服務器發送"HELO "+服務器名
string strTmp="HELO "+SmtpAddr+"\r\n";
if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
if(!CheckResponse("250")) return false; //請求操作就緒
return true;
}
void MySmtp::ReleaseSocket()
{
shutdown(m_SOCKET,SD_BOTH);
closesocket(m_SOCKET);
WSACleanup();
}
bool MySmtp::SendData(const string SendFrom, const string SendToList,
const string SenderName, const string ReceiverName,
const string Subject, const string Content )
{
if(SendFrom.empty())
return false; //源地址是空的
if(SendToList.empty())
return false; //目的地址為空
string strTmp;
ZBase64 base64;
//發送MAIL FROM:<abc@xyz.com>
strTmp="MAIL FROM:<"+SendFrom+">\r\n";
if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
if(!CheckResponse("250")) return false;
//發送RCPT To:<abc@xyz.com>
strTmp="RCPT To:<"+SendToList+">\r\n";
if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
if(!CheckResponse("250")) return false;
//發送"DATA\r\n"
if(send(m_SOCKET,"DATA\r\n",strlen("DATA\r\n"),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
if(!CheckResponse("354")) return false;
//"Mail From:SenderName<xxx@mail.com>\r\n"
strTmp="From:"+SenderName+"<"+SendFrom+">\r\n";
//"Subject: 郵件主題\r\n"
strTmp+="Subject:"+Subject+"\r\n";
//"MIME_Version:1.0\r\n"
strTmp+="MIME_Version:1.0\r\n";
//"X-Mailer:Smtp Client By xxx"//版權信息
strTmp+="X-Mailer:"; strTmp+=COPYRIGHT; strTmp+="\r\n";
//"MIME_Version:1.0\r\n"
strTmp+="MIME_Version:1.0\r\n";
//"Content-type:multipart/mixed;Boundary=xxx\r\n\r\n";
strTmp+="Content-type:multipart/mixed;Boundary=";
strTmp+=BOUNDARY;
strTmp+="\r\n\r\n";
//先將HEADER部分發送過去
if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
//郵件主體
strTmp="--";
strTmp+=BOUNDARY;
strTmp+="\r\n";
strTmp+= "Content-type:text/plain;Charset=gb2312\r\n";
strTmp+="Content-Transfer-Encoding:8bit\r\n\r\n";
//郵件內容
strTmp+=Content+"\r\n\r\n";
//將郵件內容發送出去
if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
strTmp="--";
strTmp+=BOUNDARY;
strTmp+="--\r\n.\r\n";
if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
if(!CheckResponse("250")) return false;
//退出
if(send(m_SOCKET,"QUIT\r\n",strlen("QUIT\r\n"),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
if(!CheckResponse("221")) return false;
ReleaseSocket();
return true;
}
bool MySmtp::Validate(const string Username,const string Password)
{
ZBase64 base64;
//發送"AUTH LOGIN"
if(send(m_SOCKET,"AUTH LOGIN\r\n",strlen("AUTH LOGIN\r\n"),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
if(!CheckResponse("334")) return false;
//發送經base64編碼的用戶名
string strUserName=base64.Encode((unsigned char *)Username.c_str(),Username.length())+"\r\n";
if(send(m_SOCKET,strUserName.c_str(),strUserName.length(),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
if(!CheckResponse("334")) return false;
//發送經base64編碼的密碼
string strPassword=base64.Encode((unsigned char *)Password.c_str(),Password.length())+"\r\n";
if(send(m_SOCKET,strPassword.c_str(),strPassword.length(),0) == SOCKET_ERROR)
{
ReleaseSocket();
return false;
}
if(!CheckResponse("235")) return false;
return true;
}