2013-09-05 16:02:48 +02:00
/ * *
2014-05-13 12:39:59 +02:00
* Copyright 2013 , 2014 IBM Corp .
2013-09-05 16:02:48 +02:00
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* * /
2014-05-04 00:32:04 +02:00
module . exports = function ( RED ) {
2014-05-29 23:13:21 +02:00
"use strict" ;
2014-05-04 00:32:04 +02:00
var nodemailer = require ( "nodemailer" ) ;
2014-08-18 16:47:37 +02:00
var Imap = require ( 'imap' ) ;
2014-05-13 12:39:59 +02:00
2014-05-04 00:32:04 +02:00
//console.log(nodemailer.Transport.transports.SMTP.wellKnownHosts);
2014-05-13 12:39:59 +02:00
2014-08-18 18:15:14 +02:00
try {
var globalkeys = RED . settings . email || require ( process . env . NODE _RED _HOME + "/../emailkeys.js" ) ;
} catch ( err ) {
}
2014-05-13 12:39:59 +02:00
2014-05-04 00:32:04 +02:00
function EmailNode ( n ) {
RED . nodes . createNode ( this , n ) ;
this . topic = n . topic ;
this . name = n . name ;
this . outserver = n . server ;
this . outport = n . port ;
var flag = false ;
2014-08-18 18:15:14 +02:00
if ( this . credentials && this . credentials . hasOwnProperty ( "userid" ) ) {
this . userid = this . credentials . userid ;
} else {
if ( globalkeys ) {
this . userid = globalkeys . user ;
flag = true ;
} else {
this . error ( "No e-mail userid set" ) ;
}
}
if ( this . credentials && this . credentials . hasOwnProperty ( "password" ) ) {
this . password = this . credentials . password ;
} else {
if ( globalkeys ) {
this . password = globalkeys . pass ;
flag = true ;
} else {
this . error ( "No e-mail password set" ) ;
}
2014-05-02 15:37:41 +02:00
}
2014-08-18 18:15:14 +02:00
if ( flag ) {
RED . nodes . addCredentials ( n . id , { userid : this . userid , password : this . password , global : true } ) ;
2014-05-02 15:37:41 +02:00
}
2014-05-04 00:32:04 +02:00
var node = this ;
2014-05-13 12:39:59 +02:00
2014-08-18 16:47:37 +02:00
var smtpTransport = nodemailer . createTransport ( {
2014-05-04 00:32:04 +02:00
host : node . outserver ,
port : node . outport ,
2014-08-18 16:47:37 +02:00
secure : true ,
2014-05-04 00:32:04 +02:00
auth : {
user : node . userid ,
pass : node . password
}
} ) ;
2014-05-13 12:39:59 +02:00
2014-05-04 00:32:04 +02:00
this . on ( "input" , function ( msg ) {
2015-03-31 10:21:11 +02:00
if ( msg . hasOwnProperty ( "payload" ) ) {
if ( smtpTransport ) {
node . status ( { fill : "blue" , shape : "dot" , text : "sending" } ) ;
if ( msg . to && node . name && ( msg . to !== node . name ) ) {
node . warn ( "Warning: msg properties can no longer override set node properties. See bit.ly/nr-override-msg-props" ) ;
2015-02-08 12:33:04 +01:00
}
2015-03-31 10:21:11 +02:00
var sendopts = { from : node . userid } ; // sender address
sendopts . to = node . name || msg . to ; // comma separated list of addressees
sendopts . subject = msg . topic || msg . title || "Message from Node-RED" ; // subject line
if ( Buffer . isBuffer ( msg . payload ) ) { // if it's a buffer in the payload then auto create an attachment instead
sendopts . attachments = [ { content : msg . payload , filename : ( msg . filename . replace ( /^.*[\\\/]/ , '' ) || "file.bin" ) } ] ;
if ( msg . hasOwnProperty ( "headers" ) && msg . headers . hasOwnProperty ( "content-type" ) ) {
sendopts . attachments [ 0 ] . contentType = msg . headers [ "content-type" ] ;
}
// Create some body text..
sendopts . text = "Your file from Node-RED is attached : " + ( msg . filename . replace ( /^.*[\\\/]/ , '' ) || "file.bin" ) + ( msg . hasOwnProperty ( "description" ) ? "\n\n" + msg . description : "" ) ;
2014-09-08 22:10:06 +02:00
}
2015-03-31 10:21:11 +02:00
else {
var payload = RED . util . ensureString ( msg . payload ) ;
sendopts . text = payload ; // plaintext body
if ( /<[a-z][\s\S]*>/i . test ( payload ) ) { sendopts . html = payload ; } // html body
if ( msg . attachments ) { sendopts . attachments = msg . attachments ; } // add attachments
}
smtpTransport . sendMail ( sendopts , function ( error , info ) {
if ( error ) {
node . error ( error , msg ) ;
node . status ( { fill : "red" , shape : "ring" , text : "send failed" } ) ;
} else {
node . log ( "Message sent: " + info . response ) ;
node . status ( { } ) ;
}
} ) ;
}
else { node . warn ( "No Email credentials found. See info panel." ) ; }
2014-05-04 00:32:04 +02:00
}
2015-03-31 17:39:00 +02:00
else { node . warn ( "No payload to send" ) ; }
2014-05-04 00:32:04 +02:00
} ) ;
2014-05-02 15:37:41 +02:00
}
2014-08-18 18:15:14 +02:00
RED . nodes . registerType ( "e-mail" , EmailNode , {
credentials : {
userid : { type : "text" } ,
password : { type : "password" } ,
global : { type : "boolean" }
2014-09-03 20:34:52 +02:00
}
2014-08-18 18:15:14 +02:00
} ) ;
2014-05-13 12:39:59 +02:00
2014-05-04 00:32:04 +02:00
function EmailInNode ( n ) {
RED . nodes . createNode ( this , n ) ;
this . name = n . name ;
this . repeat = n . repeat * 1000 || 300000 ;
2014-09-08 20:59:22 +02:00
this . inserver = n . server || globalkeys . server || "imap.gmail.com" ;
this . inport = n . port || globalkeys . port || "993" ;
2015-04-11 17:09:13 +02:00
this . box = n . box || "INBOX" ;
2014-05-04 00:32:04 +02:00
var flag = false ;
2014-09-03 20:34:52 +02:00
2014-08-18 18:15:14 +02:00
if ( this . credentials && this . credentials . hasOwnProperty ( "userid" ) ) {
this . userid = this . credentials . userid ;
} else {
if ( globalkeys ) {
this . userid = globalkeys . user ;
flag = true ;
} else {
this . error ( "No e-mail userid set" ) ;
}
}
if ( this . credentials && this . credentials . hasOwnProperty ( "password" ) ) {
this . password = this . credentials . password ;
} else {
if ( globalkeys ) {
this . password = globalkeys . pass ;
flag = true ;
} else {
this . error ( "No e-mail password set" ) ;
}
2014-05-04 00:32:04 +02:00
}
2014-08-18 18:15:14 +02:00
if ( flag ) {
RED . nodes . addCredentials ( n . id , { userid : this . userid , password : this . password , global : true } ) ;
2014-05-04 00:32:04 +02:00
}
2014-08-18 18:15:14 +02:00
2014-05-04 00:32:04 +02:00
var node = this ;
this . interval _id = null ;
var oldmail = { } ;
2014-05-13 12:39:59 +02:00
2014-05-04 00:32:04 +02:00
var imap = new Imap ( {
user : node . userid ,
password : node . password ,
host : node . inserver ,
port : node . inport ,
tls : true ,
tlsOptions : { rejectUnauthorized : false } ,
connTimeout : node . repeat ,
authTimeout : node . repeat
} ) ;
2014-05-13 12:39:59 +02:00
2014-05-04 00:32:04 +02:00
if ( ! isNaN ( this . repeat ) && this . repeat > 0 ) {
node . log ( "repeat = " + this . repeat ) ;
this . interval _id = setInterval ( function ( ) {
node . emit ( "input" , { } ) ;
} , this . repeat ) ;
}
2014-05-13 12:39:59 +02:00
2014-05-04 00:32:04 +02:00
this . on ( "input" , function ( msg ) {
imap . once ( 'ready' , function ( ) {
2014-05-30 21:30:26 +02:00
node . status ( { fill : "blue" , shape : "dot" , text : "fetching" } ) ;
2014-05-04 00:32:04 +02:00
var pay = { } ;
2015-04-11 17:09:13 +02:00
imap . openBox ( node . box , false , function ( err , box ) {
2014-05-04 00:32:04 +02:00
if ( box . messages . total > 0 ) {
2015-04-11 17:09:13 +02:00
var f = imap . seq . fetch ( box . messages . total + ':*' , { markSeen : true , bodies : [ 'HEADER.FIELDS (FROM SUBJECT DATE TO CC BCC)' , 'TEXT' ] } ) ;
2014-05-04 00:32:04 +02:00
f . on ( 'message' , function ( msg , seqno ) {
node . log ( 'message: #' + seqno ) ;
var prefix = '(#' + seqno + ') ' ;
msg . on ( 'body' , function ( stream , info ) {
var buffer = '' ;
stream . on ( 'data' , function ( chunk ) {
buffer += chunk . toString ( 'utf8' ) ;
} ) ;
stream . on ( 'end' , function ( ) {
if ( info . which !== 'TEXT' ) {
2015-04-11 17:09:13 +02:00
var head = Imap . parseHeader ( buffer ) ;
if ( RED . settings . verbose ) { node . log ( head ) ; }
pay . from = head . from [ 0 ] ;
pay . topic = head . subject [ 0 ] ;
pay . date = head . date [ 0 ] ;
if ( head . hasOwnProperty ( "to" ) ) { pay . to = head . to ; }
if ( head . hasOwnProperty ( "cc" ) ) { pay . cc = head . cc ; }
if ( head . hasOwnProperty ( "bcc" ) ) { pay . bcc = head . bcc ; }
2014-05-04 00:32:04 +02:00
} else {
var parts = buffer . split ( "Content-Type" ) ;
2014-09-03 20:34:52 +02:00
for ( var p = 0 ; p < parts . length ; p ++ ) {
2014-05-04 00:32:04 +02:00
if ( parts [ p ] . indexOf ( "text/plain" ) >= 0 ) {
pay . payload = parts [ p ] . split ( "\n" ) . slice ( 1 , - 2 ) . join ( "\n" ) . trim ( ) ;
}
2015-04-11 17:48:50 +02:00
else if ( parts [ p ] . indexOf ( "text/html" ) >= 0 ) {
2014-05-04 00:32:04 +02:00
pay . html = parts [ p ] . split ( "\n" ) . slice ( 1 , - 2 ) . join ( "\n" ) . trim ( ) ;
2015-04-11 17:48:50 +02:00
} else {
pay . payload = parts [ 0 ] ;
2014-05-04 00:32:04 +02:00
}
2014-05-02 15:37:41 +02:00
}
2014-05-04 00:32:04 +02:00
//pay.body = buffer;
2014-05-02 15:37:41 +02:00
}
2014-05-04 00:32:04 +02:00
} ) ;
} ) ;
msg . on ( 'end' , function ( ) {
//node.log('Finished: '+prefix);
2014-05-02 15:37:41 +02:00
} ) ;
} ) ;
2014-05-04 00:32:04 +02:00
f . on ( 'error' , function ( err ) {
node . warn ( 'fetch error: ' + err ) ;
2014-05-30 21:30:26 +02:00
node . status ( { fill : "red" , shape : "ring" , text : "fetch error" } ) ;
2014-05-02 15:37:41 +02:00
} ) ;
2014-05-04 00:32:04 +02:00
f . on ( 'end' , function ( ) {
2015-04-11 17:09:13 +02:00
delete ( pay . _msgid ) ;
2014-05-04 00:32:04 +02:00
if ( JSON . stringify ( pay ) !== oldmail ) {
oldmail = JSON . stringify ( pay ) ;
2015-04-11 17:09:13 +02:00
node . send ( pay ) ;
2014-05-04 00:32:04 +02:00
node . log ( 'received new email: ' + pay . topic ) ;
}
else { node . log ( 'duplicate not sent: ' + pay . topic ) ; }
2014-05-30 21:30:26 +02:00
//node.status({fill:"green",shape:"dot",text:"ok"});
node . status ( { } ) ;
2014-05-04 00:32:04 +02:00
imap . end ( ) ;
} ) ;
}
else {
node . log ( "you have achieved inbox zero" ) ;
2014-05-30 21:30:26 +02:00
//node.status({fill:"green",shape:"dot",text:"ok"});
node . status ( { } ) ;
2014-05-02 15:37:41 +02:00
imap . end ( ) ;
2014-05-04 00:32:04 +02:00
}
} ) ;
} ) ;
2014-05-30 21:30:26 +02:00
node . status ( { fill : "grey" , shape : "dot" , text : "connecting" } ) ;
2014-05-04 00:32:04 +02:00
imap . connect ( ) ;
2014-05-02 15:37:41 +02:00
} ) ;
2014-05-13 12:39:59 +02:00
imap . on ( 'error' , function ( err ) {
node . log ( err ) ;
2014-05-30 21:30:26 +02:00
node . status ( { fill : "red" , shape : "ring" , text : "connect error" } ) ;
2014-05-13 12:39:59 +02:00
} ) ;
2014-05-04 00:32:04 +02:00
this . on ( "error" , function ( err ) {
node . log ( "error: " , err ) ;
2014-05-02 15:37:41 +02:00
} ) ;
2014-05-13 12:39:59 +02:00
2014-05-04 00:32:04 +02:00
this . on ( "close" , function ( ) {
if ( this . interval _id != null ) {
clearInterval ( this . interval _id ) ;
}
if ( imap ) { imap . destroy ( ) ; }
} ) ;
2014-05-13 12:39:59 +02:00
2014-05-04 00:32:04 +02:00
node . emit ( "input" , { } ) ;
2014-05-02 15:37:41 +02:00
}
2014-08-18 18:15:14 +02:00
RED . nodes . registerType ( "e-mail in" , EmailInNode , {
credentials : {
userid : { type : "text" } ,
password : { type : "password" } ,
global : { type : "boolean" }
2014-09-03 20:34:52 +02:00
}
2014-05-04 00:32:04 +02:00
} ) ;
2014-11-03 14:41:45 +01:00
} ;