2013-02-27 60 views
4

我有这个系统,它尝试发送用NodeJS编写的批量电子邮件。错误:在errnoException中写入EPIPE(net.js:770:11)

它使用2个模块:fs(构建到节点v0.8.18)和nodemailer(来自NPM,v0.3.42)。

现在在与node newsletter.js执行有时它会完成和完成,但有时它会在与下面的错误随机点随机失败:

stream.js:81 
     throw er; // Unhandled stream error in pipe. 
      ^
Error: write EPIPE 
    at errnoException (net.js:770:11) 
    at Object.afterWrite (net.js:594:19) 

据我理解,因为对方发生EPIPE错误连接结束后,我们试图写入该连接。所有现有的EPIPE错误错误报告都是在打开http连接或类似的情况下进行的。

在我下面的两件事情中可能导致错误的是NewsletterEmail中的fs.readFileSync或NewsleterMailer中的mailer.send。它更可能是错误将在mailer.send和nodemailer打开连接的地方。但是,没有错误是通过throw或回调错误参数传递回来的,所以似乎无法查看导致错误的原因。

大多数人建议定义一个错误处理程序。然而,nodemailer或fs模块中没有任何东西允许我定义错误处理程序。来自mailer.send调用的nodemailer中的回调函数在其回调函数中传递了一个错误参数,但是这个特定的错误并没有通过那里。

我曾尝试以下的事情:

  • 将两个fs.readFileSync周围的try/catch和nodemailer运输sendEmail电话。
  • 删除fs.readFileSync调用并内联html - 当我这样做时,错误似乎不会发生。但是同样,节点文档没有指出在readFileSync上应该发生EPIPE错误,并且肯定没有办法添加错误处理程序。

触发此错误的代码如下:

var nodemailer = require('nodemailer'); 
var fs = require('fs'); 

/** 
* Provides a way to build newsletters when given a folder containing 
* the relevant template and images in a standard format. This folder 
* must contain a newsletter.html file, a newsletter.txt file and a images 
* directory containing any images. 
* 
* @param {Object} settings The full folder path to the 
*/ 
function NewsletterEmail(newsletterGroup, newsletterName) 
{ 
    var folder = '/var/newsletters/' + newsletterGroup + '/' + newsletterName; 
    this._html = fs.readFileSync(folder + '/newsletter.html', 'utf-8'); 
    this._text = fs.readFileSync(folder + '/newsletter.txt', 'utf-8'); 
} 

NewsletterEmail.prototype.getSubject = function() 
{ 
    return 'Testing'; 
} 

/** 
* Generates the HTML version of a newsletter. 
* 
* @return {String} 
*/ 
NewsletterEmail.prototype.buildHTML = function(email) 
{ 
    var htmlPart = this._html; 

    return htmlPart; 
} 

/** 
* Generates the text counterpart of a newsletter. 
* 
* @return {String} 
*/ 
NewsletterEmail.prototype.buildText = function(email) 
{ 
    var textPart = this._text; 

    return textPart; 
} 

/** 
* Creates a NewsletterEmail from the given folder. 
* 
* @param {String} folder The folder containing the html template, text template and images for a newsletter. 
* @return {NewsletterEmail} 
*/ 
NewsletterEmail.create = function(newsleterGroup, newsletterName) { 
    return new NewsletterEmail(newsleterGroup, newsletterName); 
} 

function NewsletterMailer(fromEmail) 
{ 
    this._from = fromEmail; 
    this._transport = nodemailer.createTransport('sendmail'); 
} 

NewsletterMailer.prototype = { 
    send: function(email, newsletterEmail, callback) { 
     var mailOptions = { 
      to: email, 
      from: this._from, 
      subject: newsletterEmail.getSubject(), 
      html: newsletterEmail.buildHTML(email), 
      text: newsletterEmail.buildText(email) 
     }; 

     this._transport.sendMail(mailOptions, callback); 

    }, 

    close: function() { 
     this._transport.close(); 
    } 
} 

function Newsletter() 
{ 
    this._id = 1; 
    this.countSent = 0; 
    this.emailsToSend = ['[email protected]', '[email protected]', '[email protected]', '[email protected]', '[email protected]', '[email protected]']; 
} 

Newsletter.prototype.send = function() { 
    var newsletter = this; 

    var newsletterEmail = NewsletterEmail.create('company1', '2013-01-24-mynewsleter'); 
    var mailer = new NewsletterMailer('[email protected]'); 

    function sendEmail() { 
     var email = newsletter.emailsToSend.pop(); 

     mailer.send(email, newsletterEmail, function(mailerErr) { 
      if (mailerErr) { 
       console.log('Mailer error: ', mailerErr); 
      } 

      newsletter.countSent++; 

      console.log('progress ' + newsletter.countSent); 

      if (newsletter.emailsToSend.length > 0) { 
       sendEmail(); 
      } 
      else { 
       mailer.close(); 
       console.log('complete'); 
      } 
     }); 
    } 

    sendEmail(); 
} 

