Skip to content

Commit c979756

Browse files
committed
add smtp server
1 parent 3ca1f7f commit c979756

9 files changed

Lines changed: 223 additions & 28 deletions

File tree

OpenFlowNodeRED/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"passport-openid-connect": "^0.1.0",
2828
"passport-saml": "^1.0.0",
2929
"passport-saml-metadata": "^1.6.0",
30+
"smtp-server": "^3.5.0",
3031
"winston": "^3.2.1"
3132
}
3233
}

OpenFlowNodeRED/src/nodered/nodes/amqp.html

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313
</div>
1414
</script>
1515
<script type="text/javascript">
16-
RED.nodes.registerType('amqp-connection',{
16+
RED.nodes.registerType('amqp-connection', {
1717
category: 'config',
1818
defaults: {
19-
host: { value: "", required:true },
19+
host: { value: "", required: true },
2020
},
2121
credentials: {
22-
username: { type:"text" },
22+
username: { type: "text" },
2323
password: { type: "password" }
2424
},
25-
label: function() {
25+
label: function () {
2626
return this.host || "amqp credentials";
2727
}
2828
});
@@ -56,10 +56,10 @@
5656
category: 'amqp',
5757
color: "#a6bbcf",
5858
defaults: {
59-
queue: { value: "", required:true },
60-
noack: { value: true, required:true },
59+
queue: { value: "", required: true },
60+
noack: { value: true, required: true },
6161
name: { value: "" },
62-
config: {value:"",type:"amqp-connection", required:true}
62+
config: { value: "", type: "amqp-connection", required: true }
6363
},
6464
inputs: 0,
6565
outputs: 1,
@@ -105,9 +105,9 @@
105105
category: 'amqp',
106106
color: "#a6bbcf",
107107
defaults: {
108-
queue: { value: "", required:true },
108+
queue: { value: "", required: true },
109109
localqueue: { value: "" },
110-
config: {value:"",type:"amqp-connection", required:true}
110+
config: { value: "", type: "amqp-connection", required: true }
111111
},
112112
inputs: 1,
113113
outputs: 1,
@@ -142,6 +142,7 @@
142142
inputs: 1,
143143
outputs: 1,
144144
icon: "bridge.png",
145+
align: "right",
145146
label: function () {
146147
return this.name || "amqp acknowledgment";
147148
},
@@ -150,4 +151,4 @@
150151
},
151152

152153
});
153-
</script>
154+
</script>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { Readable } from "stream";
2+
import { SMTPServerSession, SMTPServer } from "smtp-server";
3+
import { EventEmitter } from "events";
4+
5+
var test = require('@nodemailer/mailparser2');
6+
const simpleParser = test.SimpleParser;
7+
8+
export class libmailserver extends EventEmitter {
9+
constructor() {
10+
super();
11+
}
12+
onMailFrom(address, session, callback) {
13+
// session.xForward is a Map structure
14+
try {
15+
//config.log(4, 'XFORWARD ADDR=%s', session.xForward.get('ADDR'));
16+
} catch (err) {
17+
console.log(err);
18+
}
19+
callback();
20+
}
21+
onRcptTo(address, session, callback) {
22+
//console.log(address.address);
23+
//config.log(4, address.address);
24+
// if (address.address !== 'allan@zenamic.dk') {
25+
// return callback(new Error('Non-existent email address'));
26+
// }
27+
return callback(); // Accept the address
28+
}
29+
async onData(stream: Readable, session: SMTPServerSession, callback: (err?: Error) => void) {
30+
//var mail:ParsedMail = await simpleParser(stream);
31+
var mail = await simpleParser(stream);
32+
libmailserver.current.emit('email', mail);
33+
//config.log(4, mail);
34+
callback();
35+
}
36+
onAuth(auth, session, callback) {
37+
// config.log(4, auth);
38+
callback(null, { user: 123 }); // where 123 is the user id or similar property
39+
}
40+
static current: libmailserver;
41+
server: SMTPServer;
42+
static setupSMTP(port: number) {
43+
return new Promise<libmailserver>(async (resolve, reject) => {
44+
if (libmailserver.current) {
45+
console.log('Smtpserver is allready listening on %s', port);
46+
return resolve(libmailserver.current);
47+
}
48+
49+
libmailserver.current = new libmailserver();
50+
try {
51+
const SMTPServer = require('smtp-server').SMTPServer;
52+
libmailserver.current.server = new SMTPServer({
53+
secure: false,
54+
logger: false,
55+
authOptional: true,
56+
disableReverseLookup: true,
57+
useXClient: true,
58+
disabledCommands: ['STARTTLS', 'AUTH'],
59+
onMailFrom: libmailserver.current.onMailFrom,
60+
onRcptTo: libmailserver.current.onRcptTo,
61+
onAuth: libmailserver.current.onAuth,
62+
onData: libmailserver.current.onData
63+
});
64+
console.log('Smtpserver listening on %s', port);
65+
await libmailserver.current.server.listen(port);
66+
resolve(libmailserver.current);
67+
} catch (err) {
68+
reject(err);
69+
}
70+
});
71+
}
72+
73+
}

