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出错,退出程序!\n");
    exit(0);
  }
  else if(cnt==0)
  {
    printf("无可用消息或对方已经按序结束!\n");
  }
  else
  {
    thisBuff[cnt]='\0';
    printf("发回:%s\n",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 错误!程序退出!\n");
    exit(1);
  }
  printf("\n域名对应主机名:%s\n",host->h_name);
  
  /*创建socket*/
  int sockfd=socket(AF_INET,SOCK_STREAM,0);  //ipv4 tcp
  if(sockfd==-1)
  {
    printf("socket 创建错误!\n");
    exit(1);
  }
  printf("socket 创建成功!\n");
  
  /*目的地地址信息*/
  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("\n请求:连接IP地址 %s 端口 %d 的服务....   ",SEND_DES,SEND_PORT);
  if((connect(sockfd,(struct sockaddr*)&serAddr,sizeof(struct sockaddr)))==-1)  //结构体强制转换
  {
    printf("connect 错误!\n");
    exit(1);
  }
  printf("connect 成功!\n");
  
  cnt=recv(sockfd,buff,BUFFMAX,0);  //接受请求这个端口后的回答
  recvCntInfo(cnt,buff);
  
  /*第二步:对话及发送邮件信息*/
  
  /*初始化每次对话要发送的信息*/
  char* msg[9]={""}; //分别对应每次的发送消息
  msg[HELO]="helo 163\n";  //打招呼
  msg[AUTHLOGIN]="auth login\n";  //登录命令
  msg[USERNAME]="MTU2MDg0MTk0NTA=\n";  //已经转化为base64编码方式
  msg[PASSWORD]="MjY2MTQ3\n";   //base64编码方式
  msg[MAILFROM]="MAIL FROM:<15608419450@163.com>\n";  //发邮件人
  msg[RCPTTO]="RCPT TO:<1150614705@qq.com>\n";  //预期接受人
  msg[DATA]="data\n";  //准备发送邮件数据的命令
  msg[CONTENT]="FROM:15608419450@163.com\nTO:1150614705@qq.com\nSubject:163 to qq\n\nfffdfdfddddfdd HELLO! 163 TO QQ EMAIL!\nNow it is 20:44\n.\n";
  msg[QUIT]="quit\n"; 
  
  /*下面开始发送各个消息*/
  int step;
  for(step=HELO;step<=CONTENT;step++)  //每个step对应一次发送消息及接受消息的对话
  {
    printf("< %d > 发送信息如下:\n%s",step,msg[step]);
    if((send(sockfd,msg[step],strlen(msg[step]),0))==-1)  //注意这里一定要用strlen()而不是sizeof....
    {
      printf("send 出错!\n");
    }
    printf("send 成功! 等待回发....\n");
  
    cnt=recv(sockfd,buff,BUFFMAX,0);
    recvCntInfo(cnt,buff);
  }
  
  
  /*第三步,退出程序*/ 
  printf("邮件已成功从此客户端发送到邮件服务器!现在发送退出连接邮件服务器消息:\n");
  if((send(sockfd,msg[QUIT],strlen(msg[QUIT]),0))==-1)  //注意这里一定要用strlen()而不是sizeof....
  {
    printf("quit 发送出错!\n");
  }
  printf("quit 发送成功! 等待回发....\n");
  
  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\n";
  msg[PSW]="pass 266147\n";
  msg[QUIT]="quit\n";
  msg[LIST]="LIST\n";
  msg[RSET]="RSET\n";
  
  /*主机信息*/
  struct hostent* host;  //这里面的地址采用网络字节序
  if((host=gethostbyname(GET_DES))==NULL)  //获得域名对应的主机信息
  {
    printf("gethostbyname 错误!程序退出!\n");
    exit(1);
  }
  printf("\n域名对应主机名:%s\n",host->h_name);
  
  /*创建socket*/
  int sockfd=socket(AF_INET,SOCK_STREAM,0);  //ipv4 tcp
  if(sockfd==-1)
  {
    printf("socket 创建错误!\n");
    exit(1);
  }
  printf("socket 创建成功!\n");
  
  /*目的地地址信息*/
  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("\n请求:连接IP地址 %s 端口 %d 的服务....   ",GET_DES,GET_PORT);
  if((connect(sockfd,(struct sockaddr*)&serAddr,sizeof(struct sockaddr)))==-1)  //结构体强制转换
  {
    printf("connect 错误!\n");
    exit(1);
  }
  printf("connect 成功!\n");
  
  cnt=recv(sockfd,buff,BUFFMAX,0);  //接受请求这个端口后的回答
  recvCntInfo(cnt,buff);
    
  /*再输入用户名和密码*/
  printf("下面登录邮箱:\n");
  int step=USR;
  for(;step<=PSW;step++)  //其实就2步发送
  {
    printf("< %d > 发送信息如下:\n%s",step,msg[step]);
    if((send(sockfd,msg[step],strlen(msg[step]),0))==-1)  //注意这里一定要用strlen()而不是sizeof....
    {
      printf("send 出错!\n");
    }
    printf("send 成功! 等待回发....\n");
  
    cnt=recv(sockfd,buff,BUFFMAX,0);
    recvCntInfo(cnt,buff);
  }
  
  /*二,处理状态*/
  int choise=showOprate();
  while(choise!=0)  //循环显示
  {
    /*下面处理输入的情况*/
    if(choise>4|choise<0)
    {
      printf("选择 %d 为非法输入!请重新输入!\n",choise);
    }
    else
    {
      int sendChoise;   //发送的消息对应的下标
      int val;  //命令的参数
      char sendStr[100]={'\0'};   //待发送的字符串
      
      switch(choise)
      {
        case 1:sendChoise=LIST;break;  //仅仅列表
        case 2:{                       
                 printf("请输入要返回的邮件编号:");
                 scanf("%d",&val);   //需要编号
                 getchar();  
                 sprintf(sendStr,"%s%d%c","retr ",val,'\n');  //注意也要把换行符加进去
                 sendChoise=RETR;
                 msg[RETR]=sendStr;
                 break;
               }
        case 3:{
                 printf("请输入要删除的邮件编号");
                 scanf("%d",&val);   //需要编号
                 getchar();  
                 sprintf(sendStr,"%s%d%c","dele ",val,'\n');
                 sendChoise=DELE;
                 msg[DELE]=sendStr;
                 break;
               }
        case 4:sendChoise=RSET;break;
      }
      
      printf("发送请求:\n%s",msg[sendChoise]);
      if((send(sockfd,msg[sendChoise],strlen(msg[sendChoise]),0))==-1)  //注意这里一定要用strlen()而不是sizeof....
      {
        printf("send 出错!\n");
      }
      printf("send 成功! 等待回发....\n");
  
      cnt=recv(sockfd,buff,BUFFMAX,0);
      recvCntInfo(cnt,buff);
    }
    
    choise=showOprate();
  }
  
  /*三,更新状态*/ 
  printf("操作结束,现在发送退出连接邮件服务器消息以完成更新操作\n");
  if((send(sockfd,msg[QUIT],strlen(msg[QUIT]),0))==-1)  //注意这里一定要用strlen()而不是sizeof....
  {
    printf("quit 发送出错!\n");
  }
  printf("quit 发送成功! 等待回发....\n");
  
  cnt=recv(sockfd,buff,BUFFMAX,0);
  recvCntInfo(cnt,buff);
}

int showOprate(void)
{
  printf("\n邮件操作选项如下:\n");
  printf("1:LIST    2:RETR\n");
  printf("3:DELE    4:RSET\n");
  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工程管理

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

转载于:https://www.cnblogs.com/jiayith/p/3516463.html

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值