zoukankan      html  css  js  c++  java
  • 简易电子邮件收信的原理以及实现

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

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

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

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

         我们先要连接到网易的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] = '';
    	}while (strstr(buf, "
    .
    ") == (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] = '';
    
    	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
    ", m_username);
    	printf("%s", sendbuf);
    	send(m_sock, sendbuf, strlen(sendbuf), 0); //发送用户名
    
    
    	int rs = recv(m_sock, recvbuf, sizeof(recvbuf), 0);	//接收server发来的信息
        recvbuf[rs] = '';
    	if ( rs <= 0 || strncmp(recvbuf, "+OK", 3) != 0 )  //假设没有"+OK"就说明失败了
    	{
    		return FALSE;
    	}
    	printf("%s", recvbuf);
    	
    	/*发送password信息*/
    	memset(sendbuf, 0, sizeof(sendbuf));
    	sprintf(sendbuf, "PASS %s
    ", m_userpwd);
    	send(m_sock, sendbuf, strlen(sendbuf), 0);
    	printf("%s", sendbuf);
    
    	rs = recv(m_sock,recvbuf, sizeof(recvbuf), 0);
    	recvbuf[rs] = '';
    	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 
    ");
    	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] = '';
    	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
    ", num);
    	send(m_sock, sendbuf, strlen(sendbuf), 0);
    	do 
    	{
    		rs = Pop3Recv(recvbuf, sizeof(recvbuf), 0); //接收数据
    		if (rs < 0) 
    		{
    			return FALSE;
    		}
    		
    		recvbuf[rs] = '';
    
    		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, "
    .
    ") == (char*)NULL);
    	
    	fclose(fp);
    	return TRUE;
    }
    
    bool CPop3::Quit()
    {
    	char sendbuf[128];
    	char recvbuf[128];
    
    	/*发送QUIT命令*/
    	sprintf(sendbuf, "QUIT
    ");
    	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, "
    "); 
    	if (p == NULL)
    		return sum;
    
    	p = strstr(p + 2, "
    ");
    	if (p == NULL)
    		return sum;
    	
    	while ((p = strstr(p + 2, "
    ")) != 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的代码,加个壳而已!


  • 相关阅读:
    [Java] 计算两个日期之间的差(年 月 日)
    Javassist library is missing in classpath! Please add missed dependenc
    $_SERVER['SCRIPT_FILENAME'] 与 __FILE__ 区别
    内存管理一
    内存管理四
    内存管理二
    内存分配函数分类
    内存映像文件
    内存管理三
    到底有多少内存
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5144156.html
Copyright © 2011-2022 走看看