express-14 发送邮件

简介

Node和Express都没有内置的邮件发送功能,所以必须使用第三方模块。推荐Andris Reinman的Nodemailer

SMTP、MSA和MTA

  • 发送邮件的通用语言是简单邮件传输协议(SMTP)

  • 尽管用SMTP直接发送一封邮件给接收者的邮件服务器是有可能的,但这通常是个非常糟糕的主意。除非是像Google或Yahoo!那样的“值得信任的发送者”,否则邮件很可能会直接被扔进垃圾箱。

  • 用邮件提交代理(MSA)比较好,它会通过可信的渠道投递邮件,降低邮件被标记为垃圾邮件的可能性。

  • 除了确保邮件成功送达,MSA还处理诸如临时故障造成的滋扰和退回的邮件。

  • 邮件传输代理(MTA),它提供将邮件真正送到其最终目的地的服务。

  • 像Gmail、Hotmail、iCloud这样的MSA是有邮件限制的;一旦准备好进入生产环境,可以切换到Sendgrid或亚马逊简单Email服务(SES)之类的专业MSA。

邮件头

  • 邮件消息由两部分组成:头部和主体。

  • 头部包含与邮件有关的信息:谁发的、发给谁、接收日期、主题等; 头信息给了所有关于邮件如何到达你这里的信息,邮件经过的所有服务器和MTA都会在头部里列出来。

  • “from”地址,它可以由发送方任意设定。当指定的“from”地址不是发送邮件的账号时,经常被当作“欺诈”; 不是在建议你尝试这种行为。

  • 然而发送的邮件必须有“from”地址。有时这在发送自动邮件时会出现问题,因此经常会出现像“不要回复do-not-reply@meadowlarktravel.com”之类的返回地址。不管是想采取这种方式,还是将发送地址设为“草地鹨旅行社 info@meadowlarktravel.com”,都完全取决于你。不过如果你采用了后一种方式,就要准备好答复发给info@meadowlarktravel.com的邮件。

邮件格式

  • 互联网刚出现的时候,所有邮件都是简单的ASCII文本。

  • Nodemailer可以处理

  • 邮件既可以是普通文本(Unicode),也可以是HTML; 建议总是包含文本和HTML两种格式的邮件;

  • 几乎所有现代的邮件程序都支持HTML邮件,所以用HTML作为邮件格式一般相当安全。

Nodemailer

//简单例子
var nodemailer = require('nodemailer');

var transporter = nodemailer.createTransport({
    service: 'Gmail',
    auth: {
        user: credentials.gmail.user,
        pass: credentials.gmail.password
    }
});
  var mailOptions = {
      from: 'Fred Foo  <foo@blurdybloop.com>', // sender address 
      to: 'one@gmail.com ,tow@gmail.com', // list of receivers 
      subject: 'Hello ', // Subject line 
      text: 'Hello world ', // plaintext body 
      html: '<b>Hello world </b>' // html body 
  };
transporter.sendMail(mailOptions, function(error, info){
      if(error){
          console.log(error);
      }else{
          console.log('Message sent: ' + info.response);
      }
  });

Nodemailer为大多数流行的邮件服务提供了快捷方式:Gmail、Hotmail、iCloud、Yahoo!,除此之外还有很多。如果你的MSA没有出现在这个列表上,或者你需要直接连接一个SMTP服务器,它也支持:

var mailTransport = nodemailer.createTransport('SMTP',{ 
    host: 'smtp.meadowlarktravel.com', 
    secureConnection: true,     //用SSL 端口: 465
    auth: {
      user: credentials.meadowlarkSmtp.user,
      pass: credentials.meadowlarkSmtp.password,
    }
});

发送邮件

  • 在这里处理了错误,但没有错误不一定表示邮件成功发给了接收者:只有在跟MSA通信出现问题时才会设置回调函数的err参数(比如网络或授权错误)。如果MSA不能投递邮件(比如因为无效的邮件地址或者未知的用户),你会收到一封投递给MSA账号的失败邮件(比如你用自己的个人Gmail作为MSA,你的Gmail收件箱中就会收到一封失败消息)。

  • 如果你需要系统自动判断邮件是否投递成功,有两个选择。一是使用支持错误报告的MSA。亚马逊的简单邮件服务(SES)就是这样的服务,并且邮件退信通知是通过他们的简单通知服务(SNS)发送的,你可以配置其调用运行在你网站上的Web服务。另一个选择是使用直接投递,跳过MSA。不推荐使用直接投递,因为它是一个复杂的方案,并且你的邮件很可能会被标记为垃圾邮件。

