fuchou-angle 发表于 2009-7-3 10:04:34

编写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]
查看完整版本: 编写SMTP匿名邮件客户端(罗文涛)