@5minds/node-red-contrib-processcube-tools 1.0.1-feature-24a79f-mfgha47l → 1.0.1-feature-258a01-mfm4xbwl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/email-receiver/email-receiver.html +165 -133
- package/email-receiver/email-receiver.js +49 -35
- package/email-sender/email-sender.html +109 -85
- package/email-sender/email-sender.js +66 -34
- package/package.json +2 -4
- package/processcube-html-to-text/processcube-html-to-text.html +9 -9
- package/processcube-html-to-text/processcube-html-to-text.js +0 -3
- package/test/helpers/email-receiver.mocks.js +394 -399
- package/test/helpers/email-sender.mocks.js +364 -0
- package/test/integration/email-receiver.integration.test.js +473 -482
- package/test/integration/email-sender.integration.test.js +242 -0
- package/test/unit/email-receiver.unit.test.js +284 -289
- package/test/unit/email-sender.unit.test.js +621 -0
|
@@ -3,209 +3,224 @@
|
|
|
3
3
|
category: 'ProcessCube Tools',
|
|
4
4
|
color: '#02AFD6',
|
|
5
5
|
defaults: {
|
|
6
|
-
name: { value:
|
|
6
|
+
name: { value: '' },
|
|
7
7
|
// Mail fields
|
|
8
|
-
sender: {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
8
|
+
sender: {
|
|
9
|
+
value: 'Stoelting Ticket-System',
|
|
10
|
+
required: true,
|
|
11
|
+
validate: RED.validators.typedInput('senderType'),
|
|
12
|
+
},
|
|
13
|
+
senderType: { value: 'str' },
|
|
14
|
+
address: { value: '', required: true, validate: RED.validators.typedInput('addressType') },
|
|
15
|
+
addressType: { value: 'str' },
|
|
16
|
+
to: { value: '', required: true, validate: RED.validators.typedInput('toType') },
|
|
17
|
+
toType: { value: 'str' },
|
|
18
|
+
cc: { value: '', validate: RED.validators.typedInput('ccType') },
|
|
19
|
+
ccType: { value: 'str' },
|
|
20
|
+
bcc: { value: '', validate: RED.validators.typedInput('bccType') },
|
|
21
|
+
bccType: { value: 'str' },
|
|
22
|
+
subject: { value: '', required: true, validate: RED.validators.typedInput('subjectType') },
|
|
23
|
+
subjectType: { value: 'str' },
|
|
24
|
+
htmlContent: { value: '', required: true, validate: RED.validators.typedInput('htmlContentType') },
|
|
25
|
+
htmlContentType: { value: 'str' },
|
|
26
|
+
attachments: { value: '', required: false },
|
|
27
|
+
attachmentsType: { value: 'msg' },
|
|
24
28
|
|
|
25
29
|
// SMTP-Fields
|
|
26
|
-
host: { value:
|
|
27
|
-
hostType: { value:
|
|
28
|
-
port: { value:
|
|
29
|
-
portType: { value:
|
|
30
|
-
user: { value:
|
|
31
|
-
userType: { value:
|
|
32
|
-
password: { value:
|
|
33
|
-
passwordType: { value:
|
|
34
|
-
secure: { value:
|
|
35
|
-
secureType: { value:
|
|
36
|
-
rejectUnauthorized: {
|
|
37
|
-
|
|
30
|
+
host: { value: '', required: true, validate: RED.validators.typedInput('hostType') },
|
|
31
|
+
hostType: { value: 'str' },
|
|
32
|
+
port: { value: '', required: true, validate: RED.validators.typedInput('portType') },
|
|
33
|
+
portType: { value: 'num' },
|
|
34
|
+
user: { value: '', required: true, validate: RED.validators.typedInput('userType') },
|
|
35
|
+
userType: { value: 'str' },
|
|
36
|
+
password: { value: '', required: true, type: 'password' },
|
|
37
|
+
passwordType: { value: 'env', required: true },
|
|
38
|
+
secure: { value: '', required: true, validate: RED.validators.typedInput('secureType') },
|
|
39
|
+
secureType: { value: 'bool' },
|
|
40
|
+
rejectUnauthorized: {
|
|
41
|
+
value: '',
|
|
42
|
+
required: true,
|
|
43
|
+
validate: RED.validators.typedInput('rejectUnauthorizedType'),
|
|
44
|
+
},
|
|
45
|
+
rejectUnauthorizedType: { value: 'bool' },
|
|
38
46
|
},
|
|
39
47
|
inputs: 1,
|
|
40
48
|
outputs: 1,
|
|
41
|
-
icon:
|
|
42
|
-
label: function() {
|
|
43
|
-
return this.name ||
|
|
49
|
+
icon: 'font-awesome/fa-paper-plane',
|
|
50
|
+
label: function () {
|
|
51
|
+
return this.name || 'E-Mail Sender';
|
|
44
52
|
},
|
|
45
|
-
oneditprepare: function() {
|
|
53
|
+
oneditprepare: function () {
|
|
46
54
|
// Mail Fields
|
|
47
55
|
$('#node-input-sender').typedInput({
|
|
48
56
|
default: 'str',
|
|
49
57
|
types: ['str', 'msg', 'flow', 'global', 'env'],
|
|
50
|
-
typeField: '#node-input-senderType'
|
|
58
|
+
typeField: '#node-input-senderType',
|
|
51
59
|
});
|
|
52
60
|
$('#node-input-address').typedInput({
|
|
53
61
|
default: 'str',
|
|
54
62
|
types: ['str', 'msg', 'flow', 'global', 'env'],
|
|
55
|
-
typeField: '#node-input-addressType'
|
|
63
|
+
typeField: '#node-input-addressType',
|
|
56
64
|
});
|
|
57
65
|
$('#node-input-to').typedInput({
|
|
58
66
|
default: 'str',
|
|
59
67
|
types: ['str', 'msg', 'flow', 'global', 'env'],
|
|
60
|
-
typeField: '#node-input-toType'
|
|
68
|
+
typeField: '#node-input-toType',
|
|
61
69
|
});
|
|
62
70
|
$('#node-input-cc').typedInput({
|
|
63
71
|
default: 'str',
|
|
64
72
|
types: ['str', 'msg', 'flow', 'global', 'env'],
|
|
65
|
-
typeField: '#node-input-ccType'
|
|
73
|
+
typeField: '#node-input-ccType',
|
|
66
74
|
});
|
|
67
75
|
$('#node-input-bcc').typedInput({
|
|
68
76
|
default: 'str',
|
|
69
77
|
types: ['str', 'msg', 'flow', 'global', 'env'],
|
|
70
|
-
typeField: '#node-input-bccType'
|
|
78
|
+
typeField: '#node-input-bccType',
|
|
71
79
|
});
|
|
72
80
|
$('#node-input-subject').typedInput({
|
|
73
81
|
default: 'str',
|
|
74
82
|
types: ['str', 'msg', 'flow', 'global', 'env'],
|
|
75
|
-
typeField: '#node-input-subjectType'
|
|
83
|
+
typeField: '#node-input-subjectType',
|
|
76
84
|
});
|
|
77
85
|
$('#node-input-htmlContent').typedInput({
|
|
78
86
|
default: 'str',
|
|
79
87
|
types: ['str', 'msg', 'flow', 'global', 'json'],
|
|
80
|
-
typeField: '#node-input-htmlContentType'
|
|
88
|
+
typeField: '#node-input-htmlContentType',
|
|
81
89
|
});
|
|
82
90
|
$('#node-input-attachments').typedInput({
|
|
83
91
|
default: 'msg',
|
|
84
92
|
types: ['msg', 'flow', 'global'],
|
|
85
|
-
typeField: '#node-input-attachmentsType'
|
|
93
|
+
typeField: '#node-input-attachmentsType',
|
|
86
94
|
});
|
|
87
95
|
|
|
88
96
|
// SMTP Fields
|
|
89
97
|
$('#node-input-host').typedInput({
|
|
90
98
|
default: 'str',
|
|
91
99
|
types: ['str', 'msg', 'flow', 'global', 'env'],
|
|
92
|
-
typeField: '#node-input-hostType'
|
|
100
|
+
typeField: '#node-input-hostType',
|
|
93
101
|
});
|
|
94
102
|
$('#node-input-port').typedInput({
|
|
95
103
|
default: 'num',
|
|
96
104
|
types: ['num', 'msg', 'flow', 'global', 'env'],
|
|
97
|
-
typeField: '#node-input-portType'
|
|
105
|
+
typeField: '#node-input-portType',
|
|
98
106
|
});
|
|
99
107
|
$('#node-input-user').typedInput({
|
|
100
108
|
default: 'str',
|
|
101
109
|
types: ['str', 'msg', 'flow', 'global', 'env'],
|
|
102
|
-
typeField: '#node-input-userType'
|
|
110
|
+
typeField: '#node-input-userType',
|
|
103
111
|
});
|
|
104
112
|
$('#node-input-password').typedInput({
|
|
105
113
|
default: 'env',
|
|
106
114
|
types: ['msg', 'flow', 'global', 'env'],
|
|
107
|
-
typeField: '#node-input-passwordType'
|
|
115
|
+
typeField: '#node-input-passwordType',
|
|
108
116
|
});
|
|
109
117
|
$('#node-input-secure').typedInput({
|
|
110
118
|
default: 'bool',
|
|
111
119
|
types: ['bool', 'msg', 'flow', 'global', 'env'],
|
|
112
|
-
typeField: '#node-input-secureType'
|
|
120
|
+
typeField: '#node-input-secureType',
|
|
113
121
|
});
|
|
114
122
|
$('#node-input-rejectUnauthorized').typedInput({
|
|
115
123
|
default: 'bool',
|
|
116
124
|
types: ['bool', 'msg', 'flow', 'global', 'env'],
|
|
117
|
-
typeField: '#node-input-rejectUnauthorizedType'
|
|
125
|
+
typeField: '#node-input-rejectUnauthorizedType',
|
|
118
126
|
});
|
|
119
|
-
}
|
|
127
|
+
},
|
|
120
128
|
});
|
|
121
129
|
</script>
|
|
122
130
|
|
|
123
131
|
<script type="text/html" data-template-name="email-sender">
|
|
124
132
|
<div class="form-row">
|
|
125
133
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
126
|
-
<input type="text" id="node-input-name" placeholder="Name"
|
|
134
|
+
<input type="text" id="node-input-name" placeholder="Name" />
|
|
127
135
|
</div>
|
|
128
136
|
|
|
129
137
|
<h3>Mail Configuration</h3>
|
|
130
138
|
<div class="form-row">
|
|
131
139
|
<label for="node-input-sender"><i class="fa fa-user"></i> Sender</label>
|
|
132
|
-
<input type="text" id="node-input-sender" placeholder="John Doe"
|
|
133
|
-
<input type="hidden" id="node-input-senderType"
|
|
140
|
+
<input type="text" id="node-input-sender" placeholder="John Doe" />
|
|
141
|
+
<input type="hidden" id="node-input-senderType" />
|
|
134
142
|
</div>
|
|
135
143
|
<div class="form-row">
|
|
136
144
|
<label for="node-input-address"><i class="fa fa-envelope"></i> Address</label>
|
|
137
|
-
<input type="text" id="node-input-address" placeholder="john.doe@example.com"
|
|
138
|
-
<input type="hidden" id="node-input-addressType"
|
|
145
|
+
<input type="text" id="node-input-address" placeholder="john.doe@example.com" />
|
|
146
|
+
<input type="hidden" id="node-input-addressType" />
|
|
139
147
|
</div>
|
|
140
148
|
<div class="form-row">
|
|
141
149
|
<label for="node-input-to"><i class="fa fa-user"></i> To</label>
|
|
142
|
-
<input type="text" id="node-input-to" placeholder="my.test@example.com"
|
|
143
|
-
<input type="hidden" id="node-input-toType"
|
|
150
|
+
<input type="text" id="node-input-to" placeholder="my.test@example.com" />
|
|
151
|
+
<input type="hidden" id="node-input-toType" />
|
|
144
152
|
</div>
|
|
145
153
|
<div class="form-row">
|
|
146
154
|
<label for="node-input-cc"><i class="fa fa-user-plus"></i> CC</label>
|
|
147
|
-
<input type="text" id="node-input-cc"
|
|
148
|
-
<input type="hidden" id="node-input-ccType"
|
|
155
|
+
<input type="text" id="node-input-cc" />
|
|
156
|
+
<input type="hidden" id="node-input-ccType" />
|
|
149
157
|
</div>
|
|
150
158
|
<div class="form-row">
|
|
151
159
|
<label for="node-input-bcc"><i class="fa fa-user-secret"></i> BCC</label>
|
|
152
|
-
<input type="text" id="node-input-bcc"
|
|
153
|
-
<input type="hidden" id="node-input-bccType"
|
|
160
|
+
<input type="text" id="node-input-bcc" />
|
|
161
|
+
<input type="hidden" id="node-input-bccType" />
|
|
154
162
|
</div>
|
|
155
163
|
<div class="form-row">
|
|
156
164
|
<label for="node-input-subject"><i class="fa fa-info-circle"></i> Subject</label>
|
|
157
|
-
<input type="text" id="node-input-subject"
|
|
158
|
-
<input type="hidden" id="node-input-subjectType"
|
|
165
|
+
<input type="text" id="node-input-subject" />
|
|
166
|
+
<input type="hidden" id="node-input-subjectType" />
|
|
159
167
|
</div>
|
|
160
168
|
<div class="form-row">
|
|
161
169
|
<label for="node-input-htmlContent"><i class="fa fa-file-code-o"></i> HTML Content</label>
|
|
162
|
-
<input type="text" id="node-input-htmlContent"
|
|
163
|
-
<input type="hidden" id="node-input-htmlContentType"
|
|
170
|
+
<input type="text" id="node-input-htmlContent" />
|
|
171
|
+
<input type="hidden" id="node-input-htmlContentType" />
|
|
164
172
|
</div>
|
|
165
173
|
<div class="form-row">
|
|
166
174
|
<label for="node-input-attachments"><i class="fa fa-paperclip"></i> Attachments</label>
|
|
167
|
-
<input type="text" id="node-input-attachments"
|
|
168
|
-
<input type="hidden" id="node-input-attachmentsType"
|
|
175
|
+
<input type="text" id="node-input-attachments" />
|
|
176
|
+
<input type="hidden" id="node-input-attachmentsType" />
|
|
169
177
|
</div>
|
|
170
178
|
|
|
171
179
|
<h3>SMTP Configuration</h3>
|
|
172
180
|
<div class="form-row">
|
|
173
181
|
<label for="node-input-host"><i class="fa fa-server"></i> Host</label>
|
|
174
|
-
<input type="text" id="node-input-host" placeholder="smtp.gmail.com"
|
|
175
|
-
<input type="hidden" id="node-input-hostType"
|
|
182
|
+
<input type="text" id="node-input-host" placeholder="smtp.gmail.com" />
|
|
183
|
+
<input type="hidden" id="node-input-hostType" />
|
|
176
184
|
</div>
|
|
177
185
|
<div class="form-row">
|
|
178
186
|
<label for="node-input-port"><i class="fa fa-plug"></i> Port</label>
|
|
179
|
-
<input type="text" id="node-input-port" placeholder="587"
|
|
180
|
-
<input type="hidden" id="node-input-portType"
|
|
187
|
+
<input type="text" id="node-input-port" placeholder="587" />
|
|
188
|
+
<input type="hidden" id="node-input-portType" />
|
|
181
189
|
</div>
|
|
182
190
|
<div class="form-row">
|
|
183
191
|
<label for="node-input-user"><i class="fa fa-user"></i> User</label>
|
|
184
|
-
<input type="text" id="node-input-user" placeholder="test.user@config.com"
|
|
185
|
-
<input type="hidden" id="node-input-userType"
|
|
192
|
+
<input type="text" id="node-input-user" placeholder="test.user@config.com" />
|
|
193
|
+
<input type="hidden" id="node-input-userType" />
|
|
186
194
|
</div>
|
|
187
195
|
<div class="form-row">
|
|
188
196
|
<label for="node-input-password"><i class="fa fa-lock"></i> Password</label>
|
|
189
|
-
<input type="password" id="node-input-password"
|
|
190
|
-
<input type="hidden" id="node-input-passwordType"
|
|
197
|
+
<input type="password" id="node-input-password" />
|
|
198
|
+
<input type="hidden" id="node-input-passwordType" />
|
|
191
199
|
</div>
|
|
192
200
|
<div class="form-row">
|
|
193
201
|
<label for="node-input-secure"><i class="fa fa-shield"></i> SSL/TLS (Secure)</label>
|
|
194
|
-
<input type="text" id="node-input-secure"
|
|
195
|
-
<input type="hidden" id="node-input-secureType"
|
|
202
|
+
<input type="text" id="node-input-secure" />
|
|
203
|
+
<input type="hidden" id="node-input-secureType" />
|
|
196
204
|
</div>
|
|
197
205
|
<div class="form-row">
|
|
198
206
|
<label for="node-input-rejectUnauthorized"><i class="fa fa-ban"></i> Reject Unauthorized</label>
|
|
199
|
-
<input type="text" id="node-input-rejectUnauthorized"
|
|
200
|
-
<input type="hidden" id="node-input-rejectUnauthorizedType"
|
|
207
|
+
<input type="text" id="node-input-rejectUnauthorized" />
|
|
208
|
+
<input type="hidden" id="node-input-rejectUnauthorizedType" />
|
|
201
209
|
</div>
|
|
202
210
|
</script>
|
|
203
211
|
|
|
204
212
|
<script type="text/html" data-help-name="email-sender">
|
|
205
|
-
<p>
|
|
213
|
+
<p>
|
|
214
|
+
A custom node to send emails using an SMTP server. The configuration for each field can be sourced from a fixed
|
|
215
|
+
value, or from a <code>msg</code>, <code>flow</code>, <code>global</code>, or <code>env</code> variable.
|
|
216
|
+
</p>
|
|
206
217
|
|
|
207
218
|
<h3>Configuration</h3>
|
|
208
|
-
<p>
|
|
219
|
+
<p>
|
|
220
|
+
Every field on the configuration panel is a <b>typed input</b>. Use the dropdown menu next to each field to
|
|
221
|
+
select the source of its value. Note that <b>Sender</b>, <b>Address</b>, <b>To</b>, <b>Subject</b>, and
|
|
222
|
+
<b>HTML Content</b> are required fields and must be configured before the node can be deployed.
|
|
223
|
+
</p>
|
|
209
224
|
|
|
210
225
|
<h4>Mail Configuration</h4>
|
|
211
226
|
<dl class="message-properties">
|
|
@@ -249,18 +264,27 @@
|
|
|
249
264
|
<dd>The password for SMTP authentication.</dd>
|
|
250
265
|
|
|
251
266
|
<dt>SSL/TLS (Secure) <span class="property-type">boolean | variable</span></dt>
|
|
252
|
-
<dd>
|
|
267
|
+
<dd>
|
|
268
|
+
Use a secure connection. Set to <code>true</code> for SSL/TLS, <code>false</code> for a non-secure
|
|
269
|
+
connection.
|
|
270
|
+
</dd>
|
|
253
271
|
|
|
254
272
|
<dt>Reject Unauthorized <span class="property-type">boolean | variable</span></dt>
|
|
255
273
|
<dd>If <code>true</code>, the server's certificate is rejected if it's not authorized by a trusted CA.</dd>
|
|
256
274
|
</dl>
|
|
257
275
|
|
|
258
276
|
<h3>Usage</h3>
|
|
259
|
-
<p>
|
|
260
|
-
|
|
261
|
-
|
|
277
|
+
<p>
|
|
278
|
+
Inject a message to trigger the node and send an email.<br />
|
|
279
|
+
Credentials and other properties can be provided via message properties, flow/global context, or environment
|
|
280
|
+
variables.<br />
|
|
281
|
+
The node supports sending HTML emails and attachments.
|
|
282
|
+
</p>
|
|
262
283
|
|
|
263
284
|
<h3>Tips</h3>
|
|
264
|
-
<p
|
|
265
|
-
|
|
285
|
+
<p>
|
|
286
|
+
<b>HTML Content Creation:</b><br />
|
|
287
|
+
To generate or format HTML content for your email, you can use a <b>template node</b> before the email-sender
|
|
288
|
+
node. This allows you to create dynamic and customized email bodies.
|
|
289
|
+
</p>
|
|
266
290
|
</script>
|
|
@@ -1,22 +1,33 @@
|
|
|
1
|
-
module.exports = function(RED) {
|
|
2
|
-
|
|
3
|
-
const nodemailer = require(
|
|
1
|
+
module.exports = function (RED) {
|
|
2
|
+
'use strict';
|
|
3
|
+
const nodemailer = require('nodemailer');
|
|
4
4
|
|
|
5
5
|
function EmailSenderNode(config) {
|
|
6
6
|
RED.nodes.createNode(this, config);
|
|
7
7
|
var node = this;
|
|
8
8
|
|
|
9
|
-
node.on('input', function(msg, send, done) {
|
|
10
|
-
send =
|
|
11
|
-
|
|
9
|
+
node.on('input', function (msg, send, done) {
|
|
10
|
+
send =
|
|
11
|
+
send ||
|
|
12
|
+
function () {
|
|
13
|
+
node.send.apply(node, arguments);
|
|
14
|
+
};
|
|
15
|
+
done =
|
|
16
|
+
done ||
|
|
17
|
+
function (err) {
|
|
18
|
+
if (err) node.error(err, msg);
|
|
19
|
+
};
|
|
12
20
|
|
|
13
21
|
// Retrieve and evaluate mail configuration values
|
|
14
22
|
const sender = RED.util.evaluateNodeProperty(config.sender, config.senderType, node, msg);
|
|
15
23
|
const address = RED.util.evaluateNodeProperty(config.address, config.addressType, node, msg);
|
|
16
24
|
const to = RED.util.evaluateNodeProperty(config.to, config.toType, node, msg);
|
|
17
|
-
const cc = RED.util.evaluateNodeProperty(config.cc, config.ccType, node, msg) ||
|
|
18
|
-
const bcc = RED.util.evaluateNodeProperty(config.bcc, config.bccType, node, msg) ||
|
|
19
|
-
const subject =
|
|
25
|
+
const cc = RED.util.evaluateNodeProperty(config.cc, config.ccType, node, msg) || '';
|
|
26
|
+
const bcc = RED.util.evaluateNodeProperty(config.bcc, config.bccType, node, msg) || '';
|
|
27
|
+
const subject =
|
|
28
|
+
RED.util.evaluateNodeProperty(config.subject, config.subjectType, node, msg) ||
|
|
29
|
+
msg.topic ||
|
|
30
|
+
'Message from Node-RED';
|
|
20
31
|
const htmlContent = RED.util.evaluateNodeProperty(config.htmlContent, config.htmlContentType, node, msg);
|
|
21
32
|
const attachments = safeEvaluatePropertyAttachment(config, node, msg);
|
|
22
33
|
|
|
@@ -26,13 +37,30 @@ module.exports = function(RED) {
|
|
|
26
37
|
const user = RED.util.evaluateNodeProperty(config.user, config.userType, node, msg);
|
|
27
38
|
const password = RED.util.evaluateNodeProperty(config.password, config.passwordType, node, msg);
|
|
28
39
|
const secure = RED.util.evaluateNodeProperty(config.secure, config.secureType, node, msg);
|
|
29
|
-
const rejectUnauthorized = RED.util.evaluateNodeProperty(
|
|
40
|
+
const rejectUnauthorized = RED.util.evaluateNodeProperty(
|
|
41
|
+
config.rejectUnauthorized,
|
|
42
|
+
config.rejectUnauthorizedType,
|
|
43
|
+
node,
|
|
44
|
+
msg,
|
|
45
|
+
);
|
|
30
46
|
|
|
31
47
|
// Handle attachments and format them for Nodemailer
|
|
32
48
|
let processedAttachments = [];
|
|
33
|
-
|
|
49
|
+
|
|
50
|
+
let parsedAttachments = config.attachments;
|
|
51
|
+
|
|
52
|
+
if (config.attachmentsType === 'json' && typeof parsedAttachments === 'string') {
|
|
53
|
+
try {
|
|
54
|
+
parsedAttachments = JSON.parse(parsedAttachments);
|
|
55
|
+
} catch (e) {
|
|
56
|
+
node.error('Failed to parse attachments JSON: ' + e.message);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (parsedAttachments) {
|
|
34
62
|
// Check if it's a single attachment or an array
|
|
35
|
-
const attachmentArray = Array.isArray(
|
|
63
|
+
const attachmentArray = Array.isArray(parsedAttachments) ? parsedAttachments : [parsedAttachments];
|
|
36
64
|
|
|
37
65
|
for (const attachment of attachmentArray) {
|
|
38
66
|
try {
|
|
@@ -40,13 +68,15 @@ module.exports = function(RED) {
|
|
|
40
68
|
if (attachment.filename && attachment.content) {
|
|
41
69
|
processedAttachments.push({
|
|
42
70
|
filename: attachment.filename,
|
|
43
|
-
content: attachment.content
|
|
71
|
+
content: attachment.content,
|
|
44
72
|
});
|
|
45
73
|
} else {
|
|
46
|
-
node.
|
|
74
|
+
node.status({ fill: 'red', shape: 'dot', text: 'attachment error' });
|
|
75
|
+
node.error("Attachment object is missing 'filename' or 'content' property.");
|
|
76
|
+
return;
|
|
47
77
|
}
|
|
48
78
|
} catch (e) {
|
|
49
|
-
node.error(
|
|
79
|
+
node.error('Failed to process attachment: ' + e.message);
|
|
50
80
|
}
|
|
51
81
|
}
|
|
52
82
|
}
|
|
@@ -58,42 +88,44 @@ module.exports = function(RED) {
|
|
|
58
88
|
secure: secure,
|
|
59
89
|
auth: {
|
|
60
90
|
user: user,
|
|
61
|
-
pass: password
|
|
91
|
+
pass: password,
|
|
62
92
|
},
|
|
63
93
|
tls: {
|
|
64
|
-
rejectUnauthorized: rejectUnauthorized
|
|
65
|
-
}
|
|
94
|
+
rejectUnauthorized: rejectUnauthorized,
|
|
95
|
+
},
|
|
66
96
|
});
|
|
67
97
|
|
|
68
98
|
// Create email object
|
|
69
99
|
const mailOptions = {
|
|
70
100
|
from: {
|
|
71
101
|
name: sender,
|
|
72
|
-
address: address
|
|
102
|
+
address: address,
|
|
73
103
|
},
|
|
74
104
|
to: to,
|
|
75
105
|
cc: cc,
|
|
76
106
|
bcc: bcc,
|
|
77
107
|
subject: subject,
|
|
78
108
|
html: Buffer.from(htmlContent, 'utf-8'),
|
|
79
|
-
attachments: processedAttachments
|
|
109
|
+
attachments: processedAttachments,
|
|
80
110
|
};
|
|
81
111
|
|
|
82
112
|
// Send email
|
|
83
113
|
transporter.sendMail(mailOptions, (error, info) => {
|
|
84
114
|
if (error) {
|
|
85
|
-
node.status({ fill:
|
|
115
|
+
node.status({ fill: 'red', shape: 'dot', text: 'error sending' });
|
|
86
116
|
if (
|
|
87
117
|
error.message &&
|
|
88
|
-
error.message.includes(
|
|
89
|
-
error.message.includes(
|
|
118
|
+
error.message.includes('SSL routines') &&
|
|
119
|
+
error.message.includes('wrong version number')
|
|
90
120
|
) {
|
|
91
121
|
// Improved error message for SSL/TLS issues
|
|
92
|
-
done(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
122
|
+
done(
|
|
123
|
+
new Error(
|
|
124
|
+
'SSL/TLS connection failed: Wrong version number. ' +
|
|
125
|
+
'This usually means the wrong port or security settings are used. ' +
|
|
126
|
+
'For SMTP: use port 587 with secure=false (STARTTLS) or port 465 with secure=true (SSL/TLS).',
|
|
127
|
+
),
|
|
128
|
+
);
|
|
97
129
|
} else {
|
|
98
130
|
done(error);
|
|
99
131
|
}
|
|
@@ -103,19 +135,19 @@ module.exports = function(RED) {
|
|
|
103
135
|
|
|
104
136
|
if (msg.payload.accepted && msg.payload.accepted.length > 0) {
|
|
105
137
|
msg.payload = msg.input;
|
|
106
|
-
node.status({ fill:
|
|
138
|
+
node.status({ fill: 'green', shape: 'dot', text: 'sent' });
|
|
107
139
|
send(msg);
|
|
108
140
|
done();
|
|
109
141
|
} else if (msg.payload.rejected && msg.payload.rejected.length > 0) {
|
|
110
142
|
msg.error = { result: msg.payload.rejected };
|
|
111
|
-
node.status({ fill:
|
|
143
|
+
node.status({ fill: 'red', shape: 'dot', text: 'rejected' });
|
|
112
144
|
done(new Error('Email rejected: ' + msg.payload.rejected.join(', ')));
|
|
113
145
|
} else if (msg.payload.pending && msg.payload.pending.length > 0) {
|
|
114
146
|
msg.error = { result: msg.payload.pending };
|
|
115
|
-
node.status({ fill:
|
|
147
|
+
node.status({ fill: 'yellow', shape: 'dot', text: 'pending' });
|
|
116
148
|
done(new Error('Email pending: ' + msg.payload.pending.join(', ')));
|
|
117
149
|
} else {
|
|
118
|
-
node.status({ fill:
|
|
150
|
+
node.status({ fill: 'red', shape: 'dot', text: 'unknown error' });
|
|
119
151
|
done(new Error('Unknown error while sending email.'));
|
|
120
152
|
}
|
|
121
153
|
}
|
|
@@ -123,14 +155,14 @@ module.exports = function(RED) {
|
|
|
123
155
|
});
|
|
124
156
|
}
|
|
125
157
|
|
|
126
|
-
RED.nodes.registerType(
|
|
158
|
+
RED.nodes.registerType('email-sender', EmailSenderNode);
|
|
127
159
|
|
|
128
160
|
function safeEvaluatePropertyAttachment(config, node, msg) {
|
|
129
161
|
if (config.attachments && config.attachments.trim() !== '') {
|
|
130
162
|
try {
|
|
131
163
|
return RED.util.evaluateNodeProperty(config.attachments, config.attachmentsType, node, msg);
|
|
132
164
|
} catch (e) {
|
|
133
|
-
node.error(
|
|
165
|
+
node.error('Failed to evaluate attachments property: ' + e.message, msg);
|
|
134
166
|
return null;
|
|
135
167
|
}
|
|
136
168
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@5minds/node-red-contrib-processcube-tools",
|
|
3
|
-
"version": "1.0.1-feature-
|
|
3
|
+
"version": "1.0.1-feature-258a01-mfm4xbwl",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Node-RED tools nodes for ProcessCube",
|
|
6
6
|
"scripts": {
|
|
@@ -53,9 +53,7 @@
|
|
|
53
53
|
"chai": "^4.3.4",
|
|
54
54
|
"mocha": "^11.7.2",
|
|
55
55
|
"node-red": "^4.0.9",
|
|
56
|
-
"node-red-node-test-helper": "^0.3.5"
|
|
57
|
-
"should": "^13.2.3",
|
|
58
|
-
"sinon": "^11.1.2"
|
|
56
|
+
"node-red-node-test-helper": "^0.3.5"
|
|
59
57
|
},
|
|
60
58
|
"overrides": {
|
|
61
59
|
"semver": ">=7.5.2",
|
|
@@ -22,20 +22,20 @@
|
|
|
22
22
|
</script>
|
|
23
23
|
|
|
24
24
|
<script type="text/markdown" data-help-name="processcube-google-docs-mail-template">
|
|
25
|
-
# Html 2 Text
|
|
25
|
+
# Html 2 Text
|
|
26
26
|
|
|
27
|
-
## Inputs
|
|
27
|
+
## Inputs
|
|
28
28
|
|
|
29
|
-
: payload (String) : html content to convert to text
|
|
29
|
+
: payload (String) : html content to convert to text
|
|
30
30
|
|
|
31
|
-
## Outputs
|
|
31
|
+
## Outputs
|
|
32
32
|
|
|
33
|
-
: payload (String) : text content
|
|
33
|
+
: payload (String) : text content
|
|
34
34
|
|
|
35
|
-
---
|
|
35
|
+
---
|
|
36
36
|
|
|
37
|
-
## References
|
|
37
|
+
## References
|
|
38
38
|
|
|
39
|
-
- [The ProcessCube Developer Network](https://processcube.io) – All documentation for the ProcessCube© platform
|
|
40
|
-
- [Node-RED Integration in ProcessCube©](https://processcube.io/docs/node-red) – Node-RED integration in ProcessCube©
|
|
39
|
+
- [The ProcessCube Developer Network](https://processcube.io) – All documentation for the ProcessCube© platform
|
|
40
|
+
- [Node-RED Integration in ProcessCube©](https://processcube.io/docs/node-red) – Node-RED integration in ProcessCube©
|
|
41
41
|
</script>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
module.exports = function (RED) {
|
|
2
|
-
|
|
3
2
|
const { compile } = require('html-to-text');
|
|
4
3
|
|
|
5
4
|
function ProcesscubeHtmlToText(config) {
|
|
@@ -12,9 +11,7 @@ module.exports = function (RED) {
|
|
|
12
11
|
};
|
|
13
12
|
const compiledConvert = compile(options); // options passed here
|
|
14
13
|
|
|
15
|
-
|
|
16
14
|
node.on('input', async function (msg) {
|
|
17
|
-
|
|
18
15
|
msg.payload = compiledConvert(msg.payload);
|
|
19
16
|
|
|
20
17
|
node.send(msg);
|