将邮件发送给多个接收者

在向多个接收者发送邮件时,必须注意观察MSA的限制。比如Gmail,每封邮件的接收者上限是100个。如果发送批量邮件,可能要发送多条消息,每条消息有多个接收者:

var recipientLimit = 100;
for(var i=0; i<largeRecipientList.length/recipientLimit; i++){
    mailTransport.sendMail({
      from: '"Meadowlark Travel" <info@meadowlarktravel.com>',
      to: largeRecipientList
        .slice(i*recipientLimit, i*(recipientLimit+1)).join(','),
      subject: 'Special price on Hood River travel package!',
      text: 'Book your trip to scenic Hood River now!',
    }, function(err){
      if(err) console.error( 'Unable to send email: ' + error );
    });
  }

发送批量邮件的更佳选择

尽管确实可以通过Nodemailer和恰当的MSA发送批量邮件,但在这样做之前你应该细心考虑。一个负责任的邮件营销必须提供一种退订营销邮件的办法,并且这不是个轻而易举的任务。还要乘以你维护的每个订阅列表。像MailChimpCampaign Monitor之类的服务提供了你需要的一切,包括监测邮件营销成功情况的优秀工具.

发送HTML邮件

Nodemailer允许你在同一封邮件里发送HTML和普通文本两种版本,让邮件客户端选择显示哪个版本(一般是HTML):

mailTransport.sendMail({
    from: '"Meadowlark Travel" <info@meadowlarktravel.com>',
    to: 'joecustomer@gmail.com, "Jane Customer" ' +
        '<janecustomer@gyahoo.com>, frecsutomer@hotmail.com',
    subject: 'Your Meadowlark Travel Tour',
    html: '<h1>Meadowlark Travel</h1>\n<p>Thanks for book your trip with ' +
        'Meadowlark Travel. <b>We look forward to your visit!</b>',
    generateTextFromHtml: true,  //使用
}, function(err){
    if(err) console.error( 'Unable to send email: ' + error );
});

HTML邮件中的图片

  • 尽管可以在HTML邮件中嵌入图片,但强烈反对这样做,因为它们会使你的邮件变得臃肿,并且一般会被当成不好的做法。相反,应该把用在邮件中的图片放在Web服务器上,并在邮件中放入正确的链接。

  • 当发送邮件给其他人时,很明显不应该用localhost; 根据所用的邮件客户端,或许可以在你的邮件中用localhost来进行测试,但在你的机器之外是行不通的。

封装邮件功能

//lib/email.js

var nodemailer = require('nodemailer');

module.exports = function(credentials){
  var mailTransport = nodemailer.createTransport({
    service: 'Gmail',
    auth: {
      user: credentials.gmail.user,
      pass: credentials.gmail.password,
    } 
  });

  var from = '"example" <example@example.com>';
  var errorRecipient = credentials.gmail.user;

  return {
    send: function(to, subj, body){
        mailTransport.sendMail({
            from: from,
            to: to,
            subject: subj,
            html: body, 
            generateTextFromHtml: true
        }, function(err, info){
            if(err) {
            	console.error('Unable to send email: ' + err);
            } else {
            	console.log('Message sent: ' + info.response);
            }
        }); 
    },

    emailError: function(message, filename, exception){
      var body = '<h1>Meadowlark Travel Site Error</h1>' +
        'message:<br><pre>' + message + '</pre><br>'; 
      if(exception) body += 'exception:<br><pre>' + exception
        + '</pre><br>';
      if(filename) body += 'filename:<br><pre>' + filename
                                      + '</pre><br>';
      mailTransport.sendMail({
        from: from,
        to: errorRecipient,
        subject: 'Meadowlark Travel Site Error', 
        html: body,
        generateTextFromHtml: true
      }, function(err){
        if(err) console.error('Unable to send email: ' + err);
      }); 
    },
  }
};

//发送调用
var emailService = require('./lib/email.js')(credentials);

emailService.send('joecustomer@gmail.com', 'Hood River tours on sale today!',
  'Get \'em while they\'re hot!');

将邮件作为网站监测工具

if(err){
  email.sendError('the widget broke down!', __filename); 
  // ……给用户显示错误消息
}

// 或者

try {
  // 在这里做些不确定的事情......
} catch(ex) {
  email.sendError('the widget broke down!', __filename, ex); 
  // ……给用户显示错误消息
}
posted @ 2015-03-19 15:08  JinksPeng  阅读(842)  评论(0编辑  收藏  举报