开发者社区> 技术mix呢> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

简易电子邮件收信的原理以及实现

简介:
+关注继续查看

     上面一篇已经讲到怎样发信了,今天索性来个结尾谈一谈怎样发信!

      和前面的流程差点儿相同,我们也手工模拟一次发信流程!

      事实上和前面的发信流程差不太多!

一样的,我们以网易的邮箱为例!

     我们先要连接到网易的pop邮箱!

     命令为: telnet pop.163.com 110

     意思非常明显,要求连接到网易的popserver的110号port.

     

     然后就能够登陆了!

     输入命令:user xxxxx (你的username,不用加密)

      假设没有出错的话,系统通常会返回+OK之类的东西.

    然后输入:pass xxxxxx(你邮箱的password,不加密)

      一样的,假设没有出错的话,系统通常会返回+OK之类的东西.

      

     如今我们就能够操作了。

     尽管能够使用的命令非常多,只是最经常使用的命令仅仅有两个!

      第一个是list命令,用来列出邮件的条目!我们看一下。

      

       表示有19封邮件。右边是邮件大小。

       另一个命令自然是retr命令了!它用来获取邮件!

看我演示:

       

      retr使用规则是 retr + 你要获取的邮件的编号!

      好吧!

既然已经讲到这份上了,我顺便提一句!server发送的大部分内容是用base64加密了的。所以我们看到满屏幕的字母!

那么怎么读取出内容呢?这不是这篇文章的重点,所以我们代码採取的方式是直接将server发送过来的邮件内容写到文件中,存成.eml文件,然后邮件client能够打开这样的文件。推荐採用foxmail来打开这样的文件!

      最后。不要忘了quit命令,关闭与server的连接,这里就不再演示!

      看代码吧!

           pop3.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pop3.h"


CPop3::CPop3()
{
	WSADATA wsaData;
	WORD version = MAKEWORD(2, 0);
	WSAStartup(version, &wsaData);
}

CPop3::~CPop3()
{
	WSACleanup();
}

int CPop3::Pop3Recv(char* buf, int len, int flags) 
{/*接收数据*/
	int rs;
	int offset = 0;

	do 
	{
		if (offset > len - 2)
			return offset;

		rs = recv(m_sock, buf + offset, len - offset, flags);
		if (rs < 0) return -1;

		offset += rs;
		buf[offset] = '\0';
	}while (strstr(buf, "\r\n.\r\n") == (char*)NULL);

	return offset;
}

bool CPop3::Create(
				   const char* username,	//用户名
				   const char* userpwd,		//用户password
				   const char* svraddr,		//server地址
				   unsigned short port		//服务端口
				   )
{
	strcpy(m_username, username);
	strcpy(m_userpwd, userpwd);
	strcpy(m_svraddr, svraddr);
	m_port = port;

	return true;
}

bool CPop3::Connect()
{
	//创建套接字
	m_sock = socket(AF_INET, SOCK_STREAM, 0);

	//IP地址
	char ipaddr[16];

	struct hostent* p;
	if ((p = gethostbyname(m_svraddr)) == NULL) //假设得不到server信息,就说明出错
	{
		return FALSE;
	}
	

	sprintf(
			ipaddr,
			"%u.%u.%u.%u",
			(unsigned char)p->h_addr_list[0][0],
			(unsigned char)p->h_addr_list[0][1],
			(unsigned char)p->h_addr_list[0][2],
			(unsigned char)p->h_addr_list[0][3]
			);


	//连接popserver
	struct sockaddr_in svraddr;
	svraddr.sin_family = AF_INET;
	svraddr.sin_addr.s_addr = inet_addr(ipaddr);
	svraddr.sin_port = htons(m_port);
	int ret = connect(m_sock, (struct sockaddr*)&svraddr, sizeof(svraddr));
	if (ret == SOCKET_ERROR) 
	{
		return FALSE;
	}


	//接收pop3server发来的欢迎信息
	char buf[128];
	int rs = recv(m_sock, buf, sizeof(buf), 0);
	buf[rs] = '\0';

	printf("%s", buf);
	if (rs <= 0 || strncmp(buf, "+OK", 3) != 0)  /*server没有返回OK就出错了*/
	{
		return FALSE;
	}

	return TRUE;
}

