Merge branch 'master' of github.com:node-red/node-red-nodes

This commit is contained in:
Andreas Martens
2020-10-21 14:20:50 +01:00
38 changed files with 543 additions and 118 deletions

View File

@@ -86,7 +86,7 @@
return this._("email.email");
},
label: function() {
return this.dname||this.name||"email";
return this.dname||this.name||this._("email.email");
},
labelStyle: function() {
return (this.dname)?"node_label_italic":"";
@@ -280,3 +280,37 @@
});
})();
</script>
<script type="text/html" data-template-name="e-mail mta">
<div class="form-row">
<label for="node-input-port"><i class="fa fa-random"></i> <span data-i18n="email.label.port"></span></label>
<input type="text" id="node-input-port" style="width:70%;"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
<div class="form-tips" id="node-tip"><span data-i18n="[html]email.tip.mta"></span></div>
</script>
<script type="text/javascript">
RED.nodes.registerType('e-mail mta',{
category: 'social',
color:"#c7e9c0",
defaults: {
name: {value:""},
port: {value:"1025",required:true},
},
inputs:0,
outputs:1,
icon: "envelope.png",
paletteLabel: function() { return this._("email.email") + " MTA" },
label: function() {
return this.name||this._("email.email") + " MTA";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>

View File

@@ -1,3 +1,4 @@
/* eslint-disable indent */
/**
* POP3 protocol - RFC1939 - https://www.ietf.org/rfc/rfc1939.txt
@@ -11,11 +12,13 @@
module.exports = function(RED) {
"use strict";
var nodemailer = require("nodemailer");
var util = require("util");
var Imap = require('imap');
var POP3Client = require("poplib");
var SimpleParser = require("mailparser").simpleParser;
var util = require("util");
var nodemailer = require("nodemailer");
var simpleParser = require("mailparser").simpleParser;
var SMTPServer = require("smtp-server").SMTPServer;
//var microMTA = require("micromta").microMTA;
if (parseInt(process.version.split("v")[1].split(".")[0]) < 8) {
throw "Error : Requires nodejs version >= 8.";
@@ -291,8 +294,8 @@ module.exports = function(RED) {
// We have now received a new email message. Create an instance of a mail parser
// and pass in the email message. The parser will signal when it has parsed the message.
SimpleParser(data, {}, function(err, parsed) {
//node.log(util.format("SimpleParser: on(end): %j", mailObject));
simpleParser(data, {}, function(err, parsed) {
//node.log(util.format("simpleParser: on(end): %j", mailObject));
if (err) {
node.status({fill:"red", shape:"ring", text:"email.status.parseerror"});
node.error(RED._("email.errors.parsefail", {folder:node.box}), err);
@@ -341,17 +344,29 @@ module.exports = function(RED) {
ss = true;
node.status({fill:"blue", shape:"dot", text:"email.status.fetching"});
//console.log("> ready");
// Open the inbox folder
// Open the folder
imap.openBox(node.box, // Mailbox name
false, // Open readonly?
function(err, box) {
//console.log("> Inbox err : %j", err);
//console.log("> Inbox open: %j", box);
if (err) {
s = false;
var boxs = [];
imap.getBoxes(function(err,boxes) {
if (err) { return; }
for (var prop in boxes) {
if (boxes.hasOwnProperty(prop)) {
if (boxes[prop].children) {
boxs.push(prop+"/{"+Object.keys(boxes[prop].children)+'}');
}
else { boxs.push(prop); }
}
}
node.error(RED._("email.errors.fetchfail", {folder:node.box+". Folders - "+boxs.join(', ')}),err);
});
node.status({fill:"red", shape:"ring", text:"email.status.foldererror"});
node.error(RED._("email.errors.fetchfail", {folder:node.box}),err);
imap.end();
s = false;
setInputRepeatTimeout();
return;
}
@@ -394,7 +409,7 @@ module.exports = function(RED) {
//console.log("> Fetch message - msg=%j, seqno=%d", imapMessage, seqno);
imapMessage.on('body', function(stream, info) {
//console.log("> message - body - stream=?, info=%j", info);
SimpleParser(stream, {}, function(err, parsed) {
simpleParser(stream, {}, function(err, parsed) {
if (err) {
node.status({fill:"red", shape:"ring", text:"email.status.parseerror"});
node.error(RED._("email.errors.parsefail", {folder:node.box}),err);
@@ -412,19 +427,21 @@ module.exports = function(RED) {
var cleanup = function() {
imap.end();
s = false;
setInputRepeatTimeout();
};
if (this.disposition === "Delete") {
if (node.disposition === "Delete") {
imap.addFlags(results, "\Deleted", cleanup);
} else if (this.disposition === "Read") {
} else if (node.disposition === "Read") {
imap.addFlags(results, "\Seen", cleanup);
} else {
cleanup();
}
setInputRepeatTimeout();
});
fetch.once('error', function(err) {
console.log('Fetch error: ' + err);
imap.end();
s = false;
setInputRepeatTimeout();
});
}
@@ -442,7 +459,7 @@ module.exports = function(RED) {
if (node.protocol === "POP3") {
checkPOP3(msg);
} else if (node.protocol === "IMAP") {
if (s === false) { checkIMAP(msg); }
if (s === false && ss == false) { checkIMAP(msg); }
}
} // End of checkEmail
@@ -499,4 +516,61 @@ module.exports = function(RED) {
global: { type:"boolean" }
}
});
function EmailMtaNode(n) {
RED.nodes.createNode(this,n);
this.port = n.port;
var node = this;
node.mta = new SMTPServer({
secure: false,
logger: false,
disabledCommands: ['AUTH', 'STARTTLS'],
onData: function (stream, session, callback) {
simpleParser(stream, { skipTextToHtml:true, skipTextLinks:true }, (err, parsed) => {
if (err) { node.error(RED._("email.errors.parsefail"),err); }
else {
node.status({fill:"green", shape:"dot", text:""});
var msg = {}
msg.payload = parsed.text;
msg.topic = parsed.subject;
msg.date = parsed.date;
msg.header = {};
parsed.headers.forEach((v, k) => {msg.header[k] = v;});
if (parsed.html) { msg.html = parsed.html; }
if (parsed.to) {
if (typeof(parsed.to) === "string" && parsed.to.length > 0) { msg.to = parsed.to; }
else if (parsed.to.hasOwnProperty("text") && parsed.to.text.length > 0) { msg.to = parsed.to.text; }
}
if (parsed.cc) {
if (typeof(parsed.cc) === "string" && parsed.cc.length > 0) { msg.cc = parsed.cc; }
else if (parsed.cc.hasOwnProperty("text") && parsed.cc.text.length > 0) { msg.cc = parsed.cc.text; }
}
if (parsed.cc && parsed.cc.length > 0) { msg.cc = parsed.cc; }
if (parsed.bcc && parsed.bcc.length > 0) { msg.bcc = parsed.bcc; }
if (parsed.from && parsed.from.value && parsed.from.value.length > 0) { msg.from = parsed.from.value[0].address; }
if (parsed.attachments) { msg.attachments = parsed.attachments; }
else { msg.attachments = []; }
node.send(msg); // Propagate the message down the flow
setTimeout(function() { node.status({})}, 500);
}
callback();
});
}
});
node.mta.listen(node.port);
node.mta.on("error", err => {
node.error("Error: " + err.message, err);
});
node.on("close", function() {
node.mta.close();
});
}
RED.nodes.registerType("e-mail mta",EmailMtaNode);
};

View File

@@ -26,7 +26,7 @@
<p>Additionally <code>msg.header</code> contains the complete header object including
<i>to</i>, <i>cc</i> and other potentially useful properties.</p>
<p>It can optionally mark the message as Read (default), Delete it, or leave unmarked (None).</p>
<p>Uses the <a href="https://github.com/mscdex/node-imap/blob/master/README.md" target="_new">node-imap module</a> - see that page for
<p>Uses the <a href="https://github.com/mscdex/node-imap/blob/master/README.md" target="_new">node-imap module</a> - see that page for
information on the <code>msg.criteria</code> format if needed.</p>
<p><b>Note</b>: uses IMAP with SSL to port 993.</p>
<p>Any attachments supplied in the incoming email can be found in the <code>msg.attachments</code> property. This will be an array of objects where
@@ -51,3 +51,13 @@
</script>
<script type="text/html" data-help-name="e-mail mta">
<p>Mail Transfer Agent - listens on a port for incoming SMTP mail.</p>
<p><b>Note</b>: "NOT for production use" as there is no security built in.
This is primarily for local testing of outbound mail sending, but could be used
as a mail forwarder to a real email service if required.</p>
<p>To use ports below 1024, for example 25 or 465, you may need to get privileged access.
On linux systems this can be done by running
<pre>sudo setcap 'cap_net_bind_service=+eip' $(which node)</pre>
and restarting Node-RED. Be aware - this gives all node applications access to all ports.</p>
</script>

View File

@@ -34,7 +34,8 @@
"default-message": "__description__\n\nFile from Node-RED is attached: __filename__",
"tip": {
"cred": "<b>Note:</b> Copied credentials from global emailkeys.js file.",
"recent": "Tip: Only retrieves the single most recent email."
"recent": "Tip: Only retrieves the single most recent email.",
"mta": "<b>Note:</b> To use ports below 1024 you may need elevated (root) privileges. See help sidebar."
},
"status": {
"messagesent": "Message sent: __response__",
@@ -47,6 +48,7 @@
"inboxzero": "you have achieved Inbox Zero",
"sending": "sending",
"sendfail": "send failed",
"parseerror": "Failed to parse message",
"connecterror": "connect error"
},
"errors": {
@@ -56,6 +58,7 @@
"nosmtptransport": "No SMTP transport. See info panel.",
"nopayload": "No payload to send",
"fetchfail": "Failed to fetch folder: __folder__",
"parsefail": "Failed to parse message",
"messageerror": "Fetch message error: __error__",
"refreshtoolarge": "Refresh interval too large. Limiting to 2147483 seconds"
}

View File

@@ -38,3 +38,13 @@
<p>POP3プロトコルでのデフォルトポート番号は素のTCPでは110番SSLでは995番ですIMAPプロトコルでは素のTCPでは143番SSLでは993番です</p>
</script>
<script type="text/html" data-help-name="e-mail mta">
<p>メール転送エージェント - 入ってくるSMTPメールのためポートでリッスンします</p>
<p><b>注釈</b>: ""
これは主に外部へのメール送信のローカルテスト向けですが必要に応じて実際のメールサービスへのメール転送としても使用できます</p>
<p>1024未満のポート(例えば25や465など)を使用するには特権的アクセスを得る必要がある場合があります
Linuxシステムでは以下のコマンドを実行しNode-REDを再起動することで達成できます
<pre>sudo setcap cap_net_bind_service=+eip $(which node)</pre>
これによって全てのnodeアプリケーションが全ポートにアクセスできる様になることに注意してください.</p>
</script>

View File

@@ -21,7 +21,8 @@
"default-message": "__description__\n\nNode-REDからファイルが添付されました: __filename__",
"tip": {
"cred": "<b>注釈:</b> emailkeys.jsファイルから認証情報をコピーしました。",
"recent": "注釈: 最新のメールを1件のみ取得します。"
"recent": "注釈: 最新のメールを1件のみ取得します。",
"mta": "<b>注釈:</b> 1024未満のポートを使用するには、昇格された(root)特権が必要です。ヘルプサイドバーを参照してください。"
},
"status": {
"messagesent": "メッセージを送信しました: __response__",
@@ -34,6 +35,7 @@
"inboxzero": "受信トレイにメールがありません",
"sending": "送信中",
"sendfail": "送信が失敗しました",
"parseerror": "メッセージのパースに失敗",
"connecterror": "接続エラー"
},
"errors": {
@@ -43,6 +45,7 @@
"nosmtptransport": "SMTP転送が設定されていません。「情報」タブを参照してください",
"nopayload": "送信するペイロードがありません",
"fetchfail": "フォルダの受信に失敗しました: __folder__",
"parsefail": "メッセージのパースに失敗",
"messageerror": "メッセージ受信エラー: __error__"
}
}

View File

@@ -1,12 +1,13 @@
{
"name": "node-red-node-email",
"version": "1.7.8",
"description": "Node-RED nodes to send and receive simple emails",
"version": "1.8.1",
"description": "Node-RED nodes to send and receive simple emails.",
"dependencies": {
"imap": "^0.8.19",
"mailparser": "^2.7.7",
"nodemailer": "^6.4.6",
"poplib": "^0.1.7"
"poplib": "^0.1.7",
"mailparser": "^3.0.0",
"nodemailer": "~6.4.10",
"smtp-server": "^3.7.0"
},
"repository": {
"type": "git",
@@ -18,7 +19,8 @@
"email",
"gmail",
"imap",
"pop"
"pop",
"mta"
],
"node-red": {
"nodes": {

View File

@@ -3,9 +3,7 @@ module.exports = function(RED) {
"use strict";
var PushBullet = require('pushbullet');
var fs = require('fs');
var util = require('util');
var when = require('when');
var nodefn = require('when/node');
var EventEmitter = require('events').EventEmitter;
function onError(err, node) {
@@ -127,17 +125,19 @@ module.exports = function(RED) {
stream.on('close', function() {
self.emitter.emit('stream_disconnected');
if (!closing) {
if (tout) { clearTimeout(tout); }
tout = setTimeout(function() {
stream.connect();
},15000);
}, 15000);
}
});
stream.on('error', function(err) {
self.emitter.emit('stream_error', err);
if (!closing) {
if (tout) { clearTimeout(tout); }
tout = setTimeout(function() {
stream.connect();
},15000);
}, 15000);
}
});
stream.connect();
@@ -229,10 +229,14 @@ module.exports = function(RED) {
msg.payload = incoming.body;
}
else if (incoming.type === 'dismissal') {
msg.topic = "dismissal";
msg.topic = "Push dismissed";
msg.payload = incoming.iden;
}
else if (incoming.type === 'sms_changed') {
msg.topic = "SMS: "+ incoming.notifications[0].title;
msg.payload = incoming.notifications[0].body;
msg.message = incoming;
}
else {
this.error("unknown push type: " + incoming.type + " content: " + JSON.stringify(incoming));
return;
@@ -257,8 +261,7 @@ module.exports = function(RED) {
try {
pushkeys = RED.settings.pushbullet || require(process.env.NODE_RED_HOME+"/../pushkey.js");
}
catch(err) {
}
catch(err) { }
var cred = RED.nodes.getCredentials(n.id);
// get old apikey
@@ -327,7 +330,7 @@ module.exports = function(RED) {
try {
this.deviceid = this.credentials.deviceid;
}
catch(err) {}
catch(err) { }
}
if (configNode) {

View File

@@ -1,6 +1,6 @@
{
"name" : "node-red-node-pushbullet",
"version" : "0.0.14",
"version" : "0.0.17",
"description" : "A Node-RED node to send alerts via Pushbullet",
"dependencies" : {
"pushbullet": "^2.4.0",

View File

@@ -103,8 +103,8 @@ module.exports = function(RED) {
if (err) { node.error(err,msg); }
else {
try {
response = JSON.parse(response);
if (response.status !== 1) { node.error("[57-pushover.js] Error: "+response); }
var responseObject = JSON.parse(response);
if (responseObject.status !== 1) { node.error("[57-pushover.js] Error: "+response); }
}
catch(e) {
node.error("[57-pushover.js] Error: "+response);

View File

@@ -155,7 +155,7 @@ module.exports = function(RED) {
}
}
else if(stanza.attrs.type === 'result'){
// AM To-Do check for 'bind' result with our current jid
// To-Do check for 'bind' result with our current jid
var query = stanza.getChild('query');
if (RED.settings.verbose || LOGITALL) {that.log("result!");}
if (RED.settings.verbose || LOGITALL) {that.log(query);}
@@ -164,7 +164,6 @@ module.exports = function(RED) {
}
});
// We shouldn't have any errors here that the input/output nodes can't handle
// if you need to see everything though; uncomment this block
// this.client.on('error', err => {
@@ -497,6 +496,10 @@ module.exports = function(RED) {
node.error("Server doesn't exist "+xmpp.options.service,err);
node.status({fill:"red",shape:"ring",text:"bad address"});
}
if (err.errno === "ENOTFOUND") {
node.error("Server doesn't exist "+xmpp.options.service,err);
node.status({fill:"red",shape:"ring",text:"bad address"});
}
else if (err === "XMPP authentication failure") {
node.error(err,err);
node.status({fill:"red",shape:"ring",text:"XMPP authentication failure"});

View File

@@ -1,6 +1,6 @@
{
"name": "node-red-node-xmpp",
"version": "0.2.4",
"version": "0.3.0",
"description": "A Node-RED node to talk to an XMPP server",
"dependencies": {
"@xmpp/client": "^0.11.1"