Haraka 3.1.0 → 3.1.2

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.
Files changed (160) hide show
  1. package/.prettierignore +4 -0
  2. package/CONTRIBUTORS.md +5 -5
  3. package/Changes.md +69 -50
  4. package/Plugins.md +3 -1
  5. package/README.md +1 -1
  6. package/bin/haraka +475 -478
  7. package/config/outbound.ini +3 -0
  8. package/connection.js +1072 -1108
  9. package/docs/Connection.md +29 -30
  10. package/docs/CoreConfig.md +38 -39
  11. package/docs/CustomReturnCodes.md +0 -1
  12. package/docs/HAProxy.md +2 -2
  13. package/docs/Header.md +1 -1
  14. package/docs/Logging.md +29 -5
  15. package/docs/Outbound.md +93 -78
  16. package/docs/Plugins.md +103 -108
  17. package/docs/Transaction.md +49 -51
  18. package/docs/Tutorial.md +127 -143
  19. package/docs/deprecated/access.md +0 -1
  20. package/docs/deprecated/backscatterer.md +2 -3
  21. package/docs/deprecated/connect.rdns_access.md +18 -27
  22. package/docs/deprecated/data.headers.md +0 -1
  23. package/docs/deprecated/data.nomsgid.md +1 -2
  24. package/docs/deprecated/data.noreceived.md +1 -2
  25. package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
  26. package/docs/deprecated/dkim_sign.md +13 -17
  27. package/docs/deprecated/dkim_verify.md +9 -17
  28. package/docs/deprecated/dnsbl.md +36 -38
  29. package/docs/deprecated/dnswl.md +41 -43
  30. package/docs/deprecated/lookup_rdns.strict.md +21 -34
  31. package/docs/deprecated/mail_from.access.md +17 -25
  32. package/docs/deprecated/mail_from.blocklist.md +9 -12
  33. package/docs/deprecated/mail_from.nobounces.md +1 -2
  34. package/docs/deprecated/rcpt_to.access.md +20 -27
  35. package/docs/deprecated/rcpt_to.blocklist.md +10 -13
  36. package/docs/deprecated/rcpt_to.routes.md +0 -1
  37. package/docs/deprecated/rdns.regexp.md +13 -15
  38. package/docs/plugins/aliases.md +89 -89
  39. package/docs/plugins/auth/auth_bridge.md +5 -7
  40. package/docs/plugins/auth/auth_ldap.md +11 -14
  41. package/docs/plugins/auth/auth_proxy.md +10 -12
  42. package/docs/plugins/auth/auth_vpopmaild.md +5 -6
  43. package/docs/plugins/auth/flat_file.md +4 -4
  44. package/docs/plugins/block_me.md +3 -3
  45. package/docs/plugins/data.signatures.md +1 -2
  46. package/docs/plugins/delay_deny.md +3 -4
  47. package/docs/plugins/max_unrecognized_commands.md +4 -4
  48. package/docs/plugins/prevent_credential_leaks.md +6 -6
  49. package/docs/plugins/process_title.md +18 -18
  50. package/docs/plugins/queue/deliver.md +2 -3
  51. package/docs/plugins/queue/discard.md +4 -4
  52. package/docs/plugins/queue/lmtp.md +1 -3
  53. package/docs/plugins/queue/qmail-queue.md +7 -9
  54. package/docs/plugins/queue/quarantine.md +16 -21
  55. package/docs/plugins/queue/rabbitmq.md +8 -11
  56. package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
  57. package/docs/plugins/queue/smtp_bridge.md +7 -10
  58. package/docs/plugins/queue/smtp_forward.md +42 -34
  59. package/docs/plugins/queue/smtp_proxy.md +30 -29
  60. package/docs/plugins/queue/test.md +1 -3
  61. package/docs/plugins/rcpt_to.in_host_list.md +6 -6
  62. package/docs/plugins/rcpt_to.max_count.md +1 -1
  63. package/docs/plugins/record_envelope_addresses.md +3 -3
  64. package/docs/plugins/reseed_rng.md +6 -6
  65. package/docs/plugins/status.md +9 -8
  66. package/docs/plugins/tarpit.md +7 -11
  67. package/docs/plugins/tls.md +12 -17
  68. package/docs/plugins/toobusy.md +4 -4
  69. package/docs/plugins/xclient.md +3 -3
  70. package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
  71. package/docs/tutorials/SettingUpOutbound.md +6 -9
  72. package/endpoint.js +35 -38
  73. package/eslint.config.mjs +22 -19
  74. package/haraka.js +42 -47
  75. package/host_pool.js +75 -79
  76. package/http/html/404.html +45 -49
  77. package/http/html/index.html +39 -28
  78. package/http/package.json +2 -4
  79. package/line_socket.js +27 -28
  80. package/logger.js +182 -201
  81. package/outbound/client_pool.js +34 -27
  82. package/outbound/config.js +64 -59
  83. package/outbound/fsync_writestream.js +24 -25
  84. package/outbound/hmail.js +888 -835
  85. package/outbound/index.js +194 -187
  86. package/outbound/qfile.js +49 -52
  87. package/outbound/queue.js +197 -190
  88. package/outbound/timer_queue.js +41 -43
  89. package/outbound/tls.js +68 -61
  90. package/outbound/todo.js +11 -11
  91. package/package.json +38 -33
  92. package/plugins/.eslintrc.yaml +0 -1
  93. package/plugins/auth/auth_base.js +123 -127
  94. package/plugins/auth/auth_bridge.js +7 -7
  95. package/plugins/auth/auth_proxy.js +121 -126
  96. package/plugins/auth/auth_vpopmaild.js +84 -85
  97. package/plugins/auth/flat_file.js +18 -17
  98. package/plugins/block_me.js +31 -31
  99. package/plugins/data.signatures.js +13 -13
  100. package/plugins/delay_deny.js +65 -61
  101. package/plugins/prevent_credential_leaks.js +23 -23
  102. package/plugins/process_title.js +125 -128
  103. package/plugins/profile.js +5 -5
  104. package/plugins/queue/deliver.js +3 -3
  105. package/plugins/queue/discard.js +13 -14
  106. package/plugins/queue/lmtp.js +16 -17
  107. package/plugins/queue/qmail-queue.js +54 -55
  108. package/plugins/queue/quarantine.js +68 -70
  109. package/plugins/queue/rabbitmq.js +80 -87
  110. package/plugins/queue/rabbitmq_amqplib.js +75 -54
  111. package/plugins/queue/smtp_bridge.js +16 -16
  112. package/plugins/queue/smtp_forward.js +175 -179
  113. package/plugins/queue/smtp_proxy.js +69 -71
  114. package/plugins/queue/test.js +9 -9
  115. package/plugins/rcpt_to.host_list_base.js +30 -34
  116. package/plugins/rcpt_to.in_host_list.js +19 -19
  117. package/plugins/record_envelope_addresses.js +4 -4
  118. package/plugins/reseed_rng.js +4 -4
  119. package/plugins/status.js +90 -97
  120. package/plugins/tarpit.js +25 -14
  121. package/plugins/tls.js +68 -68
  122. package/plugins/toobusy.js +21 -23
  123. package/plugins/xclient.js +51 -53
  124. package/plugins.js +276 -293
  125. package/rfc1869.js +30 -35
  126. package/server.js +308 -299
  127. package/smtp_client.js +244 -228
  128. package/test/.eslintrc.yaml +0 -1
  129. package/test/connection.js +127 -134
  130. package/test/endpoint.js +53 -47
  131. package/test/fixtures/line_socket.js +12 -12
  132. package/test/fixtures/util_hmailitem.js +89 -85
  133. package/test/host_pool.js +90 -92
  134. package/test/installation/plugins/base_plugin.js +2 -2
  135. package/test/installation/plugins/folder_plugin/index.js +2 -3
  136. package/test/installation/plugins/inherits.js +3 -3
  137. package/test/installation/plugins/load_first.js +2 -3
  138. package/test/installation/plugins/plugin.js +1 -3
  139. package/test/installation/plugins/tls.js +2 -4
  140. package/test/logger.js +135 -116
  141. package/test/outbound/hmail.js +49 -35
  142. package/test/outbound/index.js +118 -101
  143. package/test/outbound/qfile.js +51 -53
  144. package/test/outbound_bounce_net_errors.js +84 -69
  145. package/test/outbound_bounce_rfc3464.js +235 -165
  146. package/test/plugins/auth/auth_base.js +420 -279
  147. package/test/plugins/auth/auth_vpopmaild.js +38 -39
  148. package/test/plugins/queue/smtp_forward.js +126 -104
  149. package/test/plugins/rcpt_to.host_list_base.js +85 -67
  150. package/test/plugins/rcpt_to.in_host_list.js +159 -112
  151. package/test/plugins/status.js +71 -64
  152. package/test/plugins/tls.js +37 -34
  153. package/test/plugins.js +97 -92
  154. package/test/rfc1869.js +19 -26
  155. package/test/server.js +293 -272
  156. package/test/smtp_client.js +180 -176
  157. package/test/tls_socket.js +62 -66
  158. package/test/transaction.js +159 -160
  159. package/tls_socket.js +331 -333
  160. package/transaction.js +129 -137