OpenFlowNodeRED/src/nodered/nodes/rpa.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
inputs: 1,
9393
outputs: 3,
9494
icon: "bridge.png",
95+
align: "right",
9596
outputLabels: ["completed", "status", "failed"],
9697
label: function () {
9798
return this.name || "rpa workflow";
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<script type="text/x-red" data-template-name="smtpserver in">
2+
<div class="form-row">
3+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
4+
<input type="text" id="node-input-name" placeholder="Name">
5+
</div>
6+
<div class="form-row">
7+
<label for="node-input-email"><i class="fa fa-tag"></i> Email</label>
8+
<input type="text" id="node-input-email" placeholder="Name">
9+
</div>
10+
</script>
11+
<script type="text/x-red" data-help-name="smtpserver in">
12+
<p>Receive emails directly from outside world on port 25s</p>
13+
</script>
14+
<script type="text/javascript">
15+
RED.nodes.registerType('smtpserver in', {
16+
category: 'rpa',
17+
color: "rgb(215, 215, 160)",
18+
defaults: {
19+
name: { value: "", required: false },
20+
email: { value: 'allan@demo1.openrpa.dk', required: true }
21+
},
22+
inputs: 0,
23+
outputs: 1,
24+
icon: "parser-html.png", // saved in icons/myicon.png
25+
//align: "right",
26+
label: function () {
27+
return this.name || this.email || "smtpserver in";
28+
},
29+
labelStyle: function () {
30+
return this.name ? "node_label_italic" : "";
31+
}
32+
});
33+
</script>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { Node } from "node-red";
2+
import { libmailserver } from "./libmailserver";
3+
import { NoderedUtil } from "./NoderedUtil";
4+
5+
module.exports = function (RED) {
6+
"use strict";
7+
8+
RED.nodes.registerType("smtpserver in", function (n) {
9+
RED.nodes.createNode(this, n);
10+
this.name = n.name;
11+
this.email = n.email;
12+
this.port = n.port;
13+
var node = this;
14+
var mailserver: libmailserver;
15+
16+
const onEmail = (email) => {
17+
try {
18+
var sendit: boolean = false;
19+
if (node.email == null || node.email == '' || node.email == '*') {
20+
sendit = true;
21+
}
22+
if (email.to) {
23+
if (email.to.value.filter(addr => addr.address == node.email).length > 0) {
24+
sendit = true;
25+
}
26+
}
27+
if (email.bcc) {
28+
if (email.bcc.value.filter(addr => addr.address == node.email).length > 0) {
29+
sendit = true;
30+
}
31+
}
32+
if (sendit) {
33+
var msg = { payload: email, instanceid: null };
34+
var instanceid = email.headers.get('instanceid');
35+
if (!instanceid) {
36+
instanceid = email.headers.get('XREF');
37+
}
38+
if (!instanceid) {
39+
var startindex = email.text.indexOf('instanceid');
40+
//var endindex = email.text.indexOf('instanceid', startindex+10) + 10;
41+
//var text = email.text.substring(startindex, endindex - startindex);
42+
var text = email.text.substring(startindex);
43+
var arr = text.split(':');
44+
instanceid = arr[1];
45+
}
46+
47+
msg.instanceid = instanceid;
48+
node.send(msg);
49+
// } else {
50+
// config.log(1, email);
51+
}
52+
} catch (error) {
53+
NoderedUtil.HandleError(this, error);
54+
}
55+
}
56+
async function init(port: number) {
57+
try {
58+
mailserver = await libmailserver.setupSMTP(port);
59+
mailserver.on('email', onEmail);
60+
//mailserver.on('email', onEmail);
61+
//libmailserver.current.on('email', onEmail);
62+
} catch (error) {
63+
NoderedUtil.HandleError(this, error);
64+
}
65+
}
66+
67+
var port = node.port;
68+
// if(port && port !='') {
69+
// port = parseInt(node.port);
70+
// } else {
71+
// port = config.mailserver_port;
72+
// }
73+
// port = config.mailserver_port;
74+
port = 25;
75+
init(port);
76+
77+
this.on("close", function () {
78+
//mailserver.removeAllListeners(node.endpointname);
79+
mailserver.removeListener('email', onEmail);
80+
});
81+
82+
});
83+
84+
}

OpenFlowNodeRED/src/nodered/nodes/workflow.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
</script>
1818
<script type="text/javascript">
1919
RED.nodes.registerType('workflow in', {
20-
category: 'workflow',
20+
category: 'rpa',
2121
color: "#a6bbcf",
2222
defaults: {
2323
queue: { value: "", required: true },
@@ -67,6 +67,7 @@
6767
inputs: 1,
6868
outputs: 1,
6969
icon: "bridge.png",
70+
align: "right",
7071
label: function () {
7172
return this.name || "workflow out";
7273
},

OpenFlowNodeRED/src/nodered_settings.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,30 @@ import { Config } from "./Config";
22

33
// tslint:disable-next-line: class-name
44
export class nodered_settings {
5-
public flowFile:string = "flows.json";
6-
public settingsFile:string = "nodered_settings.js";
7-
public nodesDir:string = ".";
8-
public userDir:string = ".";
5+
public flowFile: string = "flows.json";
6+
public settingsFile: string = "nodered_settings.js";
7+
public nodesDir: string = ".";
8+
public userDir: string = ".";
99

1010
public credentialSecret: string | boolean = false;
1111
public adminAuth: any = null;
1212
public httpNodeAuth: any = null;
1313
public httpStaticAuth: any = null;
14-
public httpNodeMiddleware:any;
14+
public httpNodeMiddleware: any;
1515

16-
public httpAdminRoot:string = "/";
17-
public httpNodeRoot:string = "/";
16+
public httpAdminRoot: string = "/";
17+
public httpNodeRoot: string = "/";
1818
public storageModule: any = null;
19-
public uiPort:number = Config.port;
20-
public mqttReconnectTime:number = 15000;
21-
public serialReconnectTime:number = 15000;
22-
public debugMaxLength:number = 1000;
23-
public functionGlobalContext:any = { process: process };
24-
public paletteCategories:string[] = ["workflow", "form", "robot", "api", "smtpserver", "subflows", "input", "output", "function",
25-
"social", "mobile", "storage", "analysis", "advanced"];
26-
public debugUseColors:boolean = true;
27-
public flowFilePretty:boolean = true;
28-
public logging:any = {
19+
public uiPort: number = Config.port;
20+
public mqttReconnectTime: number = 15000;
21+
public serialReconnectTime: number = 15000;
22+
public debugMaxLength: number = 1000;
23+
public functionGlobalContext: any = { process: process };
24+
public paletteCategories: string[] = ["workflow", "rpa", "subflows", "input", "output", "function", "api",
25+
"social", "mobile", "storage", "analysis", "advanced"];
26+
public debugUseColors: boolean = true;
27+
public flowFilePretty: boolean = true;
28+
public logging: any = {
2929
console: {
3030
level: "warn",
3131
metrics: false,

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
},
1818
"homepage": "https://github.com/open-rpa/openflow",
1919
"dependencies": {
20+
"@nodemailer/mailparser2": "^1.0.3",
2021
"@types/angular": "^1.6.54",
2122
"@types/angular-route": "^1.7.0",
2223
"@types/jquery": "^3.3.29",

0 commit comments

Comments
 (0)