@stacksjs/email 0.66.0 → 0.68.0
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/dist/config.d.ts +3 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +0 -3
- package/dist/template.d.ts +6 -5
- package/dist/types.d.ts +35 -31
- package/package.json +7 -9
- package/dist/drivers/index.d.ts +0 -1
- package/dist/drivers/mailgun.d.ts +0 -0
- package/dist/drivers/nodemailer.d.ts +0 -0
- package/dist/drivers/ses.d.ts +0 -0
- package/dist/email.d.ts +0 -0
- package/dist/index.js.map +0 -9
- package/dist/send.d.ts +0 -0
- package/dist/server/converter.d.ts +0 -0
- package/dist/server/inbound.d.ts +0 -0
- package/dist/server/outbound.d.ts +0 -0
- package/dist/utils/config.d.ts +0 -3
- package/src/drivers/index.ts +0 -3
- package/src/drivers/mailgun.ts +0 -21
- package/src/drivers/nodemailer.ts +0 -23
- package/src/drivers/ses.ts +0 -23
- package/src/email.ts +0 -80
- package/src/index.ts +0 -3
- package/src/send.ts +0 -38
- package/src/server/converter.ts +0 -302
- package/src/server/inbound.ts +0 -404
- package/src/server/outbound.ts +0 -296
- package/src/template.ts +0 -20
- package/src/types.ts +0 -39
- package/src/utils/config.ts +0 -5
package/src/server/converter.ts
DELETED
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
// const AWS = require('aws-sdk')
|
|
2
|
-
// const mime = require('mime')
|
|
3
|
-
// const parser = require('mailparser').simpleParser
|
|
4
|
-
//
|
|
5
|
-
// // Initialize S3.
|
|
6
|
-
// const s3 = new AWS.S3({
|
|
7
|
-
// apiVersion: '2006-03-01',
|
|
8
|
-
// })
|
|
9
|
-
//
|
|
10
|
-
// // This lambda will read RAW emails and convert them in easy to read formats
|
|
11
|
-
// // like: HTML and text
|
|
12
|
-
// exports.handler = (event: any) => {
|
|
13
|
-
// // 1. We need to process the path received by S3 since AWS dose escape the
|
|
14
|
-
// // string in a special way. They escape the string in a HTML style
|
|
15
|
-
// // but for whatever reason they convert spaces in to +ses.
|
|
16
|
-
// const s3_key = event.Records[0].s3.object.key
|
|
17
|
-
//
|
|
18
|
-
// // 2. So first we convert the + in to spaces
|
|
19
|
-
// const plus_to_space = s3_key.replace(/\+/g, ' ')
|
|
20
|
-
//
|
|
21
|
-
// // 3. And then we unescape the string, other wise we lose real + characters
|
|
22
|
-
// const unescaped_key = decodeURIComponent(plus_to_space)
|
|
23
|
-
//
|
|
24
|
-
// // 4. This JS object will contain all the data within the chain
|
|
25
|
-
// const container = {
|
|
26
|
-
// bucket: event.Records[0].s3.bucket.name,
|
|
27
|
-
// key: unescaped_key,
|
|
28
|
-
// parsed: {
|
|
29
|
-
// html: '',
|
|
30
|
-
// text: '',
|
|
31
|
-
// attachments: [],
|
|
32
|
-
// },
|
|
33
|
-
// }
|
|
34
|
-
//
|
|
35
|
-
// // -> Start the chain.
|
|
36
|
-
// load_the_email(container)
|
|
37
|
-
// .then((container) => {
|
|
38
|
-
// return remove_extension(container)
|
|
39
|
-
// }).then((container) => {
|
|
40
|
-
// return parse_the_email(container)
|
|
41
|
-
// }).then((container) => {
|
|
42
|
-
// return save_text(container)
|
|
43
|
-
// }).then((container) => {
|
|
44
|
-
// return save_html(container)
|
|
45
|
-
// }).then((container) => {
|
|
46
|
-
// return save_attachments(container)
|
|
47
|
-
// }).then((container) => {
|
|
48
|
-
// return true
|
|
49
|
-
// }).catch((error) => {
|
|
50
|
-
// console.error(error)
|
|
51
|
-
//
|
|
52
|
-
// return false
|
|
53
|
-
// })
|
|
54
|
-
// }
|
|
55
|
-
//
|
|
56
|
-
// // Load the email that triggered the function from S3
|
|
57
|
-
// function load_the_email(container: any) {
|
|
58
|
-
// return new Promise((resolve, reject) => {
|
|
59
|
-
// console.info('load_the_email')
|
|
60
|
-
//
|
|
61
|
-
// // 1. Set the query.
|
|
62
|
-
// const params = {
|
|
63
|
-
// Bucket: container.bucket,
|
|
64
|
-
// Key: container.key,
|
|
65
|
-
// }
|
|
66
|
-
//
|
|
67
|
-
// // -> Execute the query
|
|
68
|
-
// s3.getObject(params, (error: any, data: any) => {
|
|
69
|
-
// // 1. Check for internal errors
|
|
70
|
-
// if (error)
|
|
71
|
-
// return reject(error)
|
|
72
|
-
//
|
|
73
|
-
// // 2. Save the email for the next promise
|
|
74
|
-
// container.raw_email = data.Body
|
|
75
|
-
//
|
|
76
|
-
// // -> Move to the next chain.
|
|
77
|
-
// return resolve(container)
|
|
78
|
-
// })
|
|
79
|
-
// })
|
|
80
|
-
// }
|
|
81
|
-
//
|
|
82
|
-
// // Since the raw email is saved with an extension we need to remove it
|
|
83
|
-
// // before we can save other converted versions.
|
|
84
|
-
// function remove_extension(container: any) {
|
|
85
|
-
// return new Promise((resolve, reject) => {
|
|
86
|
-
// console.info('remove_extension')
|
|
87
|
-
//
|
|
88
|
-
// // 1. Split the string.
|
|
89
|
-
// const tmp = container.key.split('.')
|
|
90
|
-
//
|
|
91
|
-
// // 2. Remove the last element from the array which is `eml`.
|
|
92
|
-
// tmp.pop()
|
|
93
|
-
//
|
|
94
|
-
// // 2. Join the array back to how it was, minus the extension.
|
|
95
|
-
// // We need to do this, since we don't know how many dots
|
|
96
|
-
// // were in the email title for example.
|
|
97
|
-
// container.key = tmp.join('.')
|
|
98
|
-
//
|
|
99
|
-
// // -> Move to the next chain.
|
|
100
|
-
// return resolve(container)
|
|
101
|
-
// })
|
|
102
|
-
// }
|
|
103
|
-
//
|
|
104
|
-
// // Convert the raw email in to HTML and Text, and extract also the attachments
|
|
105
|
-
// function parse_the_email(container: any) {
|
|
106
|
-
// return new Promise((resolve, reject) => {
|
|
107
|
-
// // 1. Parse the email and extract all the necessary
|
|
108
|
-
// parser(container.raw_email, (error: any, parsed: any) => {
|
|
109
|
-
// // 1. Check for internal errors
|
|
110
|
-
// if (error)
|
|
111
|
-
// return reject(error)
|
|
112
|
-
//
|
|
113
|
-
// // 2. Save the parsed email for the next promise.
|
|
114
|
-
// container.parsed.html = parsed.html
|
|
115
|
-
// container.parsed.text = parsed.text
|
|
116
|
-
// container.parsed.attachments = parsed.attachments
|
|
117
|
-
//
|
|
118
|
-
// // -> Move to the next chain.
|
|
119
|
-
// return resolve(container)
|
|
120
|
-
// })
|
|
121
|
-
// })
|
|
122
|
-
// }
|
|
123
|
-
//
|
|
124
|
-
// // After the conversion we save the Text version to S3.
|
|
125
|
-
// function save_text(container: any) {
|
|
126
|
-
// return new Promise((resolve, reject) => {
|
|
127
|
-
// console.info('save_text')
|
|
128
|
-
//
|
|
129
|
-
// // 1. Set the query
|
|
130
|
-
// const params = {
|
|
131
|
-
// Bucket: container.bucket,
|
|
132
|
-
// Key: `${container.key}.txt`,
|
|
133
|
-
// Body: container.parsed.text,
|
|
134
|
-
// }
|
|
135
|
-
//
|
|
136
|
-
// // -> Execute the query.
|
|
137
|
-
// s3.putObject(params, (error: any, data: any) => {
|
|
138
|
-
// // 1. Check for internal errors.
|
|
139
|
-
// if (error)
|
|
140
|
-
// return reject(error)
|
|
141
|
-
//
|
|
142
|
-
// // -> Move to the next chain.
|
|
143
|
-
// return resolve(container)
|
|
144
|
-
// })
|
|
145
|
-
// })
|
|
146
|
-
// }
|
|
147
|
-
//
|
|
148
|
-
// // Then if we have a HTML version we try to save that.
|
|
149
|
-
// function save_html(container: any) {
|
|
150
|
-
// return new Promise((resolve, reject) => {
|
|
151
|
-
// // <>> When the body of an email have only one version, meaning it
|
|
152
|
-
// // does have only the pure text version and no HTML.
|
|
153
|
-
// // Nodemailer won't generate the HTML for you, it just grabs
|
|
154
|
-
// // what is in the Email body.
|
|
155
|
-
// // So, this value will be false, when there is no HTML content in
|
|
156
|
-
// // the email, and thus we skip this step.
|
|
157
|
-
// if (!container.parsed.html) {
|
|
158
|
-
// console.info('save_html - skipped')
|
|
159
|
-
//
|
|
160
|
-
// // -> Move to the next chain.
|
|
161
|
-
// return resolve(container)
|
|
162
|
-
// }
|
|
163
|
-
//
|
|
164
|
-
// console.info('save_html')
|
|
165
|
-
//
|
|
166
|
-
// // 1. Set the query.
|
|
167
|
-
// const params = {
|
|
168
|
-
// Bucket: container.bucket,
|
|
169
|
-
// Key: `${container.key}.html`,
|
|
170
|
-
// Body: container.parsed.html,
|
|
171
|
-
// }
|
|
172
|
-
//
|
|
173
|
-
// // -> Execute the query.
|
|
174
|
-
// s3.putObject(params, (error: any, data: any) => {
|
|
175
|
-
// // 1. Check for internal errors.
|
|
176
|
-
// if (error)
|
|
177
|
-
// return reject(error)
|
|
178
|
-
//
|
|
179
|
-
// // -> Move to the next chain.
|
|
180
|
-
// return resolve(container)
|
|
181
|
-
// })
|
|
182
|
-
// })
|
|
183
|
-
// }
|
|
184
|
-
//
|
|
185
|
-
// // Last thing to do is to save the attachments if there are any. If the
|
|
186
|
-
// // array is empty the loop will skip itself.
|
|
187
|
-
// function save_attachments(container: any) {
|
|
188
|
-
// return new Promise((resolve, reject) => {
|
|
189
|
-
// console.info('save_attachments')
|
|
190
|
-
//
|
|
191
|
-
// // Start the loop which save all the attachments.
|
|
192
|
-
// loop(1, (error: any) => {
|
|
193
|
-
// // <<> Check if there was an error.
|
|
194
|
-
// if (error) {
|
|
195
|
-
// // -> Stop everything and surface the error.
|
|
196
|
-
// return reject(container)
|
|
197
|
-
// }
|
|
198
|
-
//
|
|
199
|
-
// // -> Move to the next chain.
|
|
200
|
-
// return resolve(container)
|
|
201
|
-
// })
|
|
202
|
-
//
|
|
203
|
-
// // This loop will upload all the individual attachments found in a email
|
|
204
|
-
// function loop(count: any, callback: any) {
|
|
205
|
-
// // 1. Pop the last element in the array if any.
|
|
206
|
-
// const file = container.parsed.attachments.pop()
|
|
207
|
-
//
|
|
208
|
-
// // 2. If there is nothing left then we stop the loop.
|
|
209
|
-
// if (!file)
|
|
210
|
-
// return callback()
|
|
211
|
-
//
|
|
212
|
-
// // 3. Get the file name which also contain the file extension.
|
|
213
|
-
// let file_name = file.filename
|
|
214
|
-
//
|
|
215
|
-
// // 4. An email attachment is not required to have a name, this
|
|
216
|
-
// // mean we need to check if we have a file name and, if not
|
|
217
|
-
// // we create a general name, so all attachments can be saved
|
|
218
|
-
// // and accounted for.
|
|
219
|
-
// if (!file_name) {
|
|
220
|
-
// // 1. Set the generic name with the count name so we give
|
|
221
|
-
// // unique names to each attachment.
|
|
222
|
-
// file_name = `Mail Attachment ${count}`
|
|
223
|
-
//
|
|
224
|
-
// // 2. We only count the times we had to set a generic name.
|
|
225
|
-
// count++
|
|
226
|
-
// }
|
|
227
|
-
//
|
|
228
|
-
// // 5. Split the string to and get the last element of the array
|
|
229
|
-
// // which should be the file extension.
|
|
230
|
-
// const extension = file_name.split('.').pop()
|
|
231
|
-
//
|
|
232
|
-
// // 6. Then we check if the last element is an extension.
|
|
233
|
-
// const is_extension = mime.getType(extension)
|
|
234
|
-
//
|
|
235
|
-
// // 7. If it isn't, we get one from the content-type header.
|
|
236
|
-
// if (!is_extension) {
|
|
237
|
-
// // 1. Make sure we have a content type, since I'm sure
|
|
238
|
-
// // some emails won't have it if they were malformed.
|
|
239
|
-
// if (file.contentType) {
|
|
240
|
-
// // 1. Try to find out the file extension from the
|
|
241
|
-
// // content-type found in the email message.
|
|
242
|
-
// let file_type = mime.getExtension(file.contentType)
|
|
243
|
-
//
|
|
244
|
-
// // 2. If the extension was not found, then we set a
|
|
245
|
-
// // default one which will let the user know
|
|
246
|
-
// // that we don't know the type of the file, while
|
|
247
|
-
// // also setting the type to txt (for convenience)
|
|
248
|
-
// // so it can be open by any editor and inspected.
|
|
249
|
-
// if (!file_type)
|
|
250
|
-
// file_type = 'unknown_extension.txt'
|
|
251
|
-
//
|
|
252
|
-
// // 3. Attach the extension to the file.
|
|
253
|
-
// file_name += `.${file_type}`
|
|
254
|
-
// }
|
|
255
|
-
// }
|
|
256
|
-
//
|
|
257
|
-
// // 8. Then save the buffer of the attachment.
|
|
258
|
-
// const file_body = file.content
|
|
259
|
-
//
|
|
260
|
-
// // 9. Split the S3 Key (path) so we can remove the last element. Since
|
|
261
|
-
// // we don't want the object name, we care only about the path.
|
|
262
|
-
// const tmp = container.key.split('/')
|
|
263
|
-
//
|
|
264
|
-
// // 10. Now remove the last element from the array which is the
|
|
265
|
-
// // file name that contains the raw email, which we don't want.
|
|
266
|
-
// tmp.pop()
|
|
267
|
-
//
|
|
268
|
-
// // 11. After all this, we recombine the array in to a single
|
|
269
|
-
// // string which becomes again the S3 Key minus the file name.
|
|
270
|
-
// const path = tmp.join('/')
|
|
271
|
-
//
|
|
272
|
-
// // 12. This variable is used if there are two files of the same name.
|
|
273
|
-
// let cid = ''
|
|
274
|
-
//
|
|
275
|
-
// // 13. If the CID is set then it means that two files have the same names
|
|
276
|
-
// if (file.cid) {
|
|
277
|
-
// // 1. Add the CID in front of the name of the file so they won't be overwritten
|
|
278
|
-
// cid = `${file.cid} - `
|
|
279
|
-
// }
|
|
280
|
-
//
|
|
281
|
-
// // 14. Create the full key path with the object at the end.
|
|
282
|
-
// const key = `${path}/attachments/${cid}${file_name}`
|
|
283
|
-
//
|
|
284
|
-
// // 15. Set the query.
|
|
285
|
-
// const params = {
|
|
286
|
-
// Bucket: container.bucket,
|
|
287
|
-
// Key: key,
|
|
288
|
-
// Body: file_body,
|
|
289
|
-
// }
|
|
290
|
-
//
|
|
291
|
-
// // -> Execute the query.
|
|
292
|
-
// s3.putObject(params, (error: any, data: any) => {
|
|
293
|
-
// // 1. Check for internal errors.
|
|
294
|
-
// if (error)
|
|
295
|
-
// return callback(error)
|
|
296
|
-
//
|
|
297
|
-
// // -> Move to the next chain.
|
|
298
|
-
// return loop(count, callback)
|
|
299
|
-
// })
|
|
300
|
-
// }
|
|
301
|
-
// })
|
|
302
|
-
// }
|