2020-07-12 01:48:30 登录注册 RSS

当前位置: 公理网 >> 网友举报 >> Node后台邮件服务器

Node后台邮件服务器
发布时间:06-30| 来源:公理网 | 点击发表评论
勤写标兵Lv1
授予每个自然周发布1篇到3篇原创IT博文的用户。本勋章将于次周周三上午根据用户上周的博文发布情况由系统自动颁发。

80530937","ab":"new"}'target="_blank"href="https://blog.csdn.net/konghouy/article/details/80530937">feof()原理和用法
bandaoyu:博主讲的太罗嗦了,一句话:feof(fp)就是判断fp是否已经读取了EOF字符。如果已读取,返回true值,所以在调用feof(fp)之前,都应该先调用读文件的函数:fgets(ar,50,fid)、fgetc(fid),然后再判断就OK。


80530937","ab":"new"}'target="_blank"href="https://blog.csdn.net/konghouy/article/details/80530937">feof()原理和用法
42838997"target="_blank">qq_42838997:楼上原理部分错了。文件中不会存储“EOF字符”(EOF又不是ASCII码那怎样存储呢?),EOF是个在标准文件中定义的常值(-1),个人理解:系统取出文件字符时会计数,当计数值到达文件大小字节数时认为达到文件末尾返回EOF(-1),没详细研究过。。



一、使用场景

在项目整体的实现中,我们可能需要使用邮箱来提供一些服务,或是发送一些重要的信息。这时我们的后台就需要使用邮箱服务器来提供服务。常见的场景有:

邮箱注册时的验证
邮箱密码找回
后台崩溃并邮件报告管理员
接收一些用户的邮件反馈
二、邮件服务器原理
1.发送邮件

单一的node后台其实本身并没有发送邮件的功能,要想实现发送邮件的效果,还是需要借助一个邮箱来实现邮件的发送。


流程:前端提出发送需求----Node后台收集需要发送的信息----发送给邮箱服务器来进行发送

在node后台----邮箱后台的这个过程中,遵循了SMTP协议。这个协议来控制邮件的中转方式,用于因特网中邮件服务器之间交换邮件。

2.接收邮件

后台接收邮件其实就是把邮箱已经接受的邮件获取到node后台。


流程:node后台请求邮件----邮箱根据请求的情况返回对应的邮件

在邮箱收到邮件----将信息获取到后台的过程中,遵循pop3或imap协议。

pop3协议


POP3协议允许电子邮件客户端下载服务器上的邮件,但是在客户端的操作(如移动邮件、删除邮件、标记已读等),不会反馈到服务器上。


比如通过客户端收取了邮箱中的3封邮件并移动到其他文件夹,邮箱服务器上的这些邮件是没有同时被移动的。也就是说POP3协议实际上是下载了一份邮件的副本到本地邮件客户端,而且对本地邮件副本的操作只会影响本地数据。多个邮件客户端里面的邮件的状态可能会不一致。


imap协议


IMAP也是提供面向用户的邮件收取服务。与POP3不同的是,您在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上。


比如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。换句话说,IMAP把远程文件夹当成本地文件夹来操作,它们之间类似于双向同步。这样的好处是,当你在多个邮件客户端看见的邮件的状态是一致的。


POP3(PostOfficeProtocol3)邮局协议第三版本


IMAP(InternetMailAccessProtocol)internet消息访问协议。

三、实现详解
1.第三方模块

在node的生态中,实现这样的功能有很多的第三方模块。比如:

nodemailer
node-red
node-imap

大家可以在npm上搜索并查看文档进行开发。


下面我们使用nodemailer、imap这两个模块进行讲解,使用的邮箱是qq邮箱。

2.发送邮件(需要使用nodemailer模块)

一共分为三步:

使用SMTP或其他传输机制创建Nodemailer传输器
设置消息选项(谁向谁发送消息)
使用先前创建的传输程序的sendMail()方法传递消息对象