var nl = new Newsletter(); 
nl.send(); 

有其他人碰到类似的错误?你有任何关于调试或可能的解决方案的提示。

现在给出的堆栈跟踪已经有点死胡同了。以下是strace的输出。似乎总是邮件mimepart边界第一上模具:

futex(0x7f039c0008c8, FUTEX_WAKE_PRIVATE, 1) = 1 
write(8, "------Nodemailer-0.3.42-?=_1-136"..., 131) = -1 EPIPE (Broken pipe) 
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=13813, si_uid=0} --- 
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=13818, si_status=0, si_utime=0, si_stime=0} --- 
write(4, "\1\0\0\0\0\0\0\0", 8)   = 8 
rt_sigreturn()       = -1 EPIPE (Broken pipe) 
futex(0x7f039c0008c8, FUTEX_WAKE_PRIVATE, 1) = 1 
write(8, "<!DOCTYPE HTML PUBLIC =22-//W3C/"..., 18098) = -1 EPIPE (Broken pipe) 
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=13813, si_uid=0} --- 
futex(0x7f039c0008c8, FUTEX_WAKE_PRIVATE, 1) = 1 
close(8)        = 0 
epoll_wait(3, {{EPOLLIN|EPOLLHUP, {u32=9, u64=4294967305}}, {EPOLLIN|EPOLLHUP, {u32=11, u64=4294967307}}, {EPOLLIN, {u32=4, u64=4294967300}}}, 64, 0) = 3 
epoll_ctl(3, EPOLL_CTL_MOD, 9, {EPOLLIN, {u32=9, u64=4294967305}}) = 0 
epoll_ctl(3, EPOLL_CTL_MOD, 11, {EPOLLIN, {u32=11, u64=4294967307}}) = 0 
read(4, "\1\0\0\0\0\0\0\0", 8)   = 8 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED|WCONTINUED, NULL) = 13818 
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7fff2d6f4340) = -1 EINVAL (Invalid argument) 
fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0 
write(1, "progress 1\n", 11progress 1 
)   = 11 
socketpair(PF_FILE, SOCK_STREAM|SOCK_CLOEXEC, 0, [7, 8]) = 0 
socketpair(PF_FILE, SOCK_STREAM|SOCK_CLOEXEC, 0, [10, 12]) = 0 
socketpair(PF_FILE, SOCK_STREAM|SOCK_CLOEXEC, 0, [13, 14]) = 0 
pipe2([15, 16], O_NONBLOCK|O_CLOEXEC) = 0 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f03a4b35a10) = 13820 
close(16)        = 0 
poll([{fd=15, events=POLLIN|POLLHUP}], 1, -1) = 1 ([{fd=15, revents=POLLHUP}]) 
close(15)        = 0 
close(7)        = 0 
ioctl(8, FIONBIO, [1])     = 0 
close(12)        = 0 
ioctl(10, FIONBIO, [1])     = 0 
close(14)        = 0 
ioctl(13, FIONBIO, [1])     = 0 
wait4(-1, 0x7fff2d6f529c, WNOHANG|WSTOPPED|WCONTINUED, NULL) = 0 
futex(0x7f039c0008c8, FUTEX_WAKE_PRIVATE, 1) = 1 
brk(0x932000)       = 0x932000 
read(11, "", 65536)      = 0 
close(11)        = 0 
read(9, "", 65536)      = 0 
futex(0x7f039c0008c8, FUTEX_WAKE_PRIVATE, 1) = 1 
close(9)        = 0 
write(2, "\n", 1 
)      = 1 
write(2, "events.js:71\n", 13events.js:71 
+0

的错误,所以我会假设它是与nodemailer的问题。如果您正在运行Linux,请尝试使用strace运行Node,可能是由于某种原因,MTA只是挂起了连接。 – robertklep 2013-02-27 17:31:22

+0

感谢strace提示。让我看看它实际上在做什么。用strace的输出更新了帖子。不知道它真的告诉我多么真诚。我真的会认为nodemailer会处理像MTA挂起的事情,并通过回调中的错误参数报告它,以便处理它。 – rikkiloades 2013-02-27 21:34:14

+0

退房http://stackoverflow.com/a/12267735/893780(特别是安装sendmail的评论) – robertklep 2013-02-27 21:42:59

回答

5

这是由nodemailer模块包装线在75个字符而引起的。一行最后只有76个字符,并带有一个点。这个点被包装在自己的线上。

对于SMTP服务器,线上的点本身表示消息的结束并且连接已关闭。这导致连接过早关闭,随后的写入失败并出现EPIPE错误。

随着nodemailer维护者这已得到修复的问题0.3.43的帮助下加入兴田-i标志sendmail的调用,它告诉sendmail来允许与单点划线。

更多详情请点击这里:https://github.com/andris9/Nodemailer/issues/141。在`Socket.write`(net.js)发生

+0

感谢分享,一段时间以来一直困扰着我 – galchen 2013-03-03 13:48:11