@travetto/email 7.1.4 → 8.0.0-alpha.1
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/README.md +1 -1
- package/package.json +4 -4
- package/src/resource.ts +2 -2
- package/src/service.ts +3 -3
- package/src/template.ts +1 -1
- package/src/types.ts +8 -9
- package/src/util.ts +7 -13
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ npm install @travetto/email
|
|
|
13
13
|
yarn add @travetto/email
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
A standard API for sending and rendering emails. The mail transport must be defined to allow for mail to be sent properly. Out of the box, the only transport available by default is the [NullTransport](https://github.com/travetto/travetto/tree/main/module/email/src/transport.ts#L16) which will just drop emails. The structure of the API is derived from [nodemailer](https://nodemailer.com/about/), but is compatible with any library that can handle the [EmailOptions](https://github.com/travetto/travetto/tree/main/module/email/src/types.ts#
|
|
16
|
+
A standard API for sending and rendering emails. The mail transport must be defined to allow for mail to be sent properly. Out of the box, the only transport available by default is the [NullTransport](https://github.com/travetto/travetto/tree/main/module/email/src/transport.ts#L16) which will just drop emails. The structure of the API is derived from [nodemailer](https://nodemailer.com/about/), but is compatible with any library that can handle the [EmailOptions](https://github.com/travetto/travetto/tree/main/module/email/src/types.ts#L44) input.
|
|
17
17
|
|
|
18
18
|
To expose the necessary email transport, the following pattern is commonly used:
|
|
19
19
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/email",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0-alpha.1",
|
|
4
4
|
"description": "Email transmission module.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"email",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"directory": "module/email"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@travetto/config": "^
|
|
27
|
-
"@travetto/di": "^
|
|
28
|
-
"@travetto/runtime": "^
|
|
26
|
+
"@travetto/config": "^8.0.0-alpha.1",
|
|
27
|
+
"@travetto/di": "^8.0.0-alpha.1",
|
|
28
|
+
"@travetto/runtime": "^8.0.0-alpha.1",
|
|
29
29
|
"@types/mustache": "^4.2.6",
|
|
30
30
|
"mustache": "^4.2.0"
|
|
31
31
|
},
|
package/src/resource.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RuntimeError, Env, FileLoader, Runtime, RuntimeIndex } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
/** Build a resource loader that looks into a module and it's dependencies */
|
|
4
4
|
export class EmailResourceLoader extends FileLoader {
|
|
5
5
|
constructor(moduleName: string, globalResources?: string[]) {
|
|
6
6
|
const found = RuntimeIndex.getModule(moduleName);
|
|
7
7
|
if (!found) {
|
|
8
|
-
throw new
|
|
8
|
+
throw new RuntimeError(`Unknown module - ${moduleName}`, { category: 'notfound', details: { module: moduleName } });
|
|
9
9
|
}
|
|
10
10
|
super([
|
|
11
11
|
...Env.TRV_RESOURCES.list ?? [],
|
package/src/service.ts
CHANGED
|
@@ -37,9 +37,9 @@ export class MailService {
|
|
|
37
37
|
async getCompiled(key: string): Promise<EmailCompiled> {
|
|
38
38
|
if (!this.#compiled.has(key)) {
|
|
39
39
|
const [html, text, subject] = await Promise.all([
|
|
40
|
-
RuntimeResources.
|
|
41
|
-
RuntimeResources.
|
|
42
|
-
RuntimeResources.
|
|
40
|
+
RuntimeResources.readText(`${key}.compiled.html`),
|
|
41
|
+
RuntimeResources.readText(`${key}.compiled.text`),
|
|
42
|
+
RuntimeResources.readText(`${key}.compiled.subject`)
|
|
43
43
|
].map(file => file.then(MailUtil.purgeBrand)));
|
|
44
44
|
if (this.#cacheResults) {
|
|
45
45
|
this.#compiled.set(key, { html, text, subject });
|
package/src/template.ts
CHANGED
|
@@ -30,7 +30,7 @@ export class MustacheInterpolator implements MailInterpolator {
|
|
|
30
30
|
const promises: Promise<string>[] = [];
|
|
31
31
|
template = template.replace(/[{]{2,3}>\s+(\S+)([.]html)?\s*[}]{2,3}/g, (all: string, name: string) => {
|
|
32
32
|
promises.push(
|
|
33
|
-
RuntimeResources.
|
|
33
|
+
RuntimeResources.readText(`${name}.html`) // Ensure html file
|
|
34
34
|
.then(contents => this.resolveNested(contents))
|
|
35
35
|
);
|
|
36
36
|
return `$%${promises.length - 1}%$`;
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { Readable } from 'node:stream';
|
|
2
1
|
import type { Url } from 'node:url';
|
|
3
2
|
|
|
4
|
-
import type { FileLoader } from '@travetto/runtime';
|
|
3
|
+
import type { BinaryType, FileLoader } from '@travetto/runtime';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* An address
|
|
@@ -14,15 +13,15 @@ export interface EmailAddress {
|
|
|
14
13
|
/**
|
|
15
14
|
* An attachment for the email
|
|
16
15
|
*/
|
|
17
|
-
interface AttachmentLike {
|
|
18
|
-
content?:
|
|
16
|
+
interface AttachmentLike<B extends BinaryType = BinaryType> {
|
|
17
|
+
content?: B | string;
|
|
19
18
|
path?: string | Url;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* A full attachment
|
|
24
23
|
*/
|
|
25
|
-
export interface EmailAttachment extends AttachmentLike {
|
|
24
|
+
export interface EmailAttachment<B extends BinaryType = BinaryType> extends AttachmentLike<B> {
|
|
26
25
|
filename?: string | false;
|
|
27
26
|
cid?: string;
|
|
28
27
|
encoding?: string;
|
|
@@ -30,7 +29,7 @@ export interface EmailAttachment extends AttachmentLike {
|
|
|
30
29
|
contentTransferEncoding?: false | '7bit' | 'base64' | 'quoted-printable';
|
|
31
30
|
contentDisposition?: 'attachment' | 'inline';
|
|
32
31
|
headers?: Record<string, string | string[]>;
|
|
33
|
-
raw?:
|
|
32
|
+
raw?: B | string;
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
type EmailContentType = 'html' | 'text' | 'subject';
|
|
@@ -42,7 +41,7 @@ export type EmailIdentityList = EmailIdentity | EmailIdentity[];
|
|
|
42
41
|
* Full message options
|
|
43
42
|
* @concrete
|
|
44
43
|
*/
|
|
45
|
-
export interface EmailOptions {
|
|
44
|
+
export interface EmailOptions<B extends BinaryType = BinaryType> {
|
|
46
45
|
html: string;
|
|
47
46
|
text?: string;
|
|
48
47
|
subject: string;
|
|
@@ -59,8 +58,8 @@ export interface EmailOptions {
|
|
|
59
58
|
inReplyTo?: EmailIdentity;
|
|
60
59
|
references?: string | string[];
|
|
61
60
|
headers?: Record<string, string | string[]>;
|
|
62
|
-
attachments?: EmailAttachment[];
|
|
63
|
-
alternatives?: EmailAttachment[];
|
|
61
|
+
attachments?: EmailAttachment<B>[];
|
|
62
|
+
alternatives?: EmailAttachment<B>[];
|
|
64
63
|
messageId?: string;
|
|
65
64
|
date?: Date | string;
|
|
66
65
|
encoding?: string;
|
package/src/util.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Runtime,
|
|
1
|
+
import { Runtime, CodecUtil, BinaryMetadataUtil } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
import type { EmailAttachment, EmailIdentity, EmailIdentityList, EmailOptions } from './types.ts';
|
|
4
4
|
|
|
@@ -32,9 +32,9 @@ export class MailUtil {
|
|
|
32
32
|
const contentMap = new Map<string, string>();
|
|
33
33
|
|
|
34
34
|
// Max of 10mb
|
|
35
|
-
html = html.replace(/data:(image\/[^;]{1,50});base64,([^"']{1,10000000})/g, (__, contentType, content) =>
|
|
35
|
+
html = html.replace(/data:(image\/[^;]{1,50});base64,([^"']{1,10000000})/g, (__, contentType: string, content: string) =>
|
|
36
36
|
// Ensure same data uris map to a single cid
|
|
37
|
-
|
|
37
|
+
contentMap.getOrInsertComputed(content, () => {
|
|
38
38
|
const contentId = `image-${idx += 1}`;
|
|
39
39
|
const ext = contentType.split('/')[1];
|
|
40
40
|
attachments.push({
|
|
@@ -43,20 +43,14 @@ export class MailUtil {
|
|
|
43
43
|
headers: {
|
|
44
44
|
'X-Attachment-Id': `${contentId}`
|
|
45
45
|
},
|
|
46
|
-
content:
|
|
46
|
+
content: CodecUtil.fromBase64String(content),
|
|
47
47
|
contentDisposition: 'inline',
|
|
48
48
|
contentType
|
|
49
49
|
});
|
|
50
|
-
contentMap.set(content, contentId);
|
|
51
50
|
return `cid:${contentId}`;
|
|
52
|
-
}
|
|
53
|
-
return contentMap.get(content)!;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
51
|
+
}));
|
|
56
52
|
|
|
57
|
-
return {
|
|
58
|
-
html, attachments
|
|
59
|
-
};
|
|
53
|
+
return { html, attachments };
|
|
60
54
|
}
|
|
61
55
|
|
|
62
56
|
/**
|
|
@@ -78,7 +72,7 @@ export class MailUtil {
|
|
|
78
72
|
static buildUniqueMessageId(message: EmailOptions): string {
|
|
79
73
|
const from = this.getPrimaryEmail(message.from)!;
|
|
80
74
|
const to = this.getPrimaryEmail(message.to)!;
|
|
81
|
-
const uniqueId =
|
|
75
|
+
const uniqueId = BinaryMetadataUtil.hash(`${to}${from}${message.subject}${Date.now()}`, { length: 12 });
|
|
82
76
|
return `<${uniqueId}@${from.split('@')[1]}>`;
|
|
83
77
|
}
|
|
84
78
|
}
|