编写SMTP匿名邮件客户端(罗文涛)
1 技术要点:实现简单的邮件发送功能的,基于SMTP协议的匿名邮件客户端程序,了解SMTP协议和邮件服务器接收和发送邮件的的原理.
2 关键代码
//发送邮件函数
void SendMail()
{
WSADATA wsa;
struct hostent *pHostent = NULL;
SOCKET server = INVALID_SOCKET;
struct sockaddr_in ServerAddr;
int ret = 0;
char Buffer={0};
char TmpUse,TmpPWD,TmpFromAdd,TmpToAdd;
printf("\n ......................邮件发送信息....................\n\n");
//初始化Socket
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
printf("初始化Socket失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
}
//创建Socket
server = socket(AF_INET, SOCK_STREAM, 0);
if (server == INVALID_SOCKET)
{
printf("创建Socket失败...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
}
//获取SMTP邮件服务器地址
pHostent = gethostbyname(HostName);
if (pHostent == NULL)
{
printf("获取邮件服务器名称失败...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
//将获取的SMTP邮件服务器地址转化为ip地址
ServerAddr.sin_family = AF_INET;
memcpy(&ServerAddr.sin_addr.S_un.S_addr,pHostent->h_addr_list, pHostent->h_length);
ServerAddr.sin_port = htons(25);
//通过IP地址连接服务器
ret = connect(server, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
if (ret == SOCKET_ERROR)
{
printf("连接邮件服务器失败...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
printf("正在连接 %s...\n", inet_ntoa(ServerAddr.sin_addr));
ZeroMemory(Buffer, sizeof(Buffer));
ret = recv(server, Buffer, sizeof(Buffer), 0);
if (ret == SOCKET_ERROR)
{
printf("邮件服务器返回连接信息失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("邮件服务器返回连接信息:%s\n", Buffer);
}
//发送HELO Server信息
ret = send(server, "HELO Server\r\n", strlen("HELO Server\r\n"), 0);
if (ret == SOCKET_ERROR)
{
printf("发送Hello Server欢迎信息失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("正在发送HELLO Server欢迎信息!......\n");
}
ZeroMemory(Buffer, sizeof(Buffer));
ret = recv(server, Buffer, sizeof(Buffer), 0);
if (ret == SOCKET_ERROR)
{
printf("邮件服务器返回HELLO Server信息失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("邮件服务器返回helloServer信息:%s\n", Buffer);
}
//发送AUTH LOGIN信息
ret = send(server, "AUTH LOGIN\r\n", strlen("AUTH LOGIN\r\n"), 0);
if (ret == SOCKET_ERROR)
{
printf("发送AUTH LOGIN信息失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("正在发送AUTH LOGIN信息!......\n");
}
ZeroMemory(Buffer, sizeof(Buffer));
ret = recv(server, Buffer, sizeof(Buffer), 0);
if (ret == SOCKET_ERROR)
{
printf("邮件服务器返回AUTH LOGIN信息失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("邮件服务器返回AUTH LOGIN信息:%s\n", Buffer);
}
//将用户名经行Base64加密以后发送
string strEncodeUser = bs.base64_encode(User);
sprintf(TmpUse,"%s\r\n",strEncodeUser.c_str());
ret = send(server,TmpUse, strlen(TmpUse), 0);
if (ret == SOCKET_ERROR)
{
printf("发送用户名失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("正在发送用户名!...\n");
}
ZeroMemory(Buffer, sizeof(Buffer));
ret = recv(server, Buffer, sizeof(Buffer), 0);
if (ret == SOCKET_ERROR)
{
printf("邮件服务器返回用户名信息失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("服务器返回用户名信息:%s\n", Buffer);
}
//将密码进行Base64加密以后发送
string strEncodePWD = bs.base64_encode(PWD);
sprintf(TmpPWD,"%s\r\n",strEncodePWD.c_str());
ret = send(server,TmpPWD, strlen(TmpPWD), 0);
if (ret == SOCKET_ERROR)
{
printf("发送密码失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("正在发送密码!...\n");
}
ZeroMemory(Buffer, sizeof(Buffer));
ret = recv(server, Buffer, sizeof(Buffer), 0);
if (ret == SOCKET_ERROR)
{
printf("邮件服务器返回密码信息失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("服务器返回密码信息:%s\n", Buffer);
}
//设置服务器的Mail From地址(此处必须您的真实的邮件发送地址)
sprintf(TmpFromAdd,"MAIL FROM: <%s>\r\n",FromAdds);
ret = send(server, TmpFromAdd, strlen(TmpFromAdd), 0);
if (ret == SOCKET_ERROR)
{
printf("发送Mail From:失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("正在发送Mail From: %s\n",FromAdds);
}
ZeroMemory(Buffer, sizeof(Buffer));
ret = recv(server, Buffer, sizeof(Buffer), 0);
if (ret == SOCKET_ERROR)
{
printf("服务器返回邮件发送地址错误!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("服务器返回Mail From信息:%s\n", Buffer);
}
//设置邮件服务器的接受人地址
sprintf(TmpToAdd,"RCPT TO: <%s>\r\n",SendAdds);
ret = send(server, TmpToAdd, strlen(TmpToAdd), 0);
if (ret == SOCKET_ERROR)
{
printf("发送RCPT TO地址错误!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("正在发送RCPT TO地址为%s\n",SendAdds);
}
ZeroMemory(Buffer, sizeof(Buffer));
ret = recv(server, Buffer, sizeof(Buffer), 0);
if (ret == SOCKET_ERROR)
{
printf("邮件服务器返回Rcpt to错误...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("服务器返回Rcpt to信息:%s\n", Buffer);
}
//向邮件服务器发送"发送日期时间"信息
ret = send(server, "Data\r\n", strlen("Data\r\n"), 0);
if (ret == SOCKET_ERROR)
{
printf("发送(Data)时间错误!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("正在发送(Data)时间...\n");
}
ZeroMemory(Buffer, sizeof(Buffer));
ret = recv(server, Buffer, sizeof(Buffer), 0);
if (ret == SOCKET_ERROR)
{
printf("服务器返回(Data)时间失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("服务器返回(Data)时间:%s\n", Buffer);
}
//开始发送邮件数据(邮件体+邮件头)
//该处的MailData是邮件数据,其中的邮件头中
//"From: \"发送者昵称\"<xxx@126.com>\r\n"可以自定义
ret = send(server, MailData, strlen(MailData), 0);
if (ret == SOCKET_ERROR)
{
printf("发送邮件(MailData)正文失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("正在发送邮件(MailData)正文:\n%s\n",MailData);
}
ZeroMemory(Buffer, sizeof(Buffer));
ret = recv(server, Buffer, sizeof(Buffer), 0);
if (ret == SOCKET_ERROR)
{
printf("服务器返回邮件(MailData)正文失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("服务器返回邮件(MailData)正文:\n%s\n", Buffer);
}
//发送完毕,向服务器发送退出命令
ret = send(server, "QUIT\r\n", strlen("QUIT\r\n"), 0);
if (ret == SOCKET_ERROR)
{
printf("发送(QUIT)断开连接命令失败!...\n");
if (server != INVALID_SOCKET)
{
closesocket(server);
}
WSACleanup();
gets(os);
exit(1);
}
else
{
printf("成功断开服务器连接!...\n");
}
printf("\n发送邮件完成!...\n");
gets (os);
}
3 主要原理
伪造邮件数据格式的,文件头信息"From: \"发送者昵称\"<xxx@126.com>\r\n"
邮件头的具体格式:
"From: \"发送者昵称\"<xxx@126.com>\r\n"
"To: \"收件人昵称 \"<xxx @126.com>\r\n"
"Date: Mon, 25 Oct 2005 14:24:27 +0800\r\n"
"Subject:主题内容\r\n\r\n"
邮件体的格式:
"邮件体 \r\n.\r\n"
将邮件头和邮件体连成一个字符串发送到邮件服务器,自此整个邮件匿名邮件的发送过程就基本完成了
126,163等邮箱都对新注册的用户都做了SMTP/POP3的限制,不允许用户直接访问SMTP/POP3协议了.如果新注册用户访问该SMTP服务器,就会出现(550 用户被锁定)的错误提示,大家可以测试一下.言归正传,如果要QQ邮箱支持匿名发送邮件,就必须在,”QQ邮箱->设置->账户->POP3/IMAP/SMTP服务”这里开启QQ邮箱的SMTP服务,
页:
[1]