用node搭建简单smtp服务器

2013-01-24 21:31

用node搭建简单smtp服务器

by snoopyxdy

at 2013-01-24 13:31:48

original http://snoopyxdy.blog.163.com/blog/static/60117440201302403212169

最近在公司用node写了一个小程序,搭建一个简单的smtp服务器,用来接收邮件,然后根据邮件的收件人地址,再把内容分发到他rtx、手机短信和外网邮箱上。本来这个功能有个用python写的例子,全部代码不过80行。感叹python这门语言确实精练,而且第三方模块和参考资料比node要多,只需简单的import smtpd模块就可以轻松搞定了,对于MIME解析也只需要import email这个模块。

但是python做不到对email流的精准控制(可能是我不懂怎么弄,py高手别喷啊),而且最近一直在搞node,所以打算用node来实现整个工作流程,顺便也测试下1.0版本的rrestjs框架。

要完成作业,我们面临以下问题:
1、如何用node建立一个smtp服务器,监听25端口
2、如何对MIME流做解析,变成我们想要的subject,text,from,to等我们需要的东西
3、如何把邮件转发外网邮箱

问题1、
在谷歌了一阵子之后,我打算使用substack写的node-smtp-protocol模块,这哥们上次在hujs上见过,长头发很腼腆的一个男孩,他写的模块应该挺靠谱,再说万一有什么问题也方便联系的上他。
github地址:https://github.com/substack/node-smtp-protocol
例子挺简单:

var smtp = require('smtp-protocol');

var server = smtp.createServer(function (req) {
req.on('greeting', function (to, ack) {
ack.accept();
});
req.on('from', function (to, ack) {
ack.accept();
});
req.on('to', function (to, ack) {
filter(to, ack);//过滤smtp请求
});
req.on('message', function (stream, ack) {
serial(stream, ack, req.to);
});
});
server.listen(25);
console.log('starting mail server listen port 25.')

这样我们就建立起来了一个smtp服务器了,我们监听了greeting,from,to和message事件,代码中的ack.accept代表返回状态码250,表示成功,而message则表示客户端开发发送email的body流。
如果在message之前的阶段你想阻拦这次回话,只需要调用 ack.reject()方法拦截掉即可。

搭建起来之后,我只需要用telnet ip 25命令连接上node smtp服务器,测试截屏如下:

用node搭建简单smtp服务器 - snoopyxdy - snoopyxdy的博客
 
当中的^[[A这段无视,打错了,我们成功起来了一个smtp服务器了,当然我们可以在触发 to 或者 from 这些事件时做一下限制,只允许特定来源或者特定目标。

问题2、启动了mail服务器,但是我们对于mail的内容处理还停留在最原始的MIME格式流上,如何正确处理MIME流成为我们获取mail内容的关键问题了,很幸运,我找到了MailParser这个模块。
github地址:https://github.com/andris9/mailparser
这个模块使用起来更加简单,因为node-smtp-protocol模块提供了stream流,所以我们只需写如下代码就可以解析它:
var MailParser = require("mailparser").MailParser;
req.on('message', function (stream, ack) {
stream.pipe(mailparser);
mailparser.on("end", function(mail_object){
console.log(mail_object);//这里就是解析好的mail格式
})
ack.accept();
});

下面我们做一个简单例子,我们用outlook填写一份测试邮件发往node smtp服务器

用node搭建简单smtp服务器 - snoopyxdy - snoopyxdy的博客

在node smtp服务器端输出如下格式的内容
用node搭建简单smtp服务器 - snoopyxdy - snoopyxdy的博客
   
MailParser做的相当的不错,还根据信息中的GBK编码,转换成了utf-8,防止了乱码的产生。
这样问题2我们也圆满解决了,正确解析了MIME流的内容

问题3、似乎不是问题,就不多介绍了,使用 Nodemailer 可以很轻松的转发一封电子邮件,大家都用的很熟了。
github地址:https://github.com/andris9/Nodemailer

完成作业了,似乎用node搭建一个简单smtp服务器不必python费多少劲,但是代码量比python要多出不少。
另外需要注意,在node smtp监听了25端口之前,可能需要把sendmail服务器关闭,否则会存在端口inuse错误。