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工程管理
那个。。。貌似有我的邮箱用户名和密码,我也不用。。。哈哈
Linux C SMTP POP3 极简陋邮件客户端的更多相关文章
- 使用java语言基于SMTP协议手写邮件客户端
使用java语言基于SMTP协议手写邮件客户端 1. 说明 电子邮件是互联网上常见的应用,他是互联网早期的产品,直至今日依然受到广大用户的喜爱(在中国可能因为文化背景不同,电子邮件只在办公的时候常用) ...
- linux配置邮件客户端
linux配置邮件客户端 1. 申请一个163邮箱,并配置客户端授权密码 l 开启POP3/SMTP/IMAP l 设置客户端授权密码 ###此密码不能跟邮箱密码相同,此密码用来在linux邮件客户端 ...
- POP3是收邮件的协议,SMTP是发邮件的协议,IMAP是一种邮箱通信协议。
我也是第一次接触这种服务,是因为我自己在做一个小小的自动推送天气情况到自己邮箱.所以才碰到这个的/ 看一下标题,我们可以先这样理解. POP3(Post Office Protocol - Versi ...
- centos 邮件服务 腾讯企业邮箱(免费) 使用iRedmail 需要有公网的centos主机 发邮件协议:smtp 端口25 收邮件协议:pop3 端口110 iredmail安装配置 使用邮箱系统 第三十一节课
centos 邮件服务 腾讯企业邮箱(免费) 使用iRedmail 需要有公网的centos主机 发邮件协议:smtp 端口25 收邮件协议:pop3 端口110 iredmail安装配置 ...
- linux邮件客户端mutt日志文件,发不出邮件
linux上面使用很方便的收发邮件客户端(即MUA),还有一个是mail,大家也可以试试. 在网上找了很多,都说需要msmtp配合使用,其实mutt里面也内建了smtp支持的. mutt and SM ...
- mutt+msmtp做linux邮件客户端
mutt+msmtp做linux邮件客户端 1. 安装配置msmtp l 安装 wget https://sourceforge.net/projects/msmtp/files/msmtp/1.4 ...
- linux下支持托盘的邮件客户端Sylpheed
在网上搜索了很多客户端想支持系统托盘,发现一个很不错的邮件客户端Sylpheed.设置方式和foxmail很像,最为重要的是支持系统托盘,很方便,默认没有开启,简单设置下:配置->通用首选项-& ...
- POP3与SMTP以及python实现邮件的发送
什么是POP3协议: POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议.它是因特网 ...
- SMTP、POP3和IMAP邮件协议
目录 SMTP POP IMAP 总结 DNS记录中的MX记录 今天入职第一天,公司让配置个人的内网.外网邮箱,这可把我给搞晕了,本来以前就对邮箱这块不是很了解,平时也不怎么用邮箱,顶多有个QQ邮箱而 ...
随机推荐
- 05.pathinfo的两种模式与模版和控制器之间的关系
<?php function dump($data){ echo '<pre>'; var_dump($data); echo '</pre>'; } dump($_SE ...
- JNI 系统钩子
占个位置,日后学会了补充: JAVA是运行在虚拟机上的,而钩子函数是直接对操作系统进行操作控制的,这也是Java和C的主要区别之一,Java要实现钩子函数比较麻烦,需要使用JNI技术,就是Java本地 ...
- Excel转换成PDF
public class Office2Pdf { public bool DOCConvertToPDF(string sourcePath, string targetPath) { //Stre ...
- 纯windows下制作变色龙引导安装U盘教程
原创教程:纯windows下制作变色龙引导安装U盘教程 支持Mavericks和Yosemite 支持白苹果 目标:windows下制作带 Chamelon变色龙引导的黑苹果安装U盘,支持PC机引导安 ...
- Redis 安全
我们可以通过 redis 的配置文件设置密码参数,这样客户端连接到 redis 服务就需要密码验证,这样可以让你的 redis 服务更安全. 实例 我们可以通过以下命令查看是否设置了密码验证: 1 ...
- 详解ARM的AMBA设备中的 DMA设备PL08X的Linux驱动
1. 此文目的记录笔者对ARM的PL08x的DMA驱动PL08x.c理解.给其他不熟悉此DMA驱动的读者一点借鉴和参考.2. 适合读者你已经具备一定驱动编程能力,知道一些最基本的概念,比如用于输出输出 ...
- syntax error: missing ';' before identifier 'IWebBrowser'
遇到这个错误. google的结果是 去掉 WIN32_LEAN_AND_MEAN 宏定义 然而由于项目中使用了很多第三方库, 如果去掉这个宏, 会导致其他项目编译错了. 关于这个宏有什么用, 可以百 ...
- 笔记——Function类型 及其 call、apply方法
每个函数都是Function类型的实例.函数有三种定义方式和两个内部属性arguments和this. 同时函数也是对象,也有属性和方法.本篇主要其call()和apply()方法 属性 length ...
- oracle--clob
最近,收到这样的异常邮件: Error updating database. Cause: java.sql.SQLException: ORA-01461: can bind a LONG val ...
- [转]在SQL中用正则表达式替换html标签
本文转自:http://blog.csdn.net/dhttaso/article/details/6045380 由于数据库的一个表字段中多包含html标签,现在需要修改数据库的字段把html标签都 ...