bool CPop3::Login()
{/*登陆*/
	
	/*发送用户命令*/
	
	char sendbuf[128];
	char recvbuf[128];

	sprintf(sendbuf, "USER %s\r\n", m_username);
	printf("%s", sendbuf);
	send(m_sock, sendbuf, strlen(sendbuf), 0); //发送用户名


	int rs = recv(m_sock, recvbuf, sizeof(recvbuf), 0);	//接收server发来的信息
    recvbuf[rs] = '\0';
	if ( rs <= 0 || strncmp(recvbuf, "+OK", 3) != 0 )  //假设没有"+OK"就说明失败了
	{
		return FALSE;
	}
	printf("%s", recvbuf);
	
	/*发送password信息*/
	memset(sendbuf, 0, sizeof(sendbuf));
	sprintf(sendbuf, "PASS %s\r\n", m_userpwd);
	send(m_sock, sendbuf, strlen(sendbuf), 0);
	printf("%s", sendbuf);

	rs = recv(m_sock,recvbuf, sizeof(recvbuf), 0);
	recvbuf[rs] = '\0';
	if (rs <= 0 || strncmp(recvbuf, "+OK", 3) != 0) 
	{
		return FALSE;
	}		
	printf("%s", recvbuf);

	return TRUE;
}

bool CPop3::List(int& sum)
{
	/*发送list命令*/
	char sendbuf[128];
	char recvbuf[256];

	sprintf(sendbuf, "LIST \r\n");
	send(m_sock, sendbuf, strlen(sendbuf), 0);
	printf("%s", sendbuf);

	int rs = recv(m_sock, recvbuf, sizeof(recvbuf), 0);
	if (rs <= 0 || strncmp(recvbuf, "+OK", 3) != 0)
	{
		return FALSE;
	}
	recvbuf[rs] = '\0';
	printf("%s", recvbuf);

	sum = GetMailSum(recvbuf); //得到邮件的数目
	
	return TRUE;	
}

bool CPop3::FetchEx(int num)
{
	int rs;
	FILE* fp;
	int flag = 0;
	unsigned int len;
	char filename[256];

	char sendbuf[128];
	char recvbuf[20480];

	/* 发送RETR命令*/
	sprintf(sendbuf, "RETR %d\r\n", num);
	send(m_sock, sendbuf, strlen(sendbuf), 0);
	do 
	{
		rs = Pop3Recv(recvbuf, sizeof(recvbuf), 0); //接收数据
		if (rs < 0) 
		{
			return FALSE;
		}
		
		recvbuf[rs] = '\0';

		printf("Recv RETR Resp: %s", recvbuf); //输出接收的数据

		if (flag == 0)
		{
			itoa(num, filename, 10); //依照序号给文件排名
			strcat(filename, ".eml");

			flag = 1;
			fp = fopen(filename, "wb");//准备写文件
		}
		len = strlen(recvbuf);
		fwrite(recvbuf, 1, len, fp);
		fflush(fp); //刷新	
	}while (strstr(recvbuf, "\r\n.\r\n") == (char*)NULL);
	
	fclose(fp);
	return TRUE;
}

bool CPop3::Quit()
{
	char sendbuf[128];
	char recvbuf[128];

	/*发送QUIT命令*/
	sprintf(sendbuf, "QUIT\r\n");
	send(m_sock,sendbuf, strlen(sendbuf), 0);
	int rs = recv(m_sock, recvbuf, sizeof(recvbuf), 0);
	if (rs <= 0 || strncmp(recvbuf, "+OK", 3) != 0)
	{
		return FALSE;
	}
	

	closesocket(m_sock);
	return TRUE;
}



int CPop3::GetMailSum(const char* buf)
{
	int sum = 0;
	char* p = strstr(buf, "\r\n"); 
	if (p == NULL)
		return sum;

	p = strstr(p + 2, "\r\n");
	if (p == NULL)
		return sum;
	
	while ((p = strstr(p + 2, "\r\n")) != NULL) 
	{
		sum++;
	}

	return sum;
}
    pop3.h