package/transaction.js CHANGED
@@ -1,252 +1,244 @@
1
- 'use strict';
1
+ 'use strict'
2
2
  // An SMTP Transaction
3
3
 
4
- const util = require('node:util');
4
+ const util = require('node:util')
5
5
 
6
- const Notes = require('haraka-notes');
7
- const utils = require('haraka-utils');
6
+ const Notes = require('haraka-notes')
7
+ const utils = require('haraka-utils')
8
8
  const message = require('haraka-email-message')
9
9
 
10
10
  class Transaction {
11
- constructor (uuid, cfg = {}) {
12
- this.uuid = uuid || utils.uuid();
13
- this.cfg = cfg;
14
- this.mail_from = null;
15
- this.rcpt_to = [];
16
- this.header_lines = [];
17
- this.data_lines = [];
18
- this.attachment_start_hooks = [];
19
- this.banner = null;
20
- this.body_filters = [];
21
- this.data_bytes = 0;
22
- this.header_pos = 0;
23
- this.found_hb_sep = false;
24
- this.body = null;
25
- this.parse_body = false;
26
- this.notes = new Notes();
27
- this.notes.skip_plugins = [];
28
- this.header = new message.Header();
29
- this.message_stream = new message.stream(this.cfg, this.uuid, this.header.header_list);
30
- this.discard_data = false;
31
- this.resetting = false;
11
+ constructor(uuid, cfg = {}) {
12
+ this.uuid = uuid || utils.uuid()
13
+ this.cfg = cfg
14
+ this.mail_from = null
15
+ this.rcpt_to = []
16
+ this.header_lines = []
17
+ this.data_lines = []
18
+ this.attachment_start_hooks = []
19
+ this.banner = null
20
+ this.body_filters = []
21
+ this.data_bytes = 0
22
+ this.header_pos = 0
23
+ this.found_hb_sep = false
24
+ this.body = null
25
+ this.parse_body = false
26
+ this.notes = new Notes()
27
+ this.notes.skip_plugins = []
28
+ this.header = new message.Header()
29
+ this.message_stream = new message.stream(this.cfg, this.uuid, this.header.header_list)
30
+ this.discard_data = false
31
+ this.resetting = false
32
32
  this.rcpt_count = {
33
33
  accept: 0,
34
34
  tempfail: 0,
35
35
  reject: 0,
36
36
  }
37
- this.msg_status = undefined;
38
- this.data_post_start = null;
39
- this.data_post_delay = 0;
40
- this.encoding = 'utf8';
41
- this.mime_part_count = 0;
37
+ this.msg_status = undefined
38
+ this.data_post_start = null
39
+ this.data_post_delay = 0
40
+ this.encoding = 'utf8'
41
+ this.mime_part_count = 0
42
42
  }
43
43
 
44
- ensure_body () {
45
- if (this.body) return;
44
+ ensure_body() {
45
+ if (this.body) return
46
46
 
47
- this.body = new message.Body(this.header);
48
- this.body.on('mime_boundary', m => this.incr_mime_count());
47
+ this.body = new message.Body(this.header)
48
+ this.body.on('mime_boundary', (m) => this.incr_mime_count())
49
49
 
50
50
  for (const hook of this.attachment_start_hooks) {
51
- this.body.on('attachment_start', hook);
51
+ this.body.on('attachment_start', hook)
52
52
  }
53
53
 
54
- if (this.banner) this.body.set_banner(this.banner);
54
+ if (this.banner) this.body.set_banner(this.banner)
55
55
 
56
56
  for (const o of this.body_filters) {
57
57
  this.body.add_filter((ct, enc, buf) => {
58
- const re_match = (util.types.isRegExp(o.ct_match) && o.ct_match.test(ct.toLowerCase()));
59
- const ct_begins = ct.toLowerCase().indexOf(String(o.ct_match).toLowerCase()) === 0;
60
- if (re_match || ct_begins) return o.filter(ct, enc, buf);
58
+ const re_match = util.types.isRegExp(o.ct_match) && o.ct_match.test(ct.toLowerCase())
59
+ const ct_begins = ct.toLowerCase().indexOf(String(o.ct_match).toLowerCase()) === 0
60
+ if (re_match || ct_begins) return o.filter(ct, enc, buf)
61
61
  })
62
62
  }
63
63
  }
64
64
 
65
65
  // Removes the CR of a CRLF newline at the end of the buffer.
66
- remove_final_cr (data) {
67
- if (data.length < 2) return data;
68
- if (!Buffer.isBuffer(data)) data = Buffer.from(data);
66
+ remove_final_cr(data) {
67
+ if (data.length < 2) return data
68
+ if (!Buffer.isBuffer(data)) data = Buffer.from(data)
69
69
 
70
- if (data[data.length - 2] === 0x0D && data[data.length - 1] === 0x0A) {
71
- data[data.length - 2] = 0x0A;
72
- return data.slice(0, data.length - 1);
70
+ if (data[data.length - 2] === 0x0d && data[data.length - 1] === 0x0a) {
71
+ data[data.length - 2] = 0x0a
72
+ return data.slice(0, data.length - 1)
73
73
  }
74
- return data;
74
+ return data
75
75
  }
76
76
 
77
77
  // Duplicates any '.' chars at the beginning of a line (dot-stuffing) and
78
78
  // ensures all newlines are CRLF.
79
- add_dot_stuffing_and_ensure_crlf_newlines (data) {
80
- if (!data.length) return data;
81
- if (!Buffer.isBuffer(data)) data = Buffer.from(data);
79
+ add_dot_stuffing_and_ensure_crlf_newlines(data) {
80
+ if (!data.length) return data
81
+ if (!Buffer.isBuffer(data)) data = Buffer.from(data)
82
82
 
83
83
  // Make a new buffer big enough to hold two bytes for every one input
84
84
  // byte. At most, we add one extra character per input byte, so this
85
85
  // is always big enough. We allocate it "unsafe" (i.e. no memset) for
86
86
  // speed because we're about to fill it with data, and the remainder of
87
87
  // the space we don't fill will be sliced away before we return this.
88
- const output = Buffer.allocUnsafe(data.length * 2);
89
- let output_pos = 0;
88
+ const output = Buffer.allocUnsafe(data.length * 2)
89
+ let output_pos = 0
90
90
 
91
- let input_pos = 0;
92
- let next_dot = data.indexOf(0x2E);
93
- let next_lf = data.indexOf(0x0A);
91
+ let input_pos = 0
92
+ let next_dot = data.indexOf(0x2e)
93
+ let next_lf = data.indexOf(0x0a)
94
94
  while (next_dot !== -1 || next_lf !== -1) {
95
- const run_end = (next_dot !== -1 && (next_lf === -1 || next_dot < next_lf))
96
- ? next_dot : next_lf;
95
+ const run_end = next_dot !== -1 && (next_lf === -1 || next_dot < next_lf) ? next_dot : next_lf
97
96
 
98
- // Copy up till whichever comes first, '.' or '\n' (but don't
97
+ // Copy up to whichever comes first, '.' or '\n' (but don't
99
98
  // copy the '.' or '\n' itself).
100
- data.copy(output, output_pos, input_pos, run_end);
101
- output_pos += run_end - input_pos;
99
+ data.copy(output, output_pos, input_pos, run_end)
100
+ output_pos += run_end - input_pos
102
101
 
103
- if (data[run_end] === 0x2E && (run_end === 0 || data[run_end - 1] === 0x0A)) {
102
+ if (data[run_end] === 0x2e && (run_end === 0 || data[run_end - 1] === 0x0a)) {
104
103
  // Replace /^\./ with '..'
105
- output[output_pos++] = 0x2E;
106
- }
107
- else if (data[run_end] === 0x0A && (run_end === 0 || data[run_end - 1] !== 0x0D)) {
104
+ output[output_pos++] = 0x2e
105
+ } else if (data[run_end] === 0x0a && (run_end === 0 || data[run_end - 1] !== 0x0d)) {
108
106
  // Replace /\r?\n/ with '\r\n'
109
- output[output_pos++] = 0x0D;
107
+ output[output_pos++] = 0x0d
110
108
  }
111
- output[output_pos++] = data[run_end];
109
+ output[output_pos++] = data[run_end]
112
110
 
113
- input_pos = run_end + 1;
111
+ input_pos = run_end + 1
114
112
 
115
113
  if (run_end === next_dot) {
116
- next_dot = data.indexOf(0x2E, input_pos);
117
- }
118
- else {
119
- next_lf = data.indexOf(0x0A, input_pos);
114
+ next_dot = data.indexOf(0x2e, input_pos)
115
+ } else {
116
+ next_lf = data.indexOf(0x0a, input_pos)
120
117
  }
121
118
  }
122
119
 
123
120
  if (input_pos < data.length) {
124
- data.copy(output, output_pos, input_pos);
125
- output_pos += data.length - input_pos;
121
+ data.copy(output, output_pos, input_pos)
122
+ output_pos += data.length - input_pos
126
123
  }
127
124
 
128
- return output.slice(0, output_pos);
125
+ return output.slice(0, output_pos)
129
126
  }
130
127
 
131
- add_data (line) {
132
- if (typeof line === 'string') { // This shouldn't ever happen.
133
- line = Buffer.from(line, this.encoding);
128
+ add_data(line) {
129
+ if (typeof line === 'string') {
130
+ // This shouldn't ever happen.
131
+ line = Buffer.from(line, this.encoding)
134
132
  }
135
133
  // is this the end of headers line?
136
- if (this.header_pos === 0 &&
137
- (line[0] === 0x0A || (line[0] === 0x0D && line[1] === 0x0A))) {
138
- this.header.parse(this.header_lines);
139
- this.header_pos = this.header_lines.length;
140
- this.found_hb_sep = true;
141
- if (this.parse_body) this.ensure_body();
142
- }
143
- else if (this.header_pos === 0) {
134
+ if (this.header_pos === 0 && (line[0] === 0x0a || (line[0] === 0x0d && line[1] === 0x0a))) {
135
+ this.header.parse(this.header_lines)
136
+ this.header_pos = this.header_lines.length
137
+ this.found_hb_sep = true
138
+ if (this.parse_body) this.ensure_body()
139
+ } else if (this.header_pos === 0) {
144
140
  // Build up headers
145
141
  if (this.header_lines.length < (this.cfg?.headers?.max_lines || 1000)) {
146
- if (line[0] === 0x2E) line = line.slice(1); // Strip leading '.'
147
- this.header_lines.push(line.toString(this.encoding).replace(/\r\n$/, '\n'));
142
+ if (line[0] === 0x2e) line = line.slice(1) // Strip leading '.'
143
+ this.header_lines.push(line.toString(this.encoding).replace(/\r\n$/, '\n'))
148
144
  }
149
- }
150
- else if (this.parse_body) {
151
- let new_line = line;
152
- if (new_line[0] === 0x2E) new_line = new_line.slice(1); // Strip leading "."
145
+ } else if (this.parse_body) {
146
+ let new_line = line
147
+ if (new_line[0] === 0x2e) new_line = new_line.slice(1) // Strip leading "."
153
148
 
154
- line = this.add_dot_stuffing_and_ensure_crlf_newlines(
155
- this.body.parse_more(this.remove_final_cr(new_line))
156
- );
149
+ line = this.add_dot_stuffing_and_ensure_crlf_newlines(this.body.parse_more(this.remove_final_cr(new_line)))
157
150
 
158
- if (!line.length) return; // buffering for banners
151
+ if (!line.length) return // buffering for banners
159
152
  }
160
153
 
161
- if (!this.discard_data) this.message_stream.add_line(line);
154
+ if (!this.discard_data) this.message_stream.add_line(line)
162
155
  }
163
156
 
164
- end_data (cb) {
157
+ end_data(cb) {
165
158
  if (!this.found_hb_sep && this.header_lines.length) {
166
159
  // Headers not parsed yet - must be a busted email
167
160
  // Strategy: Find the first line that doesn't look like a header.
168
161
  // Treat anything before that as headers, anything after as body.
169
- let header_pos = 0;
162
+ let header_pos = 0
170
163
  for (let i = 0; i < this.header_lines.length; i++) {
171
164
  // Anything that doesn't match a header or continuation
172
165
  if (!/^(?:([^\s:]*):\s*([\s\S]*)$|[ \t])/.test(this.header_lines[i])) {
173
- break;
166
+ break
174
167
  }
175
- header_pos = i;
168
+ header_pos = i
176
169
  }
177
- const body_lines = this.header_lines.splice(header_pos + 1);
178
- this.header.parse(this.header_lines);
179
- this.header_pos = header_pos;
170
+ const body_lines = this.header_lines.splice(header_pos + 1)
171
+ this.header.parse(this.header_lines)
172
+ this.header_pos = header_pos
180
173
  if (this.parse_body) {
181
- this.ensure_body();
174
+ this.ensure_body()
182
175
  for (const bodyLine of body_lines) {
183
- this.body.parse_more(bodyLine);
176
+ this.body.parse_more(bodyLine)
184
177
  }
185
178
  }
186
179
  }
187
180
  if (this.header_pos && this.parse_body) {
188
- const line = this.add_dot_stuffing_and_ensure_crlf_newlines(this.body.parse_end());
181
+ const line = this.add_dot_stuffing_and_ensure_crlf_newlines(this.body.parse_end())
189
182
  if (line.length) {
190
- this.body.force_end();
183
+ this.body.force_end()
191
184
 
192
- if (!this.discard_data) this.message_stream.add_line(line);
185
+ if (!this.discard_data) this.message_stream.add_line(line)
193
186
  }
194
187
  }
195
188
 
196
189
  if (this.discard_data) {
197
- cb();
198
- }
199
- else {
200
- this.message_stream.add_line_end(cb);
190
+ cb()
191
+ } else {
192
+ this.message_stream.add_line_end(cb)
201
193
  }
202
194
  }
203
195
 
204
- add_header (key, value) {
205
- this.header.add_end(key, value);
206
- if (this.header_pos > 0) this.reset_headers();
196
+ add_header(key, value) {
197
+ this.header.add_end(key, value)
198
+ if (this.header_pos > 0) this.reset_headers()
207
199
  }
208
200
 
209
- add_leading_header (key, value) {
210
- this.header.add(key, value);
211
- if (this.header_pos > 0) this.reset_headers();
201
+ add_leading_header(key, value) {
202
+ this.header.add(key, value)
203
+ if (this.header_pos > 0) this.reset_headers()
212
204
  }
213
205
 
214
- reset_headers () {
215
- const header_lines = this.header.lines();
216
- this.header_pos = header_lines.length;
206
+ reset_headers() {
207
+ const header_lines = this.header.lines()
208
+ this.header_pos = header_lines.length
217
209
  }
218
210
 
219
- remove_header (key) {
220
- this.header.remove(key);
221
- if (this.header_pos > 0) this.reset_headers();
211
+ remove_header(key) {
212
+ this.header.remove(key)
213
+ if (this.header_pos > 0) this.reset_headers()
222
214
  }
223
215
 
224
- attachment_hooks (start, data, end) {
225
- this.parse_body = true;
226
- this.attachment_start_hooks.push(start);
216
+ attachment_hooks(start, data, end) {
217
+ this.parse_body = true
218
+ this.attachment_start_hooks.push(start)
227
219
  }
228
220
 
229
- set_banner (text, html) {
221
+ set_banner(text, html) {
230
222
  // throw "transaction.set_banner is currently non-functional";
231
- this.parse_body = true;
223
+ this.parse_body = true
232
224
  if (!html) {
233
- html = text.replace(/\n/g, '<br/>\n');
225
+ html = text.replace(/\n/g, '<br/>\n')
234
226
  }
235
- this.banner = [text, html];
227
+ this.banner = [text, html]
236
228
  }
237
229
 
238
- add_body_filter (ct_match, filter) {
239
- this.parse_body = true;
240
- this.body_filters.push({ ct_match, filter });
230
+ add_body_filter(ct_match, filter) {
231
+ this.parse_body = true
232
+ this.body_filters.push({ ct_match, filter })
241
233
  }
242
234
 
243
- incr_mime_count (line) {
244
- this.mime_part_count++;
235
+ incr_mime_count(line) {
236
+ this.mime_part_count++
245
237
  }
246
238
  }
247
239
 
248
- exports.Transaction = Transaction;
240
+ exports.Transaction = Transaction
249
241
 
250
242
  exports.createTransaction = (uuid, cfg) => {
251
- return new Transaction(uuid, cfg);
243
+ return new Transaction(uuid, cfg)
252
244
  }