lettransporter=nodemailer.createTransport({
host:'smtp.qq.com',
port:465,
secure:true,//truefor465,falseforotherports
auth:{
user:"[email protected]",//generatedetherealuser
pass:'邮箱的验证码'//generatedetherealpassword
//创建Nodemailer传输器
letmailOptions={
from:'"khy"[email protected]',//senderaddress
to:'[email protected]',//listofreceivers
subject:'Hello',//Subjectline
text:'Helloworld?',//plaintextbody
html:'bHelloworld?/b'//htmlbody
//设置消息选项
transporter.sendMail(mailOptions,(error,info)={
if(error){
returnconsole.log(error);
console.log('Messagesent:%s',info.messageId);
//PreviewonlyavailablewhensendingthroughanEtherealaccount
console.log('PreviewURL:%s',nodemailer.getTestMessageUrl(info));
//Messagesent:[email protected]
//PreviewURL:https://ethereal.email/message/WaQKMgKddxQDoou...
//sendMail()方法传递消息对象

a.创建Nodemailer传输器
这个部分是设置node后台需要向哪一个邮箱后台,提交邮件请求。

1、nodemailer.createTransport(options[,defaults])



auth:{

?user:"[email protected]",请求代理的邮箱地址

?pass:'jfxksdbztpcohjff’邮箱邀请码,从邮件服务提供商获取


}



2、transporter.verify(callback);

这个是后台验证是否授权成功,一般用于后台链接测试,实际项目中,不需要写!


lettransporter=nodemailer.createTransport({
host:'smtp.qq.com',
port:465,
secure:true,
auth:{
user:"[email protected]",
pass:'邮箱的验证码'
transporter.verify(function(error,success){
if(error){
console.log(error);
}else{
console.log('授权成功!');

b.设置消息选项
这个部分是编辑邮件的内容部分

我仔细研究翻译了官方的文档,做了一些测试,得到了比较全面的使用方法。这一步其实就是建立一个对象,把相关信息作为对象的属性进行存储。


属性列表:(表中尖括号括起来的内容表示数据类型)



from-邮件发出的地址



to-邮件送到的地址



cc-抄送的地址



bcc-加密抄送的地址



subject-邮件的标题

text-发送的文本,,

html-发送html页,,

attachments-添加附件对应的属性:
filename-文件名content-传输内容,,可以将数据导入文件,作为附件发送。path-本地路径如果希望流式传输文件而不是包含该文件,则使用该文件的路径(对于较大的附件更好)href–网络数据信息路径。contentType-规定附件的格式,如果未设置,将从文件名生成contentDisposition-optionalcontentdispositiontypefortheattachment,defaultsto‘attachment’cid-optionalcontentidforusinginlineimagesinHTMLmessagesourceencoding-Ifsetandcontentisstring,thenencodesthecontenttoaBufferusingthespecifiedencoding.Examplevalues:‘base64’,‘hex’,‘binary’etc.UsefulifyouwanttousebinaryattachmentsinaJSONformattedemailobject.headers-customheadersfortheattachmentnode.Sameusageaswithmessageheadersraw-isanoptionalspecialvaluethatoverridesentirecontentsofcurrentmimenodeincludingmimeheaders.Usefulifyouwanttopreparenodecontentsyourself
上边部分不太常用的的内容没有翻译,一般在邮件发送时也不需要编写,英文内容来源于nodemailer官方文档。

//address实例---符合address格式的例子1.字符串:'[email protected]'2.字符串嵌套:'"Майлер,Ноде"[email protected]'3.对象:{name:'Майлер,Ноде',address:'[email protected]'}4.数组['"НодеМайлер"[email protected],'"Name,User"[email protected]']5.混合数组['[email protected]',{name:'Майлер,Ноде',address:'[email protected]'}]//attachments实例attachments:[{//字符串生成附件filename:'text1.txt',content:'helloworld!'},{//字符流生成附件filename:'text2.txt',content:newBuffer('helloworld!','utf-8')},{//磁盘文件生成附件filename:'text3.txt',path:'/path/to/file.txt'},{//文件名及类型会自动从路径获取path:'/path/to/file.txt'},{//字符流生成附件filename:'text4.txt',content:fs.createReadStream('file.txt')},{//为附件定义自定义内容类型filename:'text.bin',content:'helloworld!',contentType:'text/plain'},{//使用URL添加附件filename:'license.txt',path:'https://raw.github.com/nodemailer/nodemailer/master/LICENSE'}]
注意:
在属性中“from”必填,且必须是Nodemailer传输器中已经授权的邮箱。否则会出现错误在属性中“to,cc,bcc”三者都表示发送到邮箱的地址。可以同时选则多个属性,每个属性也可以同时添加多个目标地址,但是不能三个属性一个收件地址都不填。subject,text,html,attachments可以为空。当他们为空时会发送空邮件。磁盘文件只能使用path路径,网络连接可以使用path或href。附件名称可以修改,可以与文件名称不一致。在设置对象中有两个属性分别是text、和html。这两个对象都是邮件需要发送的内容,当html为空时,邮件会发送空的文本。当html不为空时,html会覆盖text内容(邮件主体呈现出html内容,而不显示text内容)。所有文本字段(电子邮件地址、明文主体、html主体、附件文件名)都使用UTF-8作为编码。附件是以二进制方式传输的。c.sendMail()方法传递消息对象

使用了这个方法之后,邮件请求就发送到了SMTP服务器中了。


nodemailer.sendMail(object,callback(err,info))

object就是第二步创建的邮件信息对象对象
回调函数有两个参数,一个是错误信息,一个是发送的信息
3.获取邮件(使用imap和nodemailer模块)

在获取邮件的时候,无非就是以下几个步骤:


连接到服务器—打开指定邮箱----筛选(操作)邮件----解析邮件----查看结果


varImap=require('imap'),
inspect=require('util').inspect;
varimap=newImap({
user:'[email protected]',
password:'mygmailpassword',
host:'imap.gmail.com',
port:993,
tls:true
functionopenInbox(cb){
imap.openBox('INBOX',true,cb);
imap.once('ready',function(){
openInbox(function(err,box){
if(err)throwerr;
varf=imap.seq.fetch('1:3',{
bodies:'HEADER.FIELDS(FROMTOSUBJECTDATE)',
struct:true
f.on('message',function(msg,seqno){
console.log('Message#%d',seqno);
varprefix='(#'+seqno+')';
msg.on('body',function(stream,info){
varbuffer='';
stream.on('data',function(chunk){
buffer+=chunk.toString('utf8');
stream.once('end',function(){
console.log(prefix+'Parsedheader:%s',inspect(Imap.parseHeader(buffer)));
msg.once('attributes',function(attrs){
console.log(prefix+'Attributes:%s',inspect(attrs,false,8));
msg.once('end',function(){
console.log(prefix+'Finished');
f.once('error',function(err){
console.log('Fetcherror:'+err);
f.once('end',function(){
console.log('Donefetchingallmessages!');
imap.end();
imap.once('error',function(err){
console.log(err);
imap.once('end',function(){
console.log('Connectionended');
imap.connect();

a.连接邮箱
构造器:使用指定的配置对象创建并返回Connection的新实例。设置需要连接到哪一个服务器

varimap=newImap({
user:'[email protected]',//你的邮箱账号
password:'xxx',//你的邮箱邀请码
host:'imap.qq.com',//邮箱服务器的主机地址
port:993,//邮箱服务器的端口地址
tls:true,//使用安全传输协议
tlsOptions:{rejectUnauthorized:false}//禁用对证书有效性的检查
connTimeout:10000,//链接超时等待数,默认10000毫秒
authTimeout:5000,//身份验证的毫秒数

与服务器构建链接:connect()

imap.connect();
//链接邮箱,并身份验证

与服务器断开链接:end(),destroy()

imap.end();
//当所有的请求结束后,断开链接
imap.destroy();
//忽略正在传输的内容,立即断开链接

b.打开指定邮箱
获取所有邮箱列表:getBoxes

imap.getBoxes(function(err,box){
//box就是邮箱的列表
//box具体内容如下:
//INBOX:收件箱
//SentMessages:发送的邮件
//Drafts:草稿箱
//Deleted:删除邮件
//Junk:垃圾邮件

打开邮箱:openBox(stringmailboxName[,booleanopenReadOnly=false],functioncallback)

imap.openBox('INBOX',true,function(err,box){
//打开邮箱后的操作

关闭邮箱:closeBox([booleanautoExpunge=true,]functioncallback)

imap.closeBox(true,function(err){
//如果关闭失败,触发回调函数


?注意:这里的第一个参数可选,默认是true。如果autoExpunge为真,则在当前打开的邮箱中标记为Deleted的任何消息都将被删除,如果邮箱未在只读模式下打开。如果autoExpunge为false,则断开连接或打开另一个邮箱,标记为Deleted的消息将不会从当前打开的邮箱中删除。

addBox,delBox,renameBox等一些不常用的方法参考npm-imap文档:https://www.npmjs.com/package/imap
c.筛选(操作)邮件


搜索邮件:search(arraycriteria,functioncallback)


callback函数有两个参数(err,list)list是符合要求的UID数组


UID是邮箱用来标识你这个账户的每一封邮件的编号


})//搜索UID为430及以上的邮件
imap.search([['UID','430:450','491']],function(err,list){
console.log(box);
})//搜索UID为430到450或491的邮件

ALL:查找所有邮件
UNSEEN:查找未读信息
UNSEEN:查找已读信息
ANSWERED:已经回复后的消息

imap.search(['ALL'],function(err,list){
console.log(box);
})//搜索所有邮件
//其他功能替换ALL即可

‘BEFORE’-在指定日期之前的所有邮件
‘ON’-在指定日期当天的邮件
‘SINCE’-在指定日期及之后的邮件

imap.search([['BEFORE','2018/12/7']],function(err,list){
console.log(box);
})//搜索所有邮件
//第二个参数为,js可以解析的日期字符串或日期对象

‘LARGER’:邮件的大小大于指定字节数。
‘SMALLER’:邮件的大小小于指定字节数。

imap.search([['LARGER',1280]],function(err,list){
console.log(box);
})//搜索所有邮件
//第二个参数为int类型的数字

数组嵌套表示且
数组结合‘OR’表示或

['UNSEEN',['SINCE','April20,2010']]
[['OR','UNSEEN',['SINCE','April20,2010']]]


注意:

国内的邮件服务商,并没有对所有的search语句进行实现。建议大家使用Gmail。
以上只列出了一些常用方法,全部方法请参考:https://www.npmjs.com/package/imap
d.抓取邮件内容
fetch(MessageSourcesource,objectoptions)

source表示UID数组,options表示可以添加的属性,return


options属性:

bodies选择抓取的部分
‘HEADER’-头部信息
‘TEXT’-邮件主体
‘’-全部信息(头部+主体)
其他属性参考:https://www.npmjs.com/package/imap


varf=imap.fetch([491,496,493],{bodies:''});
f.on('message',function(msg,seqno){
//msg是抓取对应邮件的事件触发器
//seqno是邮件在邮箱的编号(不是UID)
msg.on('body',function(stream,info){
//stream表示可读流,是邮件内容的流
//info邮件的基础信息,包括大小编号
})//当对应邮件接收流触发
msg.on('end',function(){
})//当对应邮件所有内容接收完后触发
//抓取完一封邮件后触发
f.once('error',function(err){})
//抓去错误后触发
f.once('end',function(){})
//所有邮件抓取结束后触发


注意:



f本身就是一个事件的触发器,每抓取一封邮件,message的回调函数会执行,生成对应的那一封邮件的触发器msg


e.邮件内容解析–使用mailparser

f.on('message',function(msg,seqno){
varmailparser=newMailParser();
//每封邮件添加一个mailparser
msg.on('body',function(stream,info){
stream.pipe(mailparser);
//将为解析的数据流pipe到mailparser
mailparser.on("headers",function(headers){
//headers是Map类型
console.log("邮件主题:"+headers.get('subject'));
console.log("发件人:"+headers.get('from').text);
console.log("收件人:"+headers.get('to').text);
//当邮件头部流全部传入mailparser后触发
mailparser.on("data",function(data){
//data是对象
if(data.type==='text'){
console.log("邮件内容:"+data.html);
if(data.type==='attachment'){
console.log("附件名称:"+data.filename);
data.content.pipe(fs.createWriteStream(data.filename));
//保存附件到当前目录下
data.release();

四、总结

在这次的邮件服务器研究过程中,有一些问题没有深入分析,只是学习了基本使用方法。比如:在抓取邮件的过程中,涉及到了流式传输,这里没有再深入分析。


这一篇文件主要由官方文档学习所得,其中有些部分是我自己理解并试验得到的。如果哪些部分有误,请大家帮忙指出。


nodejs模块nodemailer基本使用-邮件发送(支持附件)07-113万+

最新新闻

手机浏览

公理网 版权所有

公理网 Total 0.036300(s) query 6, 报料QQ:点击这里

给我发消息