m06_task3.js 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. package/.idea/.name +1 -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/node_lab_6.iml +12 -0
  6. package/06_task2.html +73 -0
  7. package/06_task2.js +52 -0
  8. package/06_task3.js +3 -0
  9. package/06_task4.js +3 -0
  10. package/m06_task3.js +28 -0
  11. package/package/index.js +28 -0
  12. package/package/node_modules/.package-lock.json +31 -0
  13. package/package/node_modules/@types/node/LICENSE +21 -0
  14. package/package/node_modules/@types/node/README.md +16 -0
  15. package/package/node_modules/@types/node/assert/strict.d.ts +8 -0
  16. package/package/node_modules/@types/node/assert.d.ts +961 -0
  17. package/package/node_modules/@types/node/async_hooks.d.ts +501 -0
  18. package/package/node_modules/@types/node/buffer.d.ts +2258 -0
  19. package/package/node_modules/@types/node/child_process.d.ts +1369 -0
  20. package/package/node_modules/@types/node/cluster.d.ts +410 -0
  21. package/package/node_modules/@types/node/console.d.ts +412 -0
  22. package/package/node_modules/@types/node/constants.d.ts +18 -0
  23. package/package/node_modules/@types/node/crypto.d.ts +3964 -0
  24. package/package/node_modules/@types/node/dgram.d.ts +545 -0
  25. package/package/node_modules/@types/node/diagnostics_channel.d.ts +153 -0
  26. package/package/node_modules/@types/node/dns/promises.d.ts +370 -0
  27. package/package/node_modules/@types/node/dns.d.ts +659 -0
  28. package/package/node_modules/@types/node/dom-events.d.ts +126 -0
  29. package/package/node_modules/@types/node/domain.d.ts +170 -0
  30. package/package/node_modules/@types/node/events.d.ts +678 -0
  31. package/package/node_modules/@types/node/fs/promises.d.ts +1138 -0
  32. package/package/node_modules/@types/node/fs.d.ts +3872 -0
  33. package/package/node_modules/@types/node/globals.d.ts +300 -0
  34. package/package/node_modules/@types/node/globals.global.d.ts +1 -0
  35. package/package/node_modules/@types/node/http.d.ts +1614 -0
  36. package/package/node_modules/@types/node/http2.d.ts +2134 -0
  37. package/package/node_modules/@types/node/https.d.ts +541 -0
  38. package/package/node_modules/@types/node/index.d.ts +133 -0
  39. package/package/node_modules/@types/node/inspector.d.ts +2741 -0
  40. package/package/node_modules/@types/node/module.d.ts +114 -0
  41. package/package/node_modules/@types/node/net.d.ts +869 -0
  42. package/package/node_modules/@types/node/os.d.ts +466 -0
  43. package/package/node_modules/@types/node/package.json +232 -0
  44. package/package/node_modules/@types/node/path.d.ts +191 -0
  45. package/package/node_modules/@types/node/perf_hooks.d.ts +625 -0
  46. package/package/node_modules/@types/node/process.d.ts +1482 -0
  47. package/package/node_modules/@types/node/punycode.d.ts +117 -0
  48. package/package/node_modules/@types/node/querystring.d.ts +131 -0
  49. package/package/node_modules/@types/node/readline/promises.d.ts +143 -0
  50. package/package/node_modules/@types/node/readline.d.ts +653 -0
  51. package/package/node_modules/@types/node/repl.d.ts +424 -0
  52. package/package/node_modules/@types/node/stream/consumers.d.ts +12 -0
  53. package/package/node_modules/@types/node/stream/promises.d.ts +42 -0
  54. package/package/node_modules/@types/node/stream/web.d.ts +330 -0
  55. package/package/node_modules/@types/node/stream.d.ts +1340 -0
  56. package/package/node_modules/@types/node/string_decoder.d.ts +67 -0
  57. package/package/node_modules/@types/node/test.d.ts +314 -0
  58. package/package/node_modules/@types/node/timers/promises.d.ts +68 -0
  59. package/package/node_modules/@types/node/timers.d.ts +94 -0
  60. package/package/node_modules/@types/node/tls.d.ts +1028 -0
  61. package/package/node_modules/@types/node/trace_events.d.ts +171 -0
  62. package/package/node_modules/@types/node/ts4.8/assert/strict.d.ts +8 -0
  63. package/package/node_modules/@types/node/ts4.8/assert.d.ts +961 -0
  64. package/package/node_modules/@types/node/ts4.8/async_hooks.d.ts +501 -0
  65. package/package/node_modules/@types/node/ts4.8/buffer.d.ts +2259 -0
  66. package/package/node_modules/@types/node/ts4.8/child_process.d.ts +1369 -0
  67. package/package/node_modules/@types/node/ts4.8/cluster.d.ts +410 -0
  68. package/package/node_modules/@types/node/ts4.8/console.d.ts +412 -0
  69. package/package/node_modules/@types/node/ts4.8/constants.d.ts +18 -0
  70. package/package/node_modules/@types/node/ts4.8/crypto.d.ts +3964 -0
  71. package/package/node_modules/@types/node/ts4.8/dgram.d.ts +545 -0
  72. package/package/node_modules/@types/node/ts4.8/diagnostics_channel.d.ts +153 -0
  73. package/package/node_modules/@types/node/ts4.8/dns/promises.d.ts +370 -0
  74. package/package/node_modules/@types/node/ts4.8/dns.d.ts +659 -0
  75. package/package/node_modules/@types/node/ts4.8/dom-events.d.ts +126 -0
  76. package/package/node_modules/@types/node/ts4.8/domain.d.ts +170 -0
  77. package/package/node_modules/@types/node/ts4.8/events.d.ts +678 -0
  78. package/package/node_modules/@types/node/ts4.8/fs/promises.d.ts +1138 -0
  79. package/package/node_modules/@types/node/ts4.8/fs.d.ts +3872 -0
  80. package/package/node_modules/@types/node/ts4.8/globals.d.ts +294 -0
  81. package/package/node_modules/@types/node/ts4.8/globals.global.d.ts +1 -0
  82. package/package/node_modules/@types/node/ts4.8/http.d.ts +1614 -0
  83. package/package/node_modules/@types/node/ts4.8/http2.d.ts +2134 -0
  84. package/package/node_modules/@types/node/ts4.8/https.d.ts +541 -0
  85. package/package/node_modules/@types/node/ts4.8/index.d.ts +88 -0
  86. package/package/node_modules/@types/node/ts4.8/inspector.d.ts +2741 -0
  87. package/package/node_modules/@types/node/ts4.8/module.d.ts +114 -0
  88. package/package/node_modules/@types/node/ts4.8/net.d.ts +869 -0
  89. package/package/node_modules/@types/node/ts4.8/os.d.ts +466 -0
  90. package/package/node_modules/@types/node/ts4.8/path.d.ts +191 -0
  91. package/package/node_modules/@types/node/ts4.8/perf_hooks.d.ts +625 -0
  92. package/package/node_modules/@types/node/ts4.8/process.d.ts +1482 -0
  93. package/package/node_modules/@types/node/ts4.8/punycode.d.ts +117 -0
  94. package/package/node_modules/@types/node/ts4.8/querystring.d.ts +131 -0
  95. package/package/node_modules/@types/node/ts4.8/readline/promises.d.ts +143 -0
  96. package/package/node_modules/@types/node/ts4.8/readline.d.ts +653 -0
  97. package/package/node_modules/@types/node/ts4.8/repl.d.ts +424 -0
  98. package/package/node_modules/@types/node/ts4.8/stream/consumers.d.ts +12 -0
  99. package/package/node_modules/@types/node/ts4.8/stream/promises.d.ts +42 -0
  100. package/package/node_modules/@types/node/ts4.8/stream/web.d.ts +330 -0
  101. package/package/node_modules/@types/node/ts4.8/stream.d.ts +1340 -0
  102. package/package/node_modules/@types/node/ts4.8/string_decoder.d.ts +67 -0
  103. package/package/node_modules/@types/node/ts4.8/test.d.ts +314 -0
  104. package/package/node_modules/@types/node/ts4.8/timers/promises.d.ts +68 -0
  105. package/package/node_modules/@types/node/ts4.8/timers.d.ts +94 -0
  106. package/package/node_modules/@types/node/ts4.8/tls.d.ts +1028 -0
  107. package/package/node_modules/@types/node/ts4.8/trace_events.d.ts +171 -0
  108. package/package/node_modules/@types/node/ts4.8/tty.d.ts +206 -0
  109. package/package/node_modules/@types/node/ts4.8/url.d.ts +897 -0
  110. package/package/node_modules/@types/node/ts4.8/util.d.ts +1850 -0
  111. package/package/node_modules/@types/node/ts4.8/v8.d.ts +396 -0
  112. package/package/node_modules/@types/node/ts4.8/vm.d.ts +509 -0
  113. package/package/node_modules/@types/node/ts4.8/wasi.d.ts +158 -0
  114. package/package/node_modules/@types/node/ts4.8/worker_threads.d.ts +689 -0
  115. package/package/node_modules/@types/node/ts4.8/zlib.d.ts +517 -0
  116. package/package/node_modules/@types/node/tty.d.ts +206 -0
  117. package/package/node_modules/@types/node/url.d.ts +897 -0
  118. package/package/node_modules/@types/node/util.d.ts +1850 -0
  119. package/package/node_modules/@types/node/v8.d.ts +396 -0
  120. package/package/node_modules/@types/node/vm.d.ts +509 -0
  121. package/package/node_modules/@types/node/wasi.d.ts +158 -0
  122. package/package/node_modules/@types/node/worker_threads.d.ts +689 -0
  123. package/package/node_modules/@types/node/zlib.d.ts +517 -0
  124. package/package/node_modules/@types/nodemailer/LICENSE +21 -0
  125. package/package/node_modules/@types/nodemailer/README.md +16 -0
  126. package/package/node_modules/@types/nodemailer/index.d.ts +83 -0
  127. package/package/node_modules/@types/nodemailer/lib/addressparser/index.d.ts +31 -0
  128. package/package/node_modules/@types/nodemailer/lib/base64/index.d.ts +22 -0
  129. package/package/node_modules/@types/nodemailer/lib/dkim/index.d.ts +45 -0
  130. package/package/node_modules/@types/nodemailer/lib/dkim/message-parser.d.ts +75 -0
  131. package/package/node_modules/@types/nodemailer/lib/dkim/relaxed-body.d.ts +75 -0
  132. package/package/node_modules/@types/nodemailer/lib/dkim/sign.d.ts +11 -0
  133. package/package/node_modules/@types/nodemailer/lib/fetch/cookies.d.ts +54 -0
  134. package/package/node_modules/@types/nodemailer/lib/fetch/index.d.ts +38 -0
  135. package/package/node_modules/@types/nodemailer/lib/json-transport/index.d.ts +50 -0
  136. package/package/node_modules/@types/nodemailer/lib/mail-composer/index.d.ts +25 -0
  137. package/package/node_modules/@types/nodemailer/lib/mailer/index.d.ts +230 -0
  138. package/package/node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts +28 -0
  139. package/package/node_modules/@types/nodemailer/lib/mime-funcs/index.d.ts +87 -0
  140. package/package/node_modules/@types/nodemailer/lib/mime-funcs/mime-types.d.ts +2 -0
  141. package/package/node_modules/@types/nodemailer/lib/mime-node/index.d.ts +137 -0
  142. package/package/node_modules/@types/nodemailer/lib/mime-node/last-newline.d.ts +9 -0
  143. package/package/node_modules/@types/nodemailer/lib/qp/index.d.ts +23 -0
  144. package/package/node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts +53 -0
  145. package/package/node_modules/@types/nodemailer/lib/sendmail-transport/le-unix.d.ts +7 -0
  146. package/package/node_modules/@types/nodemailer/lib/sendmail-transport/le-windows.d.ts +7 -0
  147. package/package/node_modules/@types/nodemailer/lib/ses-transport/index.d.ts +136 -0
  148. package/package/node_modules/@types/nodemailer/lib/shared/index.d.ts +51 -0
  149. package/package/node_modules/@types/nodemailer/lib/smtp-connection/data-stream.d.ts +11 -0
  150. package/package/node_modules/@types/nodemailer/lib/smtp-connection/http-proxy-client.d.ts +11 -0
  151. package/package/node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts +254 -0
  152. package/package/node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts +90 -0
  153. package/package/node_modules/@types/nodemailer/lib/smtp-pool/pool-resource.d.ts +66 -0
  154. package/package/node_modules/@types/nodemailer/lib/smtp-transport/index.d.ts +115 -0
  155. package/package/node_modules/@types/nodemailer/lib/stream-transport/index.d.ts +56 -0
  156. package/package/node_modules/@types/nodemailer/lib/well-known/index.d.ts +6 -0
  157. package/package/node_modules/@types/nodemailer/lib/xoauth2/index.d.ts +110 -0
  158. package/package/node_modules/@types/nodemailer/package.json +37 -0
  159. package/package/node_modules/nodemailer/.gitattributes +6 -0
  160. package/package/node_modules/nodemailer/.prettierrc.js +8 -0
  161. package/package/node_modules/nodemailer/CHANGELOG.md +715 -0
  162. package/package/node_modules/nodemailer/CODE_OF_CONDUCT.md +76 -0
  163. package/package/node_modules/nodemailer/CONTRIBUTING.md +67 -0
  164. package/package/node_modules/nodemailer/LICENSE +16 -0
  165. package/package/node_modules/nodemailer/README.md +93 -0
  166. package/package/node_modules/nodemailer/SECURITY.txt +22 -0
  167. package/package/node_modules/nodemailer/lib/addressparser/index.js +313 -0
  168. package/package/node_modules/nodemailer/lib/base64/index.js +142 -0
  169. package/package/node_modules/nodemailer/lib/dkim/index.js +251 -0
  170. package/package/node_modules/nodemailer/lib/dkim/message-parser.js +155 -0
  171. package/package/node_modules/nodemailer/lib/dkim/relaxed-body.js +154 -0
  172. package/package/node_modules/nodemailer/lib/dkim/sign.js +117 -0
  173. package/package/node_modules/nodemailer/lib/fetch/cookies.js +281 -0
  174. package/package/node_modules/nodemailer/lib/fetch/index.js +269 -0
  175. package/package/node_modules/nodemailer/lib/json-transport/index.js +82 -0
  176. package/package/node_modules/nodemailer/lib/mail-composer/index.js +558 -0
  177. package/package/node_modules/nodemailer/lib/mailer/index.js +427 -0
  178. package/package/node_modules/nodemailer/lib/mailer/mail-message.js +315 -0
  179. package/package/node_modules/nodemailer/lib/mime-funcs/index.js +619 -0
  180. package/package/node_modules/nodemailer/lib/mime-funcs/mime-types.js +2102 -0
  181. package/package/node_modules/nodemailer/lib/mime-node/index.js +1290 -0
  182. package/package/node_modules/nodemailer/lib/mime-node/last-newline.js +33 -0
  183. package/package/node_modules/nodemailer/lib/mime-node/le-unix.js +43 -0
  184. package/package/node_modules/nodemailer/lib/mime-node/le-windows.js +52 -0
  185. package/package/node_modules/nodemailer/lib/nodemailer.js +143 -0
  186. package/package/node_modules/nodemailer/lib/qp/index.js +219 -0
  187. package/package/node_modules/nodemailer/lib/sendmail-transport/index.js +210 -0
  188. package/package/node_modules/nodemailer/lib/ses-transport/index.js +349 -0
  189. package/package/node_modules/nodemailer/lib/shared/index.js +639 -0
  190. package/package/node_modules/nodemailer/lib/smtp-connection/data-stream.js +108 -0
  191. package/package/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +143 -0
  192. package/package/node_modules/nodemailer/lib/smtp-connection/index.js +1786 -0
  193. package/package/node_modules/nodemailer/lib/smtp-pool/index.js +648 -0
  194. package/package/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +253 -0
  195. package/package/node_modules/nodemailer/lib/smtp-transport/index.js +416 -0
  196. package/package/node_modules/nodemailer/lib/stream-transport/index.js +135 -0
  197. package/package/node_modules/nodemailer/lib/well-known/index.js +47 -0
  198. package/package/node_modules/nodemailer/lib/well-known/services.json +286 -0
  199. package/package/node_modules/nodemailer/lib/xoauth2/index.js +376 -0
  200. package/package/node_modules/nodemailer/package.json +46 -0
  201. package/package/node_modules/nodemailer/postinstall.js +101 -0
  202. package/package/package-lock.json +60 -0
  203. package/package/package.json +6 -0
  204. package/package.json +19 -0