#include <WinSock2.h>
#pragma  comment(lib, "ws2_32.lib")	/*链接ws2_32.lib动态链接库*/

class CPop3 {

public:
	CPop3();
	~CPop3();

	//初始化pop3的属性
	bool Create(const char* username, const char* userpwd, const char* svraddr, 
				unsigned short port = 110);
	
	//连接pop3server
	bool Connect();

	//登陆的server
	bool Login();

	//利用list命令得到全部的邮件数目
	bool List(int& sum);
	
	//获得序号为num的邮件
	bool FetchEx(int num = 1);

	//退出命令
	bool Quit();

protected:
	int GetMailSum(const char* buf);

	SOCKET m_sock;
	char m_username[32];	/*用户名*/
	char m_userpwd[32];		/*password*/
	char m_svraddr[32];		/*server域名*/
	unsigned short m_port;

private:
	int Pop3Recv(char* buf, int len, int flags = 0);

};
      然后用一个主程序測试一下:

    main.cpp

#include <stdio.h>
#include "pop3.h"


int main()
{
	int sum;
	CPop3 pop3;
	char userName[256] = "it_is_just_a_test@163.com";
	char password[256] = "19930714lyh";
	char srv[256] = "pop.163.com";
	pop3.Create(userName, password, srv, 110); 
	

	pop3.Connect(); //连接pop3server

	pop3.Login();

	pop3.List(sum);

	if (sum < 0)
	printf("You have no letter in box !");

	for (int i = 1; i <= sum; i++) 
	{
		pop3.FetchEx(i);
	}
         
	pop3.Quit();

	return 0;
}


         在VC6以下測试完美通过!然后看看你的project的目录以下,是不是出现了非常多.eml文件?这些文件能够用foxmail打开,这就是接收到的邮件!

赶快尝试一下吧!

     文章写到这里,建议的收信,写信基本上都已经说明确了,事实上你略微包装一下。就能够写出一段MFC的邮件client的代码,加个壳而已!







本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5144156.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
CCNP必备:Linux网络及0SI7层模型深入讲解(二)|学习笔记
快速学习CCNP必备:Linux网络及0SI7层模型深入讲解
21 0
CCNP 必备:Linux 网络及 0SI7 层模型深入讲解(三)|学习笔记
快速学习 CCNP 必备:Linux 网络及 0SI7 层模型深入讲解
35 0
CCNP必备:Linux网络及0SI7层模型深入讲解(一)|学习笔记
快速学习CCNP必备:Linux网络及0SI7层模型深入讲解
44 0
关于 SAP UI5 Table 控件中行合并的实现方式
关于 SAP UI5 Table 控件中行合并的实现方式
53 0
快速部署阿里云WebIDE(DevStudio)并参与开源项目开发
3个步骤,在轻量应用服务器上完成部署DevStudio,帮你快速学习使用DevStudio进行代码的开发。
487 0
Laravel 下结合阿里云邮件推送服务
最近在学习laravel做项目开发,遇到注册用户推送邮件的问题,之前用java做的时候是自己代码写的,也就是用ECS推送邮件,但是现在转php的laravel了就打算用php的邮件发送功能来推送邮件,但是开发的过程中发现其实阿里云在2015年11月推出了邮件推送服务,所以打算使用阿里云的邮件推送服务,之前也使用过阿里云的OSS感觉也还不错不过是java的SDK,这个搞完了,后面也要实现OSS的上传文件服务功能,这个暂且放下吧。
2572 0
阿里云centos7.2 搭建 laravel 框架走过的坑
阿里云centos7.2 搭建 laravel 框架走过的坑  前言 公司正在处于发展阶段最近开发的伙伴和运维的伙伴一直在忙碌着 开发人员一直在写laravel架构的代码以及新项目的拓展,时间很赶所以作为linux运维的我也不能怠慢。
1711 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
微信客户端怎样应对弱网络
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载