计算机网络实验SMTP邮件发送系统socket编程
实验四邮件客户端实现
1316-30-何珊珊[实验名称]:邮件客户端实现
[实验器材]:
与因特网连接的计算机网络系统;
主机操作系统为Windows7;
VC6
[实验内容]::要求学生利用已有的套接字常识使用SMTP和POP3的任一种协议,实现对于特定邮件服务器(mail.163)的发送邮件功能。
[实验步骤]:
在VC6中搭建工程,因为SMTP中用户名和密码都要经过64位编码的处理,所以工程中除了对SMTP的编程外还需要一个64为编码的转换函数。以下是代码:
MailTest.cpp:
#include "stdafx.h"
#include "SMTP.h"
int main(int argc, char* argv[])
{
char to[256];char title[256];char body[1024];char strServer[128];char strUser[128];char strPsw[128];char strSndMail[128];
CSMTP smtp;
smtp.Initialize();
/*char to[]="heshanshan2512@https://www.360docs.net/doc/e717386851.html,";
char title[]="test";
char body[]="heshanshan09211595";
char strServer[]="https://www.360docs.net/doc/e717386851.html,";
char strUser[]="shan_shan2512";
char strPsw[]="shanshan091756";
char strSndMail[]="shan_shan2512@https://www.360docs.net/doc/e717386851.html,";*/ //提示输入的信息
printf("strServer:");scanf("%s",strServer);
printf("strSndMail:");scanf("%s",strSndMail);
printf("strUser:");scanf("%s",strUser);
printf("strPsw:");scanf("%s",strPsw);
printf("to:");scanf("%s",to);
printf("title:");scanf("%s",title);
printf("body:");scanf("%s",body);
if (smtp.MailSend(to,title,body,strServer,strUser,strPsw,strSndMail))
{
printf("successful\n"); //发送成功
}
else
{
printf("fail\n"); //发送失败
}
return 0;
}
SMTP.h:
#pragma once
#include
#include "Base64.h"
#include
#pragma comment(lib, "Ws2_32")
#include
#include
using namespace std;
class CSMTP
{
public:
CSMTP(void);
~CSMTP(void);
BOOL Initialize(void);
BOOL MailSend(string to, string title, string body, string strServer, string strUser, string strPsw, string strSndMail);
private:
SOCKET m_socket;
};
SMTP.cpp:
#include "stdafx.h"
#include "SMTP.h"
#define MAX_PACKET_SIZE 1024
CSMTP::CSMTP(void) //构造函数{
m_socket = NULL;
}
CSMTP::~CSMTP() //析构函数{
}
BOOL CSMTP::Initialize() //入口函数
{
WORD wVersionRequested; //用WSAStartup函数加载套接字库,并进行版本协商
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
return FALSE;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 )
{
WSACleanup();
return FALSE;
}
return TRUE;
}
BOOL CSMTP::MailSend(string to, string title, string body, string strServer, string strUser, string strPsw, string strSndMail)
{
sockaddr_in addrSmtp; //配置服务端地址信息
const char *smtpServer = strServer.c_str();
const char *smtpUser = strUser.c_str();
const char *smtpPass = strPsw.c_str();
const char *senderMail = strSndMail.c_str();
if(m_socket != NULL) //判断socket是否可用,若不可用重新创建
{
closesocket(m_socket);
m_socket = NULL;
}
if(m_socket == NULL)
{
m_socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//创建一个客户端的套接字
}
struct in_addr in;
hostent *hosts = gethostbyname(smtpServer); //域名转换
if (hosts != NULL)
{
memcpy((char**)&(in),hosts->h_addr,hosts->h_length); //把主机地址付给in }
else
{
return FALSE;
}
string addrc = inet_ntoa(in);//将网络字节序转换成应用的格式
addrSmtp.sin_family = AF_INET; //配置服务端地址信息
addrSmtp.sin_addr.s_addr = in.S_un.S_addr;
addrSmtp.sin_port = htons(25); //SMTP的端口号为25
int ret = 0;
ret = connect(m_socket, (LPSOCKADDR)&addrSmtp, sizeof(addrSmtp)); //与服务端进行连接
if(ret == SOCKET_ERROR)//连接失败
{
char *err = new char[1024];
sprintf(err,"连接失败%d",GetLastError());
printf("%s\n",err);
return FALSE;
}
char s[MAX_PACKET_SIZE];
char r[MAX_PACKET_SIZE];
memset((void*)s,0,MAX_PACKET_SIZE);
memset((void*)r,0,MAX_PACKET_SIZE);
int len;
string response;
//等待服务器回应
len = recv(m_socket,(char*)r,MAX_PACKET_SIZE,0);
if(len)
{
response = r;
int position = response.substr(0,3).compare("220");//判断返回信息的前三个字符是否为220,如果是,表示连接服务器成功
if(position == 0)
{
len = sprintf((char*)s,"helo %s\r\n", strUser.c_str());//将用户名赋给s并发送给服务器
len = send(m_socket,s,strlen(s),0);
}
else
{
printf(r);
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
len = recv(m_socket,(char*)r,MAX_PACKET_SIZE,0);//接收服务器返回的信息
if(len)
{
response = r;
int position = response.substr(0,3).compare("250");//判断返回信息的前三个字符是否为250,如果是,表示此时可以登录了
if(position == 0)
{
len = sprintf((char*)s,"AUTH LOGIN\r\n");//将要登陆的命令发送给服务器
len = send(m_socket,s,strlen(s),0);
}
else
{
printf(r);
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
//等待登录回应
len = recv(m_socket,(char*)r,MAX_PACKET_SIZE,0); //接收服务器返回的信息
if(len)
{
response = r;
int position = response.substr(0,3).compare("334");//判断返回信息的前三个字符是否为334,如果是,表示此时可以输入64位编码过的用户名了
if(position == 0)
{
unsigned char *dst = (unsigned char*)smtpUser;
len = strlen((char*)dst);
string strTmp = Base64::base64_encode(dst,len);//进行64位编码
len = sprintf((char*)s,"%s\r\n",(const char*)strTmp.c_str());
len = send(m_socket,s,strlen(s),0);//发送编码过的用户名
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
printf(r);
return FALSE;
}
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
//发送完用户名后等待回应
len = recv(m_socket,(char*)r,MAX_PACKET_SIZE,0);//发送编码过的密码,代码和发
送用户名时的方式类似
if(len)
{
response = r;
int position = response.substr(0,3).compare("334");
if(position == 0)
{
unsigned char *dst = (unsigned char*)smtpPass;
len = strlen((char*)dst);
string strTmp = Base64::base64_encode(dst,len);
len = sprintf((char*)s,"%s\r\n",(const char*)strTmp.c_str());
len = send(m_socket,s,strlen(s),0);
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
printf(r);
return FALSE;
}
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
//发送完密码后等待回应看是否登录成功
len = recv(m_socket,(char*)r,MAX_PACKET_SIZE,0);
if(len)
{
response = r;
int position = response.substr(0,3).compare("235");
if(position == 0)
{
len = sprintf((char*)s,"MAIL FROM: <%s>\r\n",senderMail);
len = send(m_socket,s,strlen(s),0); //发送本地邮箱的地址}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
printf(r);
return FALSE;
}
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
//header部份
len = recv(m_socket,(char*)r,MAX_PACKET_SIZE,0);
if(len)
{
response = r;
int position = response.substr(0,3).compare("250");
if(position == 0)
{
len = sprintf((char*)s,"RCPT TO: <%s>\r\n",to.c_str());//发送要发送的邮箱的地址
len = send(m_socket,s,strlen(s),0);
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
printf(r);
return FALSE;
}
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
//header部份
len = recv(m_socket,(char*)r,MAX_PACKET_SIZE,0);
if(len)
{
response = r;
int position = response.substr(0,3).compare("250");
if(position == 0)
{
len = sprintf((char*)s,"DATA\r\n");//发送data向服务器发送邮件内容的申请
len = send(m_socket,s,strlen(s),0);
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
printf(r);
return FALSE;
}
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
len = recv(m_socket,(char*)r,MAX_PACKET_SIZE,0);
if(len)
{
response = r;
int position = response.substr(0,3).compare("354");
if(position == 0)
{
char date_string[MAX_PACKET_SIZE];
time_t seconds;//调用本地时间
time(&seconds);
strftime(date_string, MAX_PACKET_SIZE,
"%a, %d %b %y %H:%M:%S +0800",
localtime(&seconds));
sprintf((char*)s,"From: %s\r\nT o: %s\r\nDate: %s\r\nSubject: %s\r\n\r\nX-Mailer: %s\r\ nX-Priority: %s\r\nMIME-Version: 1.0\r\nContent-type: multipart/mixed;
boundary=\"%s\"\r\n\r\n",
senderMail,to.c_str(),date_string,title.c_str(),"SMailer","3","#BOUNDARY#");
len = send(m_socket,s,strlen(s),0);
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
printf(r);
return FALSE;
}
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
//邮件正文
sprintf((char*)s,"--%s\r\nContent-Type: %s\r\nContent-Disposition: %s\r\nContent-Tran sfer-Encoding: %s\r\n\r\n%s\r\n\r\n","#BOUNDARY#","text/plain;
charset=gb2312","","8bit",body.c_str());
len = send(m_socket,s,strlen(s),0);
//邮件结束
sprintf((char*)s,"\r\n--%s--\r\n.\r\n","#BOUNDARY#");
len = send(m_socket,s,strlen(s),0);
len = recv(m_socket,(char*)r,MAX_PACKET_SIZE,0);
if(len)
{
response = r;
int position = response.substr(0,3).compare("250");
if(position == 0)
{
//退出连接
sprintf((char*)s,"QUIT\r\n");
len = send(m_socket,s,strlen(s),0);
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
printf(r);
return FALSE;
}
}
else
{
if(m_socket)
closesocket(m_socket);
m_socket = NULL;
return FALSE;
}
//断开连接
len = recv(m_socket,(char*)r,MAX_PACKET_SIZE,0);
if(len)
{
response = r;
int position = response.substr(0,3).compare("221");