• Linux C SMTP POP3 极简陋邮件客户端


    以前以为协议非常高神,但做了这个之后发现还好,没想象的那么艰难。

    先要了解邮件的原理

    再者就是上面2协议

    可以先用telnet测试一下,以初步了解那2协议:http://hi.baidu.com/343243581/item/113c7212ced7e0e05e53b1d8

    实现大致思想,SMTP,POP3相关介绍:http://www.doc88.com/p-929298657611.html

    主要人家都讲得很好很详细了,天冷,我也懒得打字了。

    /*这里面放一些公共的头文件*/
    
    #include <stdio.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>  //字节序转换函数
    #include <netdb.h>  //地址查询
    
    extern int BUFFMAX;
    extern void recvCntInfo(int cnt,char thisBuff[]);
    头文件
    #include <stdio.h>
    
    /*下面定义常量*/
    const int BUFFMAX=2000;   //接受消息缓冲区大小
    
    /*处理的函数*/
    
    void recvCntInfo(int cnt,char thisBuff[])
    {
      if(cnt==-1)
      {
        printf("recv出错,退出程序!
    ");
        exit(0);
      }
      else if(cnt==0)
      {
        printf("无可用消息或对方已经按序结束!
    ");
      }
      else
      {
        thisBuff[cnt]='';
        printf("发回:%s
    ",thisBuff);
      }
    }
    一点自定义东西
    #include "myHead.h"
    
    static const char* SEND_DES="smtp.163.com";  //访问163邮箱
    static const int SEND_PORT=25;  //smtp的端口号
    
    /*下面定义邮箱命令的标号*/
    static const int HELO=0;
    static const int AUTHLOGIN=1;
    static const int USERNAME=2;
    static const int PASSWORD=3;
    static const int MAILFROM=4;
    static const int RCPTTO=5;
    static const int DATA=6;
    static const int CONTENT=7;
    static const int QUIT=8;
    
    int main(void)
    {
      /*主机信息*/
      struct hostent* host;  //这里面的地址采用网络字节序
      if((host=gethostbyname(SEND_DES))==NULL)  //获得域名对应的主机信息
      {
        printf("gethostbyname 错误!程序退出!
    ");
        exit(1);
      }
      printf("
    域名对应主机名:%s
    ",host->h_name);
      
      /*创建socket*/
      int sockfd=socket(AF_INET,SOCK_STREAM,0);  //ipv4 tcp
      if(sockfd==-1)
      {
        printf("socket 创建错误!
    ");
        exit(1);
      }
      printf("socket 创建成功!
    ");
      
      /*目的地地址信息*/
      struct sockaddr_in serAddr;
      serAddr.sin_family=AF_INET;  //ipv4
      serAddr.sin_port=htons(SEND_PORT);  //端口号变换成网络字节须
      serAddr.sin_addr=*((struct in_addr *)host->h_addr);//server ip 注意这里的细节东西
      bzero(&(serAddr.sin_zero),8);   //加0以成功转化为struct sockaddr类型
    
    
      /*下面进行操作,共分为三大步:建立连接,对话及发送邮件信息,关闭连接*/
      char buff[BUFFMAX];
      int cnt;
      
      /*第一步:建立连接*/
      printf("
    请求:连接IP地址 %s 端口 %d 的服务....   ",SEND_DES,SEND_PORT);
      if((connect(sockfd,(struct sockaddr*)&serAddr,sizeof(struct sockaddr)))==-1)  //结构体强制转换
      {
        printf("connect 错误!
    ");
        exit(1);
      }
      printf("connect 成功!
    ");
      
      cnt=recv(sockfd,buff,BUFFMAX,0);  //接受请求这个端口后的回答
      recvCntInfo(cnt,buff);
      
      /*第二步:对话及发送邮件信息*/
      
      /*初始化每次对话要发送的信息*/
      char* msg[9]={""}; //分别对应每次的发送消息
      msg[HELO]="helo 163
    ";  //打招呼
      msg[AUTHLOGIN]="auth login
    ";  //登录命令
      msg[USERNAME]="MTU2MDg0MTk0NTA=
    ";  //已经转化为base64编码方式
      msg[PASSWORD]="MjY2MTQ3
    ";   //base64编码方式
      msg[MAILFROM]="MAIL FROM:<15608419450@163.com>
    ";  //发邮件人
      msg[RCPTTO]="RCPT TO:<1150614705@qq.com>
    ";  //预期接受人
      msg[DATA]="data
    ";  //准备发送邮件数据的命令
      msg[CONTENT]="FROM:15608419450@163.com
    TO:1150614705@qq.com
    Subject:163 to qq
    
    fffdfdfddddfdd HELLO! 163 TO QQ EMAIL!
    Now it is 20:44
    .
    ";
      msg[QUIT]="quit
    "; 
      
      /*下面开始发送各个消息*/
      int step;
      for(step=HELO;step<=CONTENT;step++)  //每个step对应一次发送消息及接受消息的对话
      {
        printf("< %d > 发送信息如下:
    %s",step,msg[step]);
        if((send(sockfd,msg[step],strlen(msg[step]),0))==-1)  //注意这里一定要用strlen()而不是sizeof....
        {
          printf("send 出错!
    ");
        }
        printf("send 成功! 等待回发....
    ");
      
        cnt=recv(sockfd,buff,BUFFMAX,0);
        recvCntInfo(cnt,buff);
      }
      
      
      /*第三步,退出程序*/ 
      printf("邮件已成功从此客户端发送到邮件服务器!现在发送退出连接邮件服务器消息:
    ");
      if((send(sockfd,msg[QUIT],strlen(msg[QUIT]),0))==-1)  //注意这里一定要用strlen()而不是sizeof....
      {
        printf("quit 发送出错!
    ");
      }
      printf("quit 发送成功! 等待回发....
    ");
      
      cnt=recv(sockfd,buff,BUFFMAX,0);
      recvCntInfo(cnt,buff);
    }
    发送程序
    #include "myHead.h"
    
    const char* GET_DES="pop3.163.com";
    const int GET_PORT=110;
    
    /*下面定义常量,其实标号不重要,只是当作下标,好记*/
    static const int USR=0;
    static const int PSW=1;
    static const int QUIT=2;
    static const int LIST=3;
    static const int RETR=4;
    static const int DELE=5;
    static const int RSET=6;
    
    static char* msg[7]={""};   //装指向字符串的指针数组,仅此文件可见
    
    
    int showOprate(void);  //显示选择,返回输入项
    
    int main(void)
    {
      /*初始化命令*/
      msg[USR]="user 15608419450@163.com
    ";
      msg[PSW]="pass 266147
    ";
      msg[QUIT]="quit
    ";
      msg[LIST]="LIST
    ";
      msg[RSET]="RSET
    ";
      
      /*主机信息*/
      struct hostent* host;  //这里面的地址采用网络字节序
      if((host=gethostbyname(GET_DES))==NULL)  //获得域名对应的主机信息
      {
        printf("gethostbyname 错误!程序退出!
    ");
        exit(1);
      }
      printf("
    域名对应主机名:%s
    ",host->h_name);
      
      /*创建socket*/
      int sockfd=socket(AF_INET,SOCK_STREAM,0);  //ipv4 tcp
      if(sockfd==-1)
      {
        printf("socket 创建错误!
    ");
        exit(1);
      }
      printf("socket 创建成功!
    ");
      
      /*目的地地址信息*/
      struct sockaddr_in serAddr;
      serAddr.sin_family=AF_INET;  //ipv4
      serAddr.sin_port=htons(GET_PORT);  //端口号变换成网络字节须
      serAddr.sin_addr=*((struct in_addr *)host->h_addr);//server ip 注意这里的细节东西
      bzero(&(serAddr.sin_zero),8);   //加0以成功转化为struct sockaddr类型
      
      /*下面进行操作,共分为三个状态*/
      char buff[BUFFMAX];
      int cnt;
      
      /*一:认证状态*/
      /*先连接主机*/
      printf("
    请求:连接IP地址 %s 端口 %d 的服务....   ",GET_DES,GET_PORT);
      if((connect(sockfd,(struct sockaddr*)&serAddr,sizeof(struct sockaddr)))==-1)  //结构体强制转换
      {
        printf("connect 错误!
    ");
        exit(1);
      }
      printf("connect 成功!
    ");
      
      cnt=recv(sockfd,buff,BUFFMAX,0);  //接受请求这个端口后的回答
      recvCntInfo(cnt,buff);
        
      /*再输入用户名和密码*/
      printf("下面登录邮箱:
    ");
      int step=USR;
      for(;step<=PSW;step++)  //其实就2步发送
      {
        printf("< %d > 发送信息如下:
    %s",step,msg[step]);
        if((send(sockfd,msg[step],strlen(msg[step]),0))==-1)  //注意这里一定要用strlen()而不是sizeof....
        {
          printf("send 出错!
    ");
        }
        printf("send 成功! 等待回发....
    ");
      
        cnt=recv(sockfd,buff,BUFFMAX,0);
        recvCntInfo(cnt,buff);
      }
      
      /*二,处理状态*/
      int choise=showOprate();
      while(choise!=0)  //循环显示
      {
        /*下面处理输入的情况*/
        if(choise>4|choise<0)
        {
          printf("选择 %d 为非法输入!请重新输入!
    ",choise);
        }
        else
        {
          int sendChoise;   //发送的消息对应的下标
          int val;  //命令的参数
          char sendStr[100]={''};   //待发送的字符串
          
          switch(choise)
          {
            case 1:sendChoise=LIST;break;  //仅仅列表
            case 2:{                       
                     printf("请输入要返回的邮件编号:");
                     scanf("%d",&val);   //需要编号
                     getchar();  
                     sprintf(sendStr,"%s%d%c","retr ",val,'
    ');  //注意也要把换行符加进去
                     sendChoise=RETR;
                     msg[RETR]=sendStr;
                     break;
                   }
            case 3:{
                     printf("请输入要删除的邮件编号");
                     scanf("%d",&val);   //需要编号
                     getchar();  
                     sprintf(sendStr,"%s%d%c","dele ",val,'
    ');
                     sendChoise=DELE;
                     msg[DELE]=sendStr;
                     break;
                   }
            case 4:sendChoise=RSET;break;
          }
          
          printf("发送请求:
    %s",msg[sendChoise]);
          if((send(sockfd,msg[sendChoise],strlen(msg[sendChoise]),0))==-1)  //注意这里一定要用strlen()而不是sizeof....
          {
            printf("send 出错!
    ");
          }
          printf("send 成功! 等待回发....
    ");
      
          cnt=recv(sockfd,buff,BUFFMAX,0);
          recvCntInfo(cnt,buff);
        }
        
        choise=showOprate();
      }
      
      /*三,更新状态*/ 
      printf("操作结束,现在发送退出连接邮件服务器消息以完成更新操作
    ");
      if((send(sockfd,msg[QUIT],strlen(msg[QUIT]),0))==-1)  //注意这里一定要用strlen()而不是sizeof....
      {
        printf("quit 发送出错!
    ");
      }
      printf("quit 发送成功! 等待回发....
    ");
      
      cnt=recv(sockfd,buff,BUFFMAX,0);
      recvCntInfo(cnt,buff);
    }
    
    int showOprate(void)
    {
      printf("
    邮件操作选项如下:
    ");
      printf("1:LIST    2:RETR
    ");
      printf("3:DELE    4:RSET
    ");
      printf("请输入操作序号(0结束):");
      int choise;
      scanf("%d",&choise);
      getchar();
      return choise;
    }
    接收程序
    exec:send get
    
    send:send.o myFunc.o
        gcc send.o myFunc.o -o send
    get:get.o myFunc.o
        gcc get.c myFunc.o -o get
    
    send.o:send.c myHead.h
        gcc send.c -c
    get.o:get.c myHead.h
        gcc get.c -c
    myFunc.0:myFunc.c
        gcc myFunc.c -c
    make工程管理

     那个。。。貌似有我的邮箱用户名和密码,我也不用。。。哈哈

  • 相关阅读:
    C++之容器
    C++之复制控制
    TCP的3次握手/4次握手
    linux编程之多线程编程
    linux编程之信号
    linux编程之共享内存
    MySQL数据库优化
    MySQL存储引擎InnoDB与Myisam
    Redis--持久化
    Redis 请求应答模式和往返延时 Pipelining
  • 原文地址:https://www.cnblogs.com/jiayith/p/3516463.html
Copyright © 2020-2023  润新知