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

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

      和前面的流程差不多,我们也手工模拟一次发信流程!

      其实和前面的发信流程差不太多!一样的,我们以网易的邮箱为例!

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

     命令为: telnet pop.163.com 110

     意思很明显,要求连接到网易的pop服务器的110号端口.

     

     然后就可以登陆了!

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

      如果没有出错的话,系统一般会返回+OK之类的东西.

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

      一样的,如果没有出错的话,系统一般会返回+OK之类的东西.

      

     现在我们就可以操作了!

     虽然可以使用的命令很多,不过最常用的命令只有两个!

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

      

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

       还有一个命令自然是retr命令了!它用来获取邮件!看我演示:

       

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

      好吧!既然已经说到这份上了,我顺便提一句!服务器发送的大部分内容是用base64加密了的,所以我们看到满屏幕的字母!那么怎么读取出内容呢?这不是这篇文章的重点,所以我们代码采取的方式是直接将服务器发送过来的邮件内容写到文件里,存成.eml文件,然后邮件客户端可以打开这种文件,推荐采用foxmail来打开这种文件!

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

      看代码吧!

   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,		//用户密码
				   const char* svraddr,		//服务器地址
				   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) //如果得不到服务器信息,就说明出错
	{
		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]
			);

	//连接pop服务器
	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;
	}

	//接收pop3服务器发来的欢迎信息
	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)  /*服务器没有返回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);	//接收服务器发来的信息
    recvbuf[rs] = '\0';
	if ( rs <= 0 || strncmp(recvbuf, "+OK", 3) != 0 )  //如果没有"+OK"就说明失败了
	{
		return FALSE;
	}
	printf("%s", recvbuf);

	/*发送密码信息*/
	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);

	//连接pop3服务器
	bool Connect();

	//登陆的服务器
	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];		/*密码*/
	char m_svraddr[32];		/*服务器域名*/
	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] = "[email protected]";
	char password[256] = "19930714lyh";
	char srv[256] = "pop.163.com";
	pop3.Create(userName, password, srv, 110); 

	pop3.Connect(); //连接pop3服务器

	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下面测试完美通过!然后看看你的工程的文件夹下面,是不是出现了很多.eml文件?这些文件可以用foxmail打开,这就是接收到的邮件!赶快尝试一下吧!

     文章写到这里,建议的收信,写信基本上都已经说明白了,其实你稍微包装一下,就可以写出一段MFC的邮件客户端的代码,加个壳而已!

    既然已经说到了这里,我顺带还提一句,算是忠告吧!尽量少用VC6来写MFC程序,虽然这款软件真他妈的经典,但是就我个人来说,我已经碰到了她的很多bug,致命性的!

    比如说一个基于对话框的应用程序,有一次我只是在框上多摆了几个控件罢了,结果跑不起了,压根无法回退到原来的状态,害得我几个小时的工作打了水漂,这种情况遇到了几次,在多台机器上,所以建议用高级一点的VS,比如VS2005,它比VC6稳定得多(VC6经常跑了几次就崩掉了有木有?)。

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

时间: 2024-11-05 22:01:58

简易电子邮件收信的原理以及实现的相关文章

QQ粘虫生成器-ASP后台收信免杀版

QQ粘虫生成器-ASP后台收信免杀版 QQ密码破解器ASP收信-2016免杀版 视频观看 地址: http://share.weiyun.com/6375edc2fcb0628549fe561ef9096940 网盘地址: www.qlyw.cccpan.com [ 登录密码:qlyw]

金笛短信平台原理及工作模式

金笛短信平台由一个数据库.构筑在数据库之上的Web服务.发送服务.接收服务构成.其运作方式为:由Web服务构成B/S结构的用户界面,使用户可以管理该平台:由发送接收服务连接外部的短信设备和短信网关,发送.接收信息.金笛短信平台原理发送服务, 定时扫描数据库数据变化, 将待发送送出去.目前支持M y S Q L .SQLServer2000/SQLServer2005-2012.Oracle.接收服务.随时处理收到的短信,将收到的短信转存到数据库.web服务.是平台主要的功能服务器,这些功能包括:

新型手机群发短信工作原理

新型手机群发短信工作原理[电薇:132乄8688乄4109][Q群780516296]胡锡进:滴滴打垮黑车 但千万不能做"对黑车的收编"生态环境部启动治霾千里眼:烧煤一查一个准飞鸟:苏炳添没尽全力 山县:决赛将会是高水平科比出来喊话!再黑詹姆斯就要逐出科蜜团队了利用微信贩卖淫秽物品牟利案宣判 主犯被判有期三年印日将首次举办联合军演 英媒:似乎是为对抗中国韩国专家:美国对伊朗的立场使韩陷入尴尬境地人民日报:让疯狂片酬回归理性 阴阳合同无所遁形快讯-游泳女子200蝶张雨霏夺冠 俞李妍获得第

C#简易商城收银系统v1.0(2-1)

C#简易商城收银系统v1.0(2-1) 当初: 面向编程对象的好处及应用简单工厂模式(继承,多态) 现在: 制作一个简易的收银窗体应用程序 可以参考之前的 计算器 随笔 创建窗体程序 客户端代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Te

C#简易商城收银系统v1.1简单工厂实现(2-2)

C#简易商城收银系统v1.1简单工厂实现(2-2) 当初: C#简易商城收银系统v1.0 现在: 用之前的工厂模式对商城收银系统v1.0进行升级 可以参考之前的 C#简易商城收银系统v1.0 随笔 添加CashSuper类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 商城收银软件 { abs

为什么我的outlook只能收信不能发信,发送测试电子邮件消息: 无法发送此邮件。请在帐户属性中验证电子邮件

链接地址:http://zhidao.baidu.com/link?url=aVIFo2aNLuHIZGZuEUataHkZp4XApHqyvbEK8ACHPhi3jwhGhM0GBAtm72AnsPv9W4Q8a3RS3pyXbv-uUzsE3q 核对outlook的账户绑定设置,以outlook express为例1.打开Outlook Express,点击“工具”选项,选择“帐户”选项:在弹出的窗口中,选择“邮件”标签:点击“添加”按钮,选择“邮件”标签:2.在显示名提示框中输入您的名字,

Android_简易的短信发送器

这个随笔将介绍如何完成一个简单的第三方的短信发送器(不打开短信界面,调用android的api完成功能) 1.首先,我们来做布局 由于我这里写的是一个简易的,,短信发送,所以只是一个LinearLayout下放了两个EditText用来存号码和内容,还有一个Button发送按钮,如果想要更华丽的布局,有兴趣的大家可以再去添加奥. 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xml

(七)android开发中两种方式监听短信的原理和实现

一.监听短信的两种方式的简介 Android程序开发中,有两种方式监听短信内容:一.接收系统的短信广播:二.应用观察者模式,监听短信数据库. 第一种方式接收系统的短信广播: A.这种方式只对新收到的短消息有效,运行代码,并不会读取收件箱中已读或未读的消息,只有当收到新来的短消息时,才会执行onReceive()方法. B.并且这个广播是有序广播,如果当别的程序先读取到了这个广播,然后拦截掉了个这个广播,你将接收不到.当然我们可以通过设置priority的数值,其实有时是不管用的,现在在一些定制的

【JQuery】jQuery自制简易手风琴效果(附实现原理)

手风琴效果经常会用在网页左侧的导航栏,当导航内容比较多时使用手风琴的展示方式更有利于信息的传递和排版,下面就分享一个自己制作的简易手风琴效果,没有用图片,背景颜色也是随意设定的,在实际项目中大家可适当修改. 效果图: 实现原理: 1.当鼠标点击span标签(即一级导航)时,先判断子目录li是否已经展开(此处使用一个on类来做标记): 2.如果是,则收缩当前的li,移出on类标记,修改span右边的提示符为加号: 3.如果不是,则展开当前的li,增加on类标记,修改span右边的提示符为减号. 源