@@ -0,0 +1,253 @@
1
+ 'use strict';
2
+
3
+ const SMTPConnection = require('../smtp-connection');
4
+ const assign = require('../shared').assign;
5
+ const XOAuth2 = require('../xoauth2');
6
+ const EventEmitter = require('events');
7
+
8
+ /**
9
+ * Creates an element for the pool
10
+ *
11
+ * @constructor
12
+ * @param {Object} options SMTPPool instance
13
+ */
14
+ class PoolResource extends EventEmitter {
15
+ constructor(pool) {
16
+ super();
17
+
18
+ this.pool = pool;
19
+ this.options = pool.options;
20
+ this.logger = this.pool.logger;
21
+
22
+ if (this.options.auth) {
23
+ switch ((this.options.auth.type || '').toString().toUpperCase()) {
24
+ case 'OAUTH2': {
25
+ let oauth2 = new XOAuth2(this.options.auth, this.logger);
26
+ oauth2.provisionCallback = (this.pool.mailer && this.pool.mailer.get('oauth2_provision_cb')) || oauth2.provisionCallback;
27
+ this.auth = {
28
+ type: 'OAUTH2',
29
+ user: this.options.auth.user,
30
+ oauth2,
31
+ method: 'XOAUTH2'
32
+ };
33
+ oauth2.on('token', token => this.pool.mailer.emit('token', token));
34
+ oauth2.on('error', err => this.emit('error', err));
35
+ break;
36
+ }
37
+ default:
38
+ if (!this.options.auth.user && !this.options.auth.pass) {
39
+ break;
40
+ }
41
+ this.auth = {
42
+ type: (this.options.auth.type || '').toString().toUpperCase() || 'LOGIN',
43
+ user: this.options.auth.user,
44
+ credentials: {
45
+ user: this.options.auth.user || '',
46
+ pass: this.options.auth.pass,
47
+ options: this.options.auth.options
48
+ },
49
+ method: (this.options.auth.method || '').trim().toUpperCase() || this.options.authMethod || false
50
+ };
51
+ }
52
+ }
53
+
54
+ this._connection = false;
55
+ this._connected = false;
56
+
57
+ this.messages = 0;
58
+ this.available = true;
59
+ }
60
+
61
+ /**
62
+ * Initiates a connection to the SMTP server
63
+ *
64
+ * @param {Function} callback Callback function to run once the connection is established or failed
65
+ */
66
+ connect(callback) {
67
+ this.pool.getSocket(this.options, (err, socketOptions) => {
68
+ if (err) {
69
+ return callback(err);
70
+ }
71
+
72
+ let returned = false;
73
+ let options = this.options;
74
+ if (socketOptions && socketOptions.connection) {
75
+ this.logger.info(
76
+ {
77
+ tnx: 'proxy',
78
+ remoteAddress: socketOptions.connection.remoteAddress,
79
+ remotePort: socketOptions.connection.remotePort,
80
+ destHost: options.host || '',
81
+ destPort: options.port || '',
82
+ action: 'connected'
83
+ },
84
+ 'Using proxied socket from %s:%s to %s:%s',
85
+ socketOptions.connection.remoteAddress,
86
+ socketOptions.connection.remotePort,
87
+ options.host || '',
88
+ options.port || ''
89
+ );
90
+
91
+ options = assign(false, options);
92
+ Object.keys(socketOptions).forEach(key => {
93
+ options[key] = socketOptions[key];
94
+ });
95
+ }
96
+
97
+ this.connection = new SMTPConnection(options);
98
+
99
+ this.connection.once('error', err => {
100
+ this.emit('error', err);
101
+ if (returned) {
102
+ return;
103
+ }
104
+ returned = true;
105
+ return callback(err);
106
+ });
107
+
108
+ this.connection.once('end', () => {
109
+ this.close();
110
+ if (returned) {
111
+ return;
112
+ }
113
+ returned = true;
114
+
115
+ let timer = setTimeout(() => {
116
+ if (returned) {
117
+ return;
118
+ }
119
+ // still have not returned, this means we have an unexpected connection close
120
+ let err = new Error('Unexpected socket close');
121
+ if (this.connection && this.connection._socket && this.connection._socket.upgrading) {
122
+ // starttls connection errors
123
+ err.code = 'ETLS';
124
+ }
125
+ callback(err);
126
+ }, 1000);
127
+
128
+ try {
129
+ timer.unref();
130
+ } catch (E) {
131
+ // Ignore. Happens on envs with non-node timer implementation
132
+ }
133
+ });
134
+
135
+ this.connection.connect(() => {
136
+ if (returned) {
137
+ return;
138
+ }
139
+
140
+ if (this.auth && (this.connection.allowsAuth || options.forceAuth)) {
141
+ this.connection.login(this.auth, err => {
142
+ if (returned) {
143
+ return;
144
+ }
145
+ returned = true;
146
+
147
+ if (err) {
148
+ this.connection.close();
149
+ this.emit('error', err);
150
+ return callback(err);
151
+ }
152
+
153
+ this._connected = true;
154
+ callback(null, true);
155
+ });
156
+ } else {
157
+ returned = true;
158
+ this._connected = true;
159
+ return callback(null, true);
160
+ }
161
+ });
162
+ });
163
+ }
164
+
165
+ /**
166
+ * Sends an e-mail to be sent using the selected settings
167
+ *
168
+ * @param {Object} mail Mail object
169
+ * @param {Function} callback Callback function
170
+ */
171
+ send(mail, callback) {
172
+ if (!this._connected) {
173
+ return this.connect(err => {
174
+ if (err) {
175
+ return callback(err);
176
+ }
177
+ return this.send(mail, callback);
178
+ });
179
+ }
180
+
181
+ let envelope = mail.message.getEnvelope();
182
+ let messageId = mail.message.messageId();
183
+
184
+ let recipients = [].concat(envelope.to || []);
185
+ if (recipients.length > 3) {
186
+ recipients.push('...and ' + recipients.splice(2).length + ' more');
187
+ }
188
+ this.logger.info(
189
+ {
190
+ tnx: 'send',
191
+ messageId,
192
+ cid: this.id
193
+ },
194
+ 'Sending message %s using #%s to <%s>',
195
+ messageId,
196
+ this.id,
197
+ recipients.join(', ')
198
+ );
199
+
200
+ if (mail.data.dsn) {
201
+ envelope.dsn = mail.data.dsn;
202
+ }
203
+
204
+ this.connection.send(envelope, mail.message.createReadStream(), (err, info) => {
205
+ this.messages++;
206
+
207
+ if (err) {
208
+ this.connection.close();
209
+ this.emit('error', err);
210
+ return callback(err);
211
+ }
212
+
213
+ info.envelope = {
214
+ from: envelope.from,
215
+ to: envelope.to
216
+ };
217
+ info.messageId = messageId;
218
+
219
+ setImmediate(() => {
220
+ let err;
221
+ if (this.messages >= this.options.maxMessages) {
222
+ err = new Error('Resource exhausted');
223
+ err.code = 'EMAXLIMIT';
224
+ this.connection.close();
225
+ this.emit('error', err);
226
+ } else {
227
+ this.pool._checkRateLimit(() => {
228
+ this.available = true;
229
+ this.emit('available');
230
+ });
231
+ }
232
+ });
233
+
234
+ callback(null, info);
235
+ });
236
+ }
237
+
238
+ /**
239
+ * Closes the connection
240
+ */
241
+ close() {
242
+ this._connected = false;
243
+ if (this.auth && this.auth.oauth2) {
244
+ this.auth.oauth2.removeAllListeners();
245
+ }
246
+ if (this.connection) {
247
+ this.connection.close();
248
+ }
249
+ this.emit('close');
250
+ }
251
+ }
252
+
253
+ module.exports = PoolResource;
@@ -0,0 +1,416 @@
1
+ 'use strict';
2
+
3
+ const EventEmitter = require('events');
4
+ const SMTPConnection = require('../smtp-connection');
5
+ const wellKnown = require('../well-known');
6
+ const shared = require('../shared');
7
+ const XOAuth2 = require('../xoauth2');
8
+ const packageData = require('../../package.json');
9
+
10
+ /**
11
+ * Creates a SMTP transport object for Nodemailer
12
+ *
13
+ * @constructor
14
+ * @param {Object} options Connection options
15
+ */
16
+ class SMTPTransport extends EventEmitter {
17
+ constructor(options) {
18
+ super();
19
+
20
+ options = options || {};
21
+
22
+ if (typeof options === 'string') {
23
+ options = {
24
+ url: options
25
+ };
26
+ }
27
+
28
+ let urlData;
29
+ let service = options.service;
30
+
31
+ if (typeof options.getSocket === 'function') {
32
+ this.getSocket = options.getSocket;
33
+ }
34
+
35
+ if (options.url) {
36
+ urlData = shared.parseConnectionUrl(options.url);
37
+ service = service || urlData.service;
38
+ }
39
+
40
+ this.options = shared.assign(
41
+ false, // create new object
42
+ options, // regular options
43
+ urlData, // url options
44
+ service && wellKnown(service) // wellknown options
45
+ );
46
+
47
+ this.logger = shared.getLogger(this.options, {
48
+ component: this.options.component || 'smtp-transport'
49
+ });
50
+
51
+ // temporary object
52
+ let connection = new SMTPConnection(this.options);
53
+
54
+ this.name = 'SMTP';
55
+ this.version = packageData.version + '[client:' + connection.version + ']';
56
+
57
+ if (this.options.auth) {
58
+ this.auth = this.getAuth({});
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Placeholder function for creating proxy sockets. This method immediatelly returns
64
+ * without a socket
65
+ *
66
+ * @param {Object} options Connection options
67
+ * @param {Function} callback Callback function to run with the socket keys
68
+ */
69
+ getSocket(options, callback) {
70
+ // return immediatelly
71
+ return setImmediate(() => callback(null, false));
72
+ }
73
+
74
+ getAuth(authOpts) {
75
+ if (!authOpts) {
76
+ return this.auth;
77
+ }
78
+
79
+ let hasAuth = false;
80
+ let authData = {};
81
+
82
+ if (this.options.auth && typeof this.options.auth === 'object') {
83
+ Object.keys(this.options.auth).forEach(key => {
84
+ hasAuth = true;
85
+ authData[key] = this.options.auth[key];
86
+ });
87
+ }
88
+
89
+ if (authOpts && typeof authOpts === 'object') {
90
+ Object.keys(authOpts).forEach(key => {
91
+ hasAuth = true;
92
+ authData[key] = authOpts[key];
93
+ });
94
+ }
95
+
96
+ if (!hasAuth) {
97
+ return false;
98
+ }
99
+
100
+ switch ((authData.type || '').toString().toUpperCase()) {
101
+ case 'OAUTH2': {
102
+ if (!authData.service && !authData.user) {
103
+ return false;
104
+ }
105
+ let oauth2 = new XOAuth2(authData, this.logger);
106
+ oauth2.provisionCallback = (this.mailer && this.mailer.get('oauth2_provision_cb')) || oauth2.provisionCallback;
107
+ oauth2.on('token', token => this.mailer.emit('token', token));
108
+ oauth2.on('error', err => this.emit('error', err));
109
+ return {
110
+ type: 'OAUTH2',
111
+ user: authData.user,
112
+ oauth2,
113
+ method: 'XOAUTH2'
114
+ };
115
+ }
116
+ default:
117
+ return {
118
+ type: (authData.type || '').toString().toUpperCase() || 'LOGIN',
119
+ user: authData.user,
120
+ credentials: {
121
+ user: authData.user || '',
122
+ pass: authData.pass,
123
+ options: authData.options
124
+ },
125
+ method: (authData.method || '').trim().toUpperCase() || this.options.authMethod || false
126
+ };
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Sends an e-mail using the selected settings
132
+ *
133
+ * @param {Object} mail Mail object
134
+ * @param {Function} callback Callback function
135
+ */
136
+ send(mail, callback) {
137
+ this.getSocket(this.options, (err, socketOptions) => {
138
+ if (err) {
139
+ return callback(err);
140
+ }
141
+
142
+ let returned = false;
143
+ let options = this.options;
144
+ if (socketOptions && socketOptions.connection) {
145
+ this.logger.info(
146
+ {
147
+ tnx: 'proxy',
148
+ remoteAddress: socketOptions.connection.remoteAddress,
149
+ remotePort: socketOptions.connection.remotePort,
150
+ destHost: options.host || '',
151
+ destPort: options.port || '',
152
+ action: 'connected'
153
+ },
154
+ 'Using proxied socket from %s:%s to %s:%s',
155
+ socketOptions.connection.remoteAddress,
156
+ socketOptions.connection.remotePort,
157
+ options.host || '',
158
+ options.port || ''
159
+ );
160
+
161
+ // only copy options if we need to modify it
162
+ options = shared.assign(false, options);
163
+ Object.keys(socketOptions).forEach(key => {
164
+ options[key] = socketOptions[key];
165
+ });
166
+ }
167
+
168
+ let connection = new SMTPConnection(options);
169
+
170
+ connection.once('error', err => {
171
+ if (returned) {
172
+ return;
173
+ }
174
+ returned = true;
175
+ connection.close();
176
+ return callback(err);
177
+ });
178
+
179
+ connection.once('end', () => {
180
+ if (returned) {
181
+ return;
182
+ }
183
+
184
+ let timer = setTimeout(() => {
185
+ if (returned) {
186
+ return;
187
+ }
188
+ returned = true;
189
+ // still have not returned, this means we have an unexpected connection close
190
+ let err = new Error('Unexpected socket close');
191
+ if (connection && connection._socket && connection._socket.upgrading) {
192
+ // starttls connection errors
193
+ err.code = 'ETLS';
194
+ }
195
+ callback(err);
196
+ }, 1000);
197
+
198
+ try {
199
+ timer.unref();
200
+ } catch (E) {
201
+ // Ignore. Happens on envs with non-node timer implementation
202
+ }
203
+ });
204
+
205
+ let sendMessage = () => {
206
+ let envelope = mail.message.getEnvelope();
207
+ let messageId = mail.message.messageId();
208
+
209
+ let recipients = [].concat(envelope.to || []);
210
+ if (recipients.length > 3) {
211
+ recipients.push('...and ' + recipients.splice(2).length + ' more');
212
+ }
213
+
214
+ if (mail.data.dsn) {
215
+ envelope.dsn = mail.data.dsn;
216
+ }
217
+
218
+ this.logger.info(
219
+ {
220
+ tnx: 'send',
221
+ messageId
222
+ },
223
+ 'Sending message %s to <%s>',
224
+ messageId,
225
+ recipients.join(', ')
226
+ );
227
+
228
+ connection.send(envelope, mail.message.createReadStream(), (err, info) => {
229
+ returned = true;
230
+ connection.close();
231
+ if (err) {
232
+ this.logger.error(
233
+ {
234
+ err,
235
+ tnx: 'send'
236
+ },
237
+ 'Send error for %s: %s',
238
+ messageId,
239
+ err.message
240
+ );
241
+ return callback(err);
242
+ }
243
+ info.envelope = {
244
+ from: envelope.from,
245
+ to: envelope.to
246
+ };
247
+ info.messageId = messageId;
248
+ try {
249
+ return callback(null, info);
250
+ } catch (E) {
251
+ this.logger.error(
252
+ {
253
+ err: E,
254
+ tnx: 'callback'
255
+ },
256
+ 'Callback error for %s: %s',
257
+ messageId,
258
+ E.message
259
+ );
260
+ }
261
+ });
262
+ };
263
+
264
+ connection.connect(() => {
265
+ if (returned) {
266
+ return;
267
+ }
268
+
269
+ let auth = this.getAuth(mail.data.auth);
270
+
271
+ if (auth && (connection.allowsAuth || options.forceAuth)) {
272
+ connection.login(auth, err => {
273
+ if (auth && auth !== this.auth && auth.oauth2) {
274
+ auth.oauth2.removeAllListeners();
275
+ }
276
+ if (returned) {
277
+ return;
278
+ }
279
+
280
+ if (err) {
281
+ returned = true;
282
+ connection.close();
283
+ return callback(err);
284
+ }
285
+
286
+ sendMessage();
287
+ });
288
+ } else {
289
+ sendMessage();
290
+ }
291
+ });
292
+ });
293
+ }
294
+
295
+ /**
296
+ * Verifies SMTP configuration
297
+ *
298
+ * @param {Function} callback Callback function
299
+ */
300
+ verify(callback) {
301
+ let promise;
302
+
303
+ if (!callback) {
304
+ promise = new Promise((resolve, reject) => {
305
+ callback = shared.callbackPromise(resolve, reject);
306
+ });
307
+ }
308
+
309
+ this.getSocket(this.options, (err, socketOptions) => {
310
+ if (err) {
311
+ return callback(err);
312
+ }
313
+
314
+ let options = this.options;
315
+ if (socketOptions && socketOptions.connection) {
316
+ this.logger.info(
317
+ {
318
+ tnx: 'proxy',
319
+ remoteAddress: socketOptions.connection.remoteAddress,
320
+ remotePort: socketOptions.connection.remotePort,
321
+ destHost: options.host || '',
322
+ destPort: options.port || '',
323
+ action: 'connected'
324
+ },
325
+ 'Using proxied socket from %s:%s to %s:%s',
326
+ socketOptions.connection.remoteAddress,
327
+ socketOptions.connection.remotePort,
328
+ options.host || '',
329
+ options.port || ''
330
+ );
331
+
332
+ options = shared.assign(false, options);
333
+ Object.keys(socketOptions).forEach(key => {
334
+ options[key] = socketOptions[key];
335
+ });
336
+ }
337
+
338
+ let connection = new SMTPConnection(options);
339
+ let returned = false;
340
+
341
+ connection.once('error', err => {
342
+ if (returned) {
343
+ return;
344
+ }
345
+ returned = true;
346
+ connection.close();
347
+ return callback(err);
348
+ });
349
+
350
+ connection.once('end', () => {
351
+ if (returned) {
352
+ return;
353
+ }
354
+ returned = true;
355
+ return callback(new Error('Connection closed'));
356
+ });
357
+
358
+ let finalize = () => {
359
+ if (returned) {
360
+ return;
361
+ }
362
+ returned = true;
363
+ connection.quit();
364
+ return callback(null, true);
365
+ };
366
+
367
+ connection.connect(() => {
368
+ if (returned) {
369
+ return;
370
+ }
371
+
372
+ let authData = this.getAuth({});
373
+
374
+ if (authData && (connection.allowsAuth || options.forceAuth)) {
375
+ connection.login(authData, err => {
376
+ if (returned) {
377
+ return;
378
+ }
379
+
380
+ if (err) {
381
+ returned = true;
382
+ connection.close();
383
+ return callback(err);
384
+ }
385
+
386
+ finalize();
387
+ });
388
+ } else if (!authData && connection.allowsAuth && options.forceAuth) {
389
+ let err = new Error('Authentication info was not provided');
390
+ err.code = 'NoAuth';
391
+
392
+ returned = true;
393
+ connection.close();
394
+ return callback(err);
395
+ } else {
396
+ finalize();
397
+ }
398
+ });
399
+ });
400
+
401
+ return promise;
402
+ }
403
+
404
+ /**
405
+ * Releases resources
406
+ */
407
+ close() {
408
+ if (this.auth && this.auth.oauth2) {
409
+ this.auth.oauth2.removeAllListeners();
410
+ }
411
+ this.emit('close');
412
+ }
413
+ }
414
+
415
+ // expose to the world
416
+ module.exports = SMTPTransport;