前言
这次记录一下Node来处理邮件的尝试,IMAP和POP3我都有测试,遇到的问题稍微记录一下。
IMAP
https://github.com/mscdex/node-imap
尝试用的这个库来测试163的邮箱,配置好账号密码和服务器后,用自带的例子报这个错误:
Error: EXAMINE Unsafe Login. Please contact kefu@188.com for help
问题的根源还是挺好找的,在这个网页里面,看海大神就有提到。
网易之所以这么做,是基于 RFC 2971 协议,该协议主要内容就是规定 IMAP4 ID extension 的通信规则。所以并不是网上疯传的网易邮箱为了圈地,封禁其他客户端,强制要求使用网易客户端的原因。事实上,Gmail 邮箱也是要求客户端遵守这一协议的。
解决方法呢,就是调用ID方法,再给服务器传递一个消息,让服务器区别一下你是哪个客户端就是了。 那这个id要怎么调用呢?其实库里面已经解决这个问题了。(https://github.com/mscdex/node-imap/pull/307)这个issues里面说自己已经解决好了,但是并没有说怎么使用。。。唉,看一下他们的对话可以发现主要改的是lib/Connection.js 。那就到源码的lib/Connection.js 里面去找一下他到底是怎么改的。还好源码里面的id不多,可以很快找到(下面的图片),分析一下代码,需要两个参数,一个是identification,一个是cb。咱们看参考代码和名字可以知道cb指的就是callback,也就是回调函数,这个简单。问题是这个identification是啥嘞?
Connection.prototype.id = function(identification, cb) {
if (!this.serverSupports('ID'))
throw new Error('Server does not support ID');
var cmd = 'ID';
if ((identification === null) || (Object.keys(identification).length === 0))
cmd += ' NIL';
else {
if (Object.keys(identification).length > 30)
throw new Error('Max allowed number of keys is 30');
var kv = [];
for (var k in identification) {
if (Buffer.byteLength(k) > 30)
throw new Error('Max allowed key length is 30');
if (Buffer.byteLength(identification[k]) > 1024)
throw new Error('Max allowed value length is 1024');
kv.push('"' + escape(k) + '"');
kv.push('"' + escape(identification[k]) + '"');
}
cmd += ' (' + kv.join(' ') + ')';
}
this._enqueue(cmd, cb);
};
根据RFC 2971 协议的文档(3.1节)的例子中可以看出来,我们还需要传输我们的信息作为参数发送给服务器。具体的参数类型可以查看文档的第3.3节,我测试了你只要传个name 属性给他就能完成验证,根据代码就是传一个信息类就行。 最终代码如下:
var Imap = require('imap')
var imap = new Imap({
user: 账号,
password: 密码,
host: 'imap.163.com',
port: 993,
tls: true
});
var idIden = {
name: "llsxily",
}
imap.once('ready', function() {
imap.id(idIden,function(err, box) {
if (err) throw err;
console.log()
}
}
POP3
pop3可能因为太简单,前端大神都看不上,所以库都start很少。我用的是:
https://github.com/node-pop3/node-pop3
这个库就非常简单了,我放一段我遍历头信息的代码给大家参考一下就好
const Pop3Command = require('node-pop3');
const pop3 = new Pop3Command({
user: 账号,
password: 密码,
host: 'pop.163.com',
});
(async () => {
let mailList = await pop3.STAT();
mailList = mailList.split(' ')
console.log(mailList);
for(let i=1;i<=mailList[0];i++){
console.log(i)
let mlist = await pop3.TOP(i, 0)
console.log(mlist)
}
await pop3.QUIT();
})();
POP3的指令比较简单,因为他只有读取而没有上传和删除等权限,所以他的命令比IMAP少的多。所以其实掌握了POP3的指令可以很快的理解这个库的这些方法。主要的指令如下:
POP3命令格式 | 说明 |
---|
user username | user 命令是POP3客户端程序与POP3邮件服务器建立连接后通常发送的第一条命令,参数 username 表示收件人的帐户名称。 | pass password | pass 命令是在user命令成功通过后,POP3客户端程序接着发送的命令,它用于传递帐户的密码,参数 password 表示帐户的密码。 | apop name,digest | apop 命令用于替代user和pass命令,它以MD5 数字摘要的形式向POP3邮件服务器提交帐户密码。 | stat | stat 命令用于查询邮箱中的统计信息,例如:邮箱中的邮件数量和邮件占用的字节大小等。 | uidl msg# | uidl 命令用于查询某封邮件的唯一标志符,参数msg#表示邮件的序号,是一个从1开始编号的数字。 | list [MSG#] | list 命令用于列出邮箱中的邮件信息,参数 msg#是一个可选参数,表示邮件的序号。当不指定参数时,POP3服务器列出邮箱中所有的邮件信息;当指定参数msg#时,POP3服务器只返回序号对应的邮件信息。 | retr msg# | retr 命令用于获取某封邮件的内容,参数 msg#表示邮件的序号。 | dele msg# | dele 命令用于在某封邮件上设置删除标记,参数msg#表示邮件的序号。POP3服务器执行dele命令时,只是为邮件设置了删除标记,并没有真正把邮件删除掉,只有POP3客户端发出quit命令后,POP3服务器才会真正删除所有设置了删除标记的邮件。 | rest | rest 命令用于清除所有邮件的删除标记。 | top msg# n | top 命令用于获取某封邮件的邮件头和邮件体中的前n行内容,参数msg#表示邮件的序号,参数n表示要返回邮件的前几行内容。使用这条命令以提高 Web Mail系统(通过Web站点上收发邮件)中的邮件列表显示的处理效率,因为这种情况下不需要获取每封邮件的完整内容,而是仅仅需要获取每封邮件的邮件头信息。 | noop | noop 命令用于检测POP3客户端与POP3服务器的连接情况。 | quit | quit 命令表示要结束邮件接收过程,POP3服务器接收到此命令后,将删除所有设置了删除标记的邮件,并关闭与POP3客户端程序的网络连接。 |
结语
这可能是我最近最后一次学习node这些库的使用了,我放弃了,后续可能js还是只做前端,我还是回去用python吧。 回想2017年的时候,彼时我还在挣扎着看webRTC的代码,我问组里的前端龙哥啥是nodejs,nodejs能做什么? 龙哥一脸骄傲的和我说nodejs是现在最活跃的社区,node什么都能做,后端能干的他能干,后端不能干的他也能干。所以我对node一直心怀向往。 自己真的用起来,说实话,只能说大失所望。node社区过了5年,我需要的东西都没有,JS也是和S一样的代码结构。可能给我这个感觉,是我学艺不精,但是我以前刚开始学Android开发的时候,慢慢学会用JAVA和XML写页面,我对这个结构是有一种逐步学习,逐步惊叹的感觉,惊叹与设计之巧妙,代码之美丽。但是学JS我从头到尾都在吐槽。真的尤其是对比python,感觉就像知乎的那句话,“JS就是一堆S山,ES6就是在上面撒了一些糖霜”。 可能从一开始选择js就决定了node的命运吧。一个主要使用者是前端开发者的语言,可能注定很能积攒出很多后端的轮子。回想5年前龙哥提到node时眼中的神采,可能node的真正使命还是前端的工程化吧。 个人的一些心境感悟,请各位前端大神轻喷。我是碎碎念的llsxily,你可以叫我橘子。
|