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=; //接受消息缓冲区大小 /*处理的函数*/ void recvCntInfo(int cnt,char thisBuff[])
{
if(cnt==-)
{
printf("recv出错,退出程序!\n");
exit();
}
else if(cnt==)
{
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=; //smtp的端口号 /*下面定义邮箱命令的标号*/
static const int HELO=;
static const int AUTHLOGIN=;
static const int USERNAME=;
static const int PASSWORD=;
static const int MAILFROM=;
static const int RCPTTO=;
static const int DATA=;
static const int CONTENT=;
static const int QUIT=; int main(void)
{
/*主机信息*/
struct hostent* host; //这里面的地址采用网络字节序
if((host=gethostbyname(SEND_DES))==NULL) //获得域名对应的主机信息
{
printf("gethostbyname 错误!程序退出!\n");
exit();
}
printf("\n域名对应主机名:%s\n",host->h_name); /*创建socket*/
int sockfd=socket(AF_INET,SOCK_STREAM,); //ipv4 tcp
if(sockfd==-)
{
printf("socket 创建错误!\n");
exit();
}
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),); //加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)))==-) //结构体强制转换
{
printf("connect 错误!\n");
exit();
}
printf("connect 成功!\n"); cnt=recv(sockfd,buff,BUFFMAX,); //接受请求这个端口后的回答
recvCntInfo(cnt,buff); /*第二步:对话及发送邮件信息*/ /*初始化每次对话要发送的信息*/
char* msg[]={""}; //分别对应每次的发送消息
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]),))==-) //注意这里一定要用strlen()而不是sizeof....
{
printf("send 出错!\n");
}
printf("send 成功! 等待回发....\n"); cnt=recv(sockfd,buff,BUFFMAX,);
recvCntInfo(cnt,buff);
} /*第三步,退出程序*/
printf("邮件已成功从此客户端发送到邮件服务器!现在发送退出连接邮件服务器消息:\n");
if((send(sockfd,msg[QUIT],strlen(msg[QUIT]),))==-) //注意这里一定要用strlen()而不是sizeof....
{
printf("quit 发送出错!\n");
}
printf("quit 发送成功! 等待回发....\n"); cnt=recv(sockfd,buff,BUFFMAX,);
recvCntInfo(cnt,buff);
}

发送程序

#include "myHead.h"

const char* GET_DES="pop3.163.com";
const int GET_PORT=; /*下面定义常量,其实标号不重要,只是当作下标,好记*/
static const int USR=;
static const int PSW=;
static const int QUIT=;
static const int LIST=;
static const int RETR=;
static const int DELE=;
static const int RSET=; static char* msg[]={""}; //装指向字符串的指针数组,仅此文件可见 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();
}
printf("\n域名对应主机名:%s\n",host->h_name); /*创建socket*/
int sockfd=socket(AF_INET,SOCK_STREAM,); //ipv4 tcp
if(sockfd==-)
{
printf("socket 创建错误!\n");
exit();
}
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),); //加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)))==-) //结构体强制转换
{
printf("connect 错误!\n");
exit();
}
printf("connect 成功!\n"); cnt=recv(sockfd,buff,BUFFMAX,); //接受请求这个端口后的回答
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]),))==-) //注意这里一定要用strlen()而不是sizeof....
{
printf("send 出错!\n");
}
printf("send 成功! 等待回发....\n"); cnt=recv(sockfd,buff,BUFFMAX,);
recvCntInfo(cnt,buff);
} /*二,处理状态*/
int choise=showOprate();
while(choise!=) //循环显示
{
/*下面处理输入的情况*/
if(choise>|choise<)
{
printf("选择 %d 为非法输入!请重新输入!\n",choise);
}
else
{
int sendChoise; //发送的消息对应的下标
int val; //命令的参数
char sendStr[]={'\0'}; //待发送的字符串 switch(choise)
{
case :sendChoise=LIST;break; //仅仅列表
case :{
printf("请输入要返回的邮件编号:");
scanf("%d",&val); //需要编号
getchar();
sprintf(sendStr,"%s%d%c","retr ",val,'\n'); //注意也要把换行符加进去
sendChoise=RETR;
msg[RETR]=sendStr;
break;
}
case :{
printf("请输入要删除的邮件编号");
scanf("%d",&val); //需要编号
getchar();
sprintf(sendStr,"%s%d%c","dele ",val,'\n');
sendChoise=DELE;
msg[DELE]=sendStr;
break;
}
case :sendChoise=RSET;break;
} printf("发送请求:\n%s",msg[sendChoise]);
if((send(sockfd,msg[sendChoise],strlen(msg[sendChoise]),))==-) //注意这里一定要用strlen()而不是sizeof....
{
printf("send 出错!\n");
}
printf("send 成功! 等待回发....\n"); cnt=recv(sockfd,buff,BUFFMAX,);
recvCntInfo(cnt,buff);
} choise=showOprate();
} /*三,更新状态*/
printf("操作结束,现在发送退出连接邮件服务器消息以完成更新操作\n");
if((send(sockfd,msg[QUIT],strlen(msg[QUIT]),))==-) //注意这里一定要用strlen()而不是sizeof....
{
printf("quit 发送出错!\n");
}
printf("quit 发送成功! 等待回发....\n"); cnt=recv(sockfd,buff,BUFFMAX,);
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.:myFunc.c
gcc myFunc.c -c

make工程管理

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

上一篇:BeautifulSoup Some characters could not be decoded, and were replaced with REPLACEMENT CHARACTER.


下一篇:升级到VS2013.Update.4的问题