Add MTA node to email

This commit is contained in:
Dave Conway-Jones 2020-10-19 12:24:18 +01:00
parent 8f2c631410
commit 14087a9f77
No known key found for this signature in database
GPG Key ID: 88BA2B8A411BE9FF
7 changed files with 140 additions and 16 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);
@ -406,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);
@ -513,4 +516,63 @@ 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
})
.then(parsed => {
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);
})
.catch(err => { node.error(RED._("email.errors.parsefail"),err); })
.finally(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.11",
"description": "Node-RED nodes to send and receive simple emails",
"version": "1.8.0",
"description": "Node-RED nodes to send and receive simple emails.",
"dependencies": {
"imap": "^0.8.19",
"mailparser": "^2.8.1",
"nodemailer": "^6.4.11",
"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": {