polikolog 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. package/.idea/5lab.iml +12 -0
  2. package/.idea/inspectionProfiles/Project_Default.xml +10 -0
  3. package/.idea/jsLibraryMappings.xml +6 -0
  4. package/.idea/modules.xml +8 -0
  5. package/.idea/vcs.xml +6 -0
  6. package/06-02.js +48 -0
  7. package/06-03.js +22 -0
  8. package/06-04.js +22 -0
  9. package/index.html +41 -0
  10. package/m0603.js +28 -0
  11. package/mypackage/m0603.js +28 -0
  12. package/mypackage/node_modules/.package-lock.json +24 -0
  13. package/mypackage/node_modules/nodemailer/.gitattributes +6 -0
  14. package/mypackage/node_modules/nodemailer/.prettierrc.js +8 -0
  15. package/mypackage/node_modules/nodemailer/CHANGELOG.md +725 -0
  16. package/mypackage/node_modules/nodemailer/CODE_OF_CONDUCT.md +76 -0
  17. package/mypackage/node_modules/nodemailer/CONTRIBUTING.md +67 -0
  18. package/mypackage/node_modules/nodemailer/LICENSE +16 -0
  19. package/mypackage/node_modules/nodemailer/README.md +97 -0
  20. package/mypackage/node_modules/nodemailer/SECURITY.txt +22 -0
  21. package/mypackage/node_modules/nodemailer/lib/addressparser/index.js +313 -0
  22. package/mypackage/node_modules/nodemailer/lib/base64/index.js +142 -0
  23. package/mypackage/node_modules/nodemailer/lib/dkim/index.js +251 -0
  24. package/mypackage/node_modules/nodemailer/lib/dkim/message-parser.js +155 -0
  25. package/mypackage/node_modules/nodemailer/lib/dkim/relaxed-body.js +154 -0
  26. package/mypackage/node_modules/nodemailer/lib/dkim/sign.js +117 -0
  27. package/mypackage/node_modules/nodemailer/lib/fetch/cookies.js +281 -0
  28. package/mypackage/node_modules/nodemailer/lib/fetch/index.js +274 -0
  29. package/mypackage/node_modules/nodemailer/lib/json-transport/index.js +82 -0
  30. package/mypackage/node_modules/nodemailer/lib/mail-composer/index.js +558 -0
  31. package/mypackage/node_modules/nodemailer/lib/mailer/index.js +427 -0
  32. package/mypackage/node_modules/nodemailer/lib/mailer/mail-message.js +315 -0
  33. package/mypackage/node_modules/nodemailer/lib/mime-funcs/index.js +625 -0
  34. package/mypackage/node_modules/nodemailer/lib/mime-funcs/mime-types.js +2102 -0
  35. package/mypackage/node_modules/nodemailer/lib/mime-node/index.js +1290 -0
  36. package/mypackage/node_modules/nodemailer/lib/mime-node/last-newline.js +33 -0
  37. package/mypackage/node_modules/nodemailer/lib/mime-node/le-unix.js +43 -0
  38. package/mypackage/node_modules/nodemailer/lib/mime-node/le-windows.js +52 -0
  39. package/mypackage/node_modules/nodemailer/lib/nodemailer.js +143 -0
  40. package/mypackage/node_modules/nodemailer/lib/qp/index.js +219 -0
  41. package/mypackage/node_modules/nodemailer/lib/sendmail-transport/index.js +210 -0
  42. package/mypackage/node_modules/nodemailer/lib/ses-transport/index.js +349 -0
  43. package/mypackage/node_modules/nodemailer/lib/shared/index.js +638 -0
  44. package/mypackage/node_modules/nodemailer/lib/smtp-connection/data-stream.js +108 -0
  45. package/mypackage/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +143 -0
  46. package/mypackage/node_modules/nodemailer/lib/smtp-connection/index.js +1796 -0
  47. package/mypackage/node_modules/nodemailer/lib/smtp-pool/index.js +648 -0
  48. package/mypackage/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +253 -0
  49. package/mypackage/node_modules/nodemailer/lib/smtp-transport/index.js +416 -0
  50. package/mypackage/node_modules/nodemailer/lib/stream-transport/index.js +135 -0
  51. package/mypackage/node_modules/nodemailer/lib/well-known/index.js +47 -0
  52. package/mypackage/node_modules/nodemailer/lib/well-known/services.json +286 -0
  53. package/mypackage/node_modules/nodemailer/lib/xoauth2/index.js +376 -0
  54. package/mypackage/node_modules/nodemailer/package.json +46 -0
  55. package/mypackage/node_modules/nodemailer/postinstall.js +101 -0
  56. package/mypackage/package.json +15 -0
  57. package/package.json +15 -0
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ const Transform = require('stream').Transform;
4
+
5
+ class LastNewline extends Transform {
6
+ constructor() {
7
+ super();
8
+ this.lastByte = false;
9
+ }
10
+
11
+ _transform(chunk, encoding, done) {
12
+ if (chunk.length) {
13
+ this.lastByte = chunk[chunk.length - 1];
14
+ }
15
+
16
+ this.push(chunk);
17
+ done();
18
+ }
19
+
20
+ _flush(done) {
21
+ if (this.lastByte === 0x0a) {
22
+ return done();
23
+ }
24
+ if (this.lastByte === 0x0d) {
25
+ this.push(Buffer.from('\n'));
26
+ return done();
27
+ }
28
+ this.push(Buffer.from('\r\n'));
29
+ return done();
30
+ }
31
+ }
32
+
33
+ module.exports = LastNewline;
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ const stream = require('stream');
4
+ const Transform = stream.Transform;
5
+
6
+ /**
7
+ * Ensures that only <LF> is used for linebreaks
8
+ *
9
+ * @param {Object} options Stream options
10
+ */
11
+ class LeWindows extends Transform {
12
+ constructor(options) {
13
+ super(options);
14
+ // init Transform
15
+ this.options = options || {};
16
+ }
17
+
18
+ /**
19
+ * Escapes dots
20
+ */
21
+ _transform(chunk, encoding, done) {
22
+ let buf;
23
+ let lastPos = 0;
24
+
25
+ for (let i = 0, len = chunk.length; i < len; i++) {
26
+ if (chunk[i] === 0x0d) {
27
+ // \n
28
+ buf = chunk.slice(lastPos, i);
29
+ lastPos = i + 1;
30
+ this.push(buf);
31
+ }
32
+ }
33
+ if (lastPos && lastPos < chunk.length) {
34
+ buf = chunk.slice(lastPos);
35
+ this.push(buf);
36
+ } else if (!lastPos) {
37
+ this.push(chunk);
38
+ }
39
+ done();
40
+ }
41
+ }
42
+
43
+ module.exports = LeWindows;
@@ -0,0 +1,52 @@
1
+ 'use strict';
2
+
3
+ const stream = require('stream');
4
+ const Transform = stream.Transform;
5
+
6
+ /**
7
+ * Ensures that only <CR><LF> sequences are used for linebreaks
8
+ *
9
+ * @param {Object} options Stream options
10
+ */
11
+ class LeWindows extends Transform {
12
+ constructor(options) {
13
+ super(options);
14
+ // init Transform
15
+ this.options = options || {};
16
+ this.lastByte = false;
17
+ }
18
+
19
+ /**
20
+ * Escapes dots
21
+ */
22
+ _transform(chunk, encoding, done) {
23
+ let buf;
24
+ let lastPos = 0;
25
+
26
+ for (let i = 0, len = chunk.length; i < len; i++) {
27
+ if (chunk[i] === 0x0a) {
28
+ // \n
29
+ if ((i && chunk[i - 1] !== 0x0d) || (!i && this.lastByte !== 0x0d)) {
30
+ if (i > lastPos) {
31
+ buf = chunk.slice(lastPos, i);
32
+ this.push(buf);
33
+ }
34
+ this.push(Buffer.from('\r\n'));
35
+ lastPos = i + 1;
36
+ }
37
+ }
38
+ }
39
+
40
+ if (lastPos && lastPos < chunk.length) {
41
+ buf = chunk.slice(lastPos);
42
+ this.push(buf);
43
+ } else if (!lastPos) {
44
+ this.push(chunk);
45
+ }
46
+
47
+ this.lastByte = chunk[chunk.length - 1];
48
+ done();
49
+ }
50
+ }
51
+
52
+ module.exports = LeWindows;
@@ -0,0 +1,143 @@
1
+ 'use strict';
2
+
3
+ const Mailer = require('./mailer');
4
+ const shared = require('./shared');
5
+ const SMTPPool = require('./smtp-pool');
6
+ const SMTPTransport = require('./smtp-transport');
7
+ const SendmailTransport = require('./sendmail-transport');
8
+ const StreamTransport = require('./stream-transport');
9
+ const JSONTransport = require('./json-transport');
10
+ const SESTransport = require('./ses-transport');
11
+ const nmfetch = require('./fetch');
12
+ const packageData = require('../package.json');
13
+
14
+ const ETHEREAL_API = (process.env.ETHEREAL_API || 'https://api.nodemailer.com').replace(/\/+$/, '');
15
+ const ETHEREAL_WEB = (process.env.ETHEREAL_WEB || 'https://ethereal.email').replace(/\/+$/, '');
16
+ const ETHEREAL_CACHE = ['true', 'yes', 'y', '1'].includes((process.env.ETHEREAL_CACHE || 'yes').toString().trim().toLowerCase());
17
+
18
+ let testAccount = false;
19
+
20
+ module.exports.createTransport = function (transporter, defaults) {
21
+ let urlConfig;
22
+ let options;
23
+ let mailer;
24
+
25
+ if (
26
+ // provided transporter is a configuration object, not transporter plugin
27
+ (typeof transporter === 'object' && typeof transporter.send !== 'function') ||
28
+ // provided transporter looks like a connection url
29
+ (typeof transporter === 'string' && /^(smtps?|direct):/i.test(transporter))
30
+ ) {
31
+ if ((urlConfig = typeof transporter === 'string' ? transporter : transporter.url)) {
32
+ // parse a configuration URL into configuration options
33
+ options = shared.parseConnectionUrl(urlConfig);
34
+ } else {
35
+ options = transporter;
36
+ }
37
+
38
+ if (options.pool) {
39
+ transporter = new SMTPPool(options);
40
+ } else if (options.sendmail) {
41
+ transporter = new SendmailTransport(options);
42
+ } else if (options.streamTransport) {
43
+ transporter = new StreamTransport(options);
44
+ } else if (options.jsonTransport) {
45
+ transporter = new JSONTransport(options);
46
+ } else if (options.SES) {
47
+ transporter = new SESTransport(options);
48
+ } else {
49
+ transporter = new SMTPTransport(options);
50
+ }
51
+ }
52
+
53
+ mailer = new Mailer(transporter, options, defaults);
54
+
55
+ return mailer;
56
+ };
57
+
58
+ module.exports.createTestAccount = function (apiUrl, callback) {
59
+ let promise;
60
+
61
+ if (!callback && typeof apiUrl === 'function') {
62
+ callback = apiUrl;
63
+ apiUrl = false;
64
+ }
65
+
66
+ if (!callback) {
67
+ promise = new Promise((resolve, reject) => {
68
+ callback = shared.callbackPromise(resolve, reject);
69
+ });
70
+ }
71
+
72
+ if (ETHEREAL_CACHE && testAccount) {
73
+ setImmediate(() => callback(null, testAccount));
74
+ return promise;
75
+ }
76
+
77
+ apiUrl = apiUrl || ETHEREAL_API;
78
+
79
+ let chunks = [];
80
+ let chunklen = 0;
81
+
82
+ let req = nmfetch(apiUrl + '/user', {
83
+ contentType: 'application/json',
84
+ method: 'POST',
85
+ body: Buffer.from(
86
+ JSON.stringify({
87
+ requestor: packageData.name,
88
+ version: packageData.version
89
+ })
90
+ )
91
+ });
92
+
93
+ req.on('readable', () => {
94
+ let chunk;
95
+ while ((chunk = req.read()) !== null) {
96
+ chunks.push(chunk);
97
+ chunklen += chunk.length;
98
+ }
99
+ });
100
+
101
+ req.once('error', err => callback(err));
102
+
103
+ req.once('end', () => {
104
+ let res = Buffer.concat(chunks, chunklen);
105
+ let data;
106
+ let err;
107
+ try {
108
+ data = JSON.parse(res.toString());
109
+ } catch (E) {
110
+ err = E;
111
+ }
112
+ if (err) {
113
+ return callback(err);
114
+ }
115
+ if (data.status !== 'success' || data.error) {
116
+ return callback(new Error(data.error || 'Request failed'));
117
+ }
118
+ delete data.status;
119
+ testAccount = data;
120
+ callback(null, testAccount);
121
+ });
122
+
123
+ return promise;
124
+ };
125
+
126
+ module.exports.getTestMessageUrl = function (info) {
127
+ if (!info || !info.response) {
128
+ return false;
129
+ }
130
+
131
+ let infoProps = new Map();
132
+ info.response.replace(/\[([^\]]+)\]$/, (m, props) => {
133
+ props.replace(/\b([A-Z0-9]+)=([^\s]+)/g, (m, key, value) => {
134
+ infoProps.set(key, value);
135
+ });
136
+ });
137
+
138
+ if (infoProps.has('STATUS') && infoProps.has('MSGID')) {
139
+ return (testAccount.web || ETHEREAL_WEB) + '/message/' + infoProps.get('MSGID');
140
+ }
141
+
142
+ return false;
143
+ };
@@ -0,0 +1,219 @@
1
+ 'use strict';
2
+
3
+ const Transform = require('stream').Transform;
4
+
5
+ /**
6
+ * Encodes a Buffer into a Quoted-Printable encoded string
7
+ *
8
+ * @param {Buffer} buffer Buffer to convert
9
+ * @returns {String} Quoted-Printable encoded string
10
+ */
11
+ function encode(buffer) {
12
+ if (typeof buffer === 'string') {
13
+ buffer = Buffer.from(buffer, 'utf-8');
14
+ }
15
+
16
+ // usable characters that do not need encoding
17
+ let ranges = [
18
+ // https://tools.ietf.org/html/rfc2045#section-6.7
19
+ [0x09], // <TAB>
20
+ [0x0a], // <LF>
21
+ [0x0d], // <CR>
22
+ [0x20, 0x3c], // <SP>!"#$%&'()*+,-./0123456789:;
23
+ [0x3e, 0x7e] // >?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}
24
+ ];
25
+ let result = '';
26
+ let ord;
27
+
28
+ for (let i = 0, len = buffer.length; i < len; i++) {
29
+ ord = buffer[i];
30
+ // if the char is in allowed range, then keep as is, unless it is a WS in the end of a line
31
+ if (checkRanges(ord, ranges) && !((ord === 0x20 || ord === 0x09) && (i === len - 1 || buffer[i + 1] === 0x0a || buffer[i + 1] === 0x0d))) {
32
+ result += String.fromCharCode(ord);
33
+ continue;
34
+ }
35
+ result += '=' + (ord < 0x10 ? '0' : '') + ord.toString(16).toUpperCase();
36
+ }
37
+
38
+ return result;
39
+ }
40
+
41
+ /**
42
+ * Adds soft line breaks to a Quoted-Printable string
43
+ *
44
+ * @param {String} str Quoted-Printable encoded string that might need line wrapping
45
+ * @param {Number} [lineLength=76] Maximum allowed length for a line
46
+ * @returns {String} Soft-wrapped Quoted-Printable encoded string
47
+ */
48
+ function wrap(str, lineLength) {
49
+ str = (str || '').toString();
50
+ lineLength = lineLength || 76;
51
+
52
+ if (str.length <= lineLength) {
53
+ return str;
54
+ }
55
+
56
+ let pos = 0;
57
+ let len = str.length;
58
+ let match, code, line;
59
+ let lineMargin = Math.floor(lineLength / 3);
60
+ let result = '';
61
+
62
+ // insert soft linebreaks where needed
63
+ while (pos < len) {
64
+ line = str.substr(pos, lineLength);
65
+ if ((match = line.match(/\r\n/))) {
66
+ line = line.substr(0, match.index + match[0].length);
67
+ result += line;
68
+ pos += line.length;
69
+ continue;
70
+ }
71
+
72
+ if (line.substr(-1) === '\n') {
73
+ // nothing to change here
74
+ result += line;
75
+ pos += line.length;
76
+ continue;
77
+ } else if ((match = line.substr(-lineMargin).match(/\n.*?$/))) {
78
+ // truncate to nearest line break
79
+ line = line.substr(0, line.length - (match[0].length - 1));
80
+ result += line;
81
+ pos += line.length;
82
+ continue;
83
+ } else if (line.length > lineLength - lineMargin && (match = line.substr(-lineMargin).match(/[ \t.,!?][^ \t.,!?]*$/))) {
84
+ // truncate to nearest space
85
+ line = line.substr(0, line.length - (match[0].length - 1));
86
+ } else if (line.match(/[=][\da-f]{0,2}$/i)) {
87
+ // push incomplete encoding sequences to the next line
88
+ if ((match = line.match(/[=][\da-f]{0,1}$/i))) {
89
+ line = line.substr(0, line.length - match[0].length);
90
+ }
91
+
92
+ // ensure that utf-8 sequences are not split
93
+ while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/[=][\da-f]{2}$/gi))) {
94
+ code = parseInt(match[0].substr(1, 2), 16);
95
+ if (code < 128) {
96
+ break;
97
+ }
98
+
99
+ line = line.substr(0, line.length - 3);
100
+
101
+ if (code >= 0xc0) {
102
+ break;
103
+ }
104
+ }
105
+ }
106
+
107
+ if (pos + line.length < len && line.substr(-1) !== '\n') {
108
+ if (line.length === lineLength && line.match(/[=][\da-f]{2}$/i)) {
109
+ line = line.substr(0, line.length - 3);
110
+ } else if (line.length === lineLength) {
111
+ line = line.substr(0, line.length - 1);
112
+ }
113
+ pos += line.length;
114
+ line += '=\r\n';
115
+ } else {
116
+ pos += line.length;
117
+ }
118
+
119
+ result += line;
120
+ }
121
+
122
+ return result;
123
+ }
124
+
125
+ /**
126
+ * Helper function to check if a number is inside provided ranges
127
+ *
128
+ * @param {Number} nr Number to check for
129
+ * @param {Array} ranges An Array of allowed values
130
+ * @returns {Boolean} True if the value was found inside allowed ranges, false otherwise
131
+ */
132
+ function checkRanges(nr, ranges) {
133
+ for (let i = ranges.length - 1; i >= 0; i--) {
134
+ if (!ranges[i].length) {
135
+ continue;
136
+ }
137
+ if (ranges[i].length === 1 && nr === ranges[i][0]) {
138
+ return true;
139
+ }
140
+ if (ranges[i].length === 2 && nr >= ranges[i][0] && nr <= ranges[i][1]) {
141
+ return true;
142
+ }
143
+ }
144
+ return false;
145
+ }
146
+
147
+ /**
148
+ * Creates a transform stream for encoding data to Quoted-Printable encoding
149
+ *
150
+ * @constructor
151
+ * @param {Object} options Stream options
152
+ * @param {Number} [options.lineLength=76] Maximum length for lines, set to false to disable wrapping
153
+ */
154
+ class Encoder extends Transform {
155
+ constructor(options) {
156
+ super();
157
+
158
+ // init Transform
159
+ this.options = options || {};
160
+
161
+ if (this.options.lineLength !== false) {
162
+ this.options.lineLength = this.options.lineLength || 76;
163
+ }
164
+
165
+ this._curLine = '';
166
+
167
+ this.inputBytes = 0;
168
+ this.outputBytes = 0;
169
+ }
170
+
171
+ _transform(chunk, encoding, done) {
172
+ let qp;
173
+
174
+ if (encoding !== 'buffer') {
175
+ chunk = Buffer.from(chunk, encoding);
176
+ }
177
+
178
+ if (!chunk || !chunk.length) {
179
+ return done();
180
+ }
181
+
182
+ this.inputBytes += chunk.length;
183
+
184
+ if (this.options.lineLength) {
185
+ qp = this._curLine + encode(chunk);
186
+ qp = wrap(qp, this.options.lineLength);
187
+ qp = qp.replace(/(^|\n)([^\n]*)$/, (match, lineBreak, lastLine) => {
188
+ this._curLine = lastLine;
189
+ return lineBreak;
190
+ });
191
+
192
+ if (qp) {
193
+ this.outputBytes += qp.length;
194
+ this.push(qp);
195
+ }
196
+ } else {
197
+ qp = encode(chunk);
198
+ this.outputBytes += qp.length;
199
+ this.push(qp, 'ascii');
200
+ }
201
+
202
+ done();
203
+ }
204
+
205
+ _flush(done) {
206
+ if (this._curLine) {
207
+ this.outputBytes += this._curLine.length;
208
+ this.push(this._curLine, 'ascii');
209
+ }
210
+ done();
211
+ }
212
+ }
213
+
214
+ // expose to the world
215
+ module.exports = {
216
+ encode,
217
+ wrap,
218
+ Encoder
219
+ };
@@ -0,0 +1,210 @@
1
+ 'use strict';
2
+
3
+ const spawn = require('child_process').spawn;
4
+ const packageData = require('../../package.json');
5
+ const shared = require('../shared');
6
+
7
+ /**
8
+ * Generates a Transport object for Sendmail
9
+ *
10
+ * Possible options can be the following:
11
+ *
12
+ * * **path** optional path to sendmail binary
13
+ * * **newline** either 'windows' or 'unix'
14
+ * * **args** an array of arguments for the sendmail binary
15
+ *
16
+ * @constructor
17
+ * @param {Object} optional config parameter for Sendmail
18
+ */
19
+ class SendmailTransport {
20
+ constructor(options) {
21
+ options = options || {};
22
+
23
+ // use a reference to spawn for mocking purposes
24
+ this._spawn = spawn;
25
+
26
+ this.options = options || {};
27
+
28
+ this.name = 'Sendmail';
29
+ this.version = packageData.version;
30
+
31
+ this.path = 'sendmail';
32
+ this.args = false;
33
+ this.winbreak = false;
34
+
35
+ this.logger = shared.getLogger(this.options, {
36
+ component: this.options.component || 'sendmail'
37
+ });
38
+
39
+ if (options) {
40
+ if (typeof options === 'string') {
41
+ this.path = options;
42
+ } else if (typeof options === 'object') {
43
+ if (options.path) {
44
+ this.path = options.path;
45
+ }
46
+ if (Array.isArray(options.args)) {
47
+ this.args = options.args;
48
+ }
49
+ this.winbreak = ['win', 'windows', 'dos', '\r\n'].includes((options.newline || '').toString().toLowerCase());
50
+ }
51
+ }
52
+ }
53
+
54
+ /**
55
+ * <p>Compiles a mailcomposer message and forwards it to handler that sends it.</p>
56
+ *
57
+ * @param {Object} emailMessage MailComposer object
58
+ * @param {Function} callback Callback function to run when the sending is completed
59
+ */
60
+ send(mail, done) {
61
+ // Sendmail strips this header line by itself
62
+ mail.message.keepBcc = true;
63
+
64
+ let envelope = mail.data.envelope || mail.message.getEnvelope();
65
+ let messageId = mail.message.messageId();
66
+ let args;
67
+ let sendmail;
68
+ let returned;
69
+
70
+ const hasInvalidAddresses = []
71
+ .concat(envelope.from || [])
72
+ .concat(envelope.to || [])
73
+ .some(addr => /^-/.test(addr));
74
+ if (hasInvalidAddresses) {
75
+ return done(new Error('Can not send mail. Invalid envelope addresses.'));
76
+ }
77
+
78
+ if (this.args) {
79
+ // force -i to keep single dots
80
+ args = ['-i'].concat(this.args).concat(envelope.to);
81
+ } else {
82
+ args = ['-i'].concat(envelope.from ? ['-f', envelope.from] : []).concat(envelope.to);
83
+ }
84
+
85
+ let callback = err => {
86
+ if (returned) {
87
+ // ignore any additional responses, already done
88
+ return;
89
+ }
90
+ returned = true;
91
+ if (typeof done === 'function') {
92
+ if (err) {
93
+ return done(err);
94
+ } else {
95
+ return done(null, {
96
+ envelope: mail.data.envelope || mail.message.getEnvelope(),
97
+ messageId,
98
+ response: 'Messages queued for delivery'
99
+ });
100
+ }
101
+ }
102
+ };
103
+
104
+ try {
105
+ sendmail = this._spawn(this.path, args);
106
+ } catch (E) {
107
+ this.logger.error(
108
+ {
109
+ err: E,
110
+ tnx: 'spawn',
111
+ messageId
112
+ },
113
+ 'Error occurred while spawning sendmail. %s',
114
+ E.message
115
+ );
116
+ return callback(E);
117
+ }
118
+
119
+ if (sendmail) {
120
+ sendmail.on('error', err => {
121
+ this.logger.error(
122
+ {
123
+ err,
124
+ tnx: 'spawn',
125
+ messageId
126
+ },
127
+ 'Error occurred when sending message %s. %s',
128
+ messageId,
129
+ err.message
130
+ );
131
+ callback(err);
132
+ });
133
+
134
+ sendmail.once('exit', code => {
135
+ if (!code) {
136
+ return callback();
137
+ }
138
+ let err;
139
+ if (code === 127) {
140
+ err = new Error('Sendmail command not found, process exited with code ' + code);
141
+ } else {
142
+ err = new Error('Sendmail exited with code ' + code);
143
+ }
144
+
145
+ this.logger.error(
146
+ {
147
+ err,
148
+ tnx: 'stdin',
149
+ messageId
150
+ },
151
+ 'Error sending message %s to sendmail. %s',
152
+ messageId,
153
+ err.message
154
+ );
155
+ callback(err);
156
+ });
157
+ sendmail.once('close', callback);
158
+
159
+ sendmail.stdin.on('error', err => {
160
+ this.logger.error(
161
+ {
162
+ err,
163
+ tnx: 'stdin',
164
+ messageId
165
+ },
166
+ 'Error occurred when piping message %s to sendmail. %s',
167
+ messageId,
168
+ err.message
169
+ );
170
+ callback(err);
171
+ });
172
+
173
+ let recipients = [].concat(envelope.to || []);
174
+ if (recipients.length > 3) {
175
+ recipients.push('...and ' + recipients.splice(2).length + ' more');
176
+ }
177
+ this.logger.info(
178
+ {
179
+ tnx: 'send',
180
+ messageId
181
+ },
182
+ 'Sending message %s to <%s>',
183
+ messageId,
184
+ recipients.join(', ')
185
+ );
186
+
187
+ let sourceStream = mail.message.createReadStream();
188
+ sourceStream.once('error', err => {
189
+ this.logger.error(
190
+ {
191
+ err,
192
+ tnx: 'stdin',
193
+ messageId
194
+ },
195
+ 'Error occurred when generating message %s. %s',
196
+ messageId,
197
+ err.message
198
+ );
199
+ sendmail.kill('SIGINT'); // do not deliver the message
200
+ callback(err);
201
+ });
202
+
203
+ sourceStream.pipe(sendmail.stdin);
204
+ } else {
205
+ return callback(new Error('sendmail was not found'));
206
+ }
207
+ }
208
+ }
209
+
210
+ module.exports = SendmailTransport;