@travetto/email 3.0.0-rc.2 → 3.0.0-rc.21
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/{index.ts → __index__.ts} +1 -0
- package/package.json +10 -7
- package/src/resource.ts +14 -0
- package/src/service.ts +10 -7
- package/src/template.ts +8 -5
- package/src/extension/nodemailer.ts +0 -48
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- This file was generated by @travetto/doc and should not be modified directly -->
|
|
2
|
-
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/email/
|
|
2
|
+
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/email/DOC.ts and execute "npx trv doc" to rebuild -->
|
|
3
3
|
# Email
|
|
4
4
|
## Email transmission module.
|
|
5
5
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/email",
|
|
3
|
-
"
|
|
4
|
-
"version": "3.0.0-rc.2",
|
|
3
|
+
"version": "3.0.0-rc.21",
|
|
5
4
|
"description": "Email transmission module.",
|
|
6
5
|
"keywords": [
|
|
7
6
|
"email",
|
|
@@ -15,20 +14,24 @@
|
|
|
15
14
|
"name": "Travetto Framework"
|
|
16
15
|
},
|
|
17
16
|
"files": [
|
|
18
|
-
"
|
|
17
|
+
"__index__.ts",
|
|
19
18
|
"src"
|
|
20
19
|
],
|
|
21
|
-
"main": "
|
|
20
|
+
"main": "__index__.ts",
|
|
22
21
|
"repository": {
|
|
23
22
|
"url": "https://github.com/travetto/travetto.git",
|
|
24
23
|
"directory": "module/email"
|
|
25
24
|
},
|
|
26
25
|
"dependencies": {
|
|
27
|
-
"@travetto/
|
|
28
|
-
"@travetto/
|
|
29
|
-
"@
|
|
26
|
+
"@travetto/base": "^3.0.0-rc.17",
|
|
27
|
+
"@travetto/config": "^3.0.0-rc.21",
|
|
28
|
+
"@travetto/di": "^3.0.0-rc.20",
|
|
29
|
+
"@types/mustache": "^4.2.2",
|
|
30
30
|
"mustache": "^4.2.0"
|
|
31
31
|
},
|
|
32
|
+
"travetto": {
|
|
33
|
+
"displayName": "Email"
|
|
34
|
+
},
|
|
32
35
|
"publishConfig": {
|
|
33
36
|
"access": "public"
|
|
34
37
|
}
|
package/src/resource.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FileResourceProvider } from '@travetto/base';
|
|
2
|
+
import { InjectableFactory } from '@travetto/di';
|
|
3
|
+
|
|
4
|
+
export class EmailResource extends FileResourceProvider {
|
|
5
|
+
|
|
6
|
+
@InjectableFactory()
|
|
7
|
+
static getResources(): EmailResource {
|
|
8
|
+
return new EmailResource();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
constructor(paths?: string[]) {
|
|
12
|
+
super({ paths, includeCommon: true });
|
|
13
|
+
}
|
|
14
|
+
}
|
package/src/service.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GlobalEnv } from '@travetto/base';
|
|
2
2
|
import { Injectable } from '@travetto/di';
|
|
3
|
-
import { EnvUtil } from '@travetto/boot';
|
|
4
3
|
|
|
5
4
|
import { MessageOptions, SentMessage } from './types';
|
|
6
5
|
import { MailTransport } from './transport';
|
|
7
6
|
import { MailTemplateEngine } from './template';
|
|
8
7
|
import { MailUtil } from './util';
|
|
8
|
+
import { EmailResource } from './resource';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Email service for sending and templating emails
|
|
@@ -16,13 +16,16 @@ export class MailService {
|
|
|
16
16
|
#compiled = new Map<string, MessageOptions>();
|
|
17
17
|
#transport: MailTransport;
|
|
18
18
|
#tplEngine: MailTemplateEngine;
|
|
19
|
+
#resources: EmailResource;
|
|
19
20
|
|
|
20
21
|
constructor(
|
|
21
22
|
transport: MailTransport,
|
|
22
|
-
tplEngine: MailTemplateEngine
|
|
23
|
+
tplEngine: MailTemplateEngine,
|
|
24
|
+
resources: EmailResource
|
|
23
25
|
) {
|
|
24
26
|
this.#tplEngine = tplEngine;
|
|
25
27
|
this.#transport = transport;
|
|
28
|
+
this.#resources = resources;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
/**
|
|
@@ -46,11 +49,11 @@ export class MailService {
|
|
|
46
49
|
*/
|
|
47
50
|
async sendCompiled<S extends SentMessage = SentMessage>(key: string, msg: Omit<MessageOptions, 'html' | 'text' | 'subject'>): Promise<S> {
|
|
48
51
|
// Bypass cache if in dynamic mode
|
|
49
|
-
if (
|
|
52
|
+
if (GlobalEnv.dynamic || !this.#compiled.has(key)) {
|
|
50
53
|
const [html, text, subject] = await Promise.all([
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
this.#resources.read(`${key}.compiled.html`),
|
|
55
|
+
this.#resources.read(`${key}.compiled.text`).catch(() => ''),
|
|
56
|
+
this.#resources.read(`${key}.compiled.subject`)
|
|
54
57
|
]);
|
|
55
58
|
|
|
56
59
|
this.#compiled.set(key, { html, text, subject });
|
package/src/template.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import mustache from 'mustache';
|
|
2
2
|
|
|
3
3
|
import { Injectable } from '@travetto/di';
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
import { EmailResource } from './resource';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Mail templating engine
|
|
@@ -23,14 +24,16 @@ export interface MailTemplateEngine {
|
|
|
23
24
|
@Injectable()
|
|
24
25
|
export class MustacheTemplateEngine implements MailTemplateEngine {
|
|
25
26
|
|
|
27
|
+
resources = new EmailResource();
|
|
28
|
+
|
|
26
29
|
/**
|
|
27
30
|
* Resolved nested templates
|
|
28
31
|
*/
|
|
29
32
|
async resolveNested(template: string): Promise<string> {
|
|
30
33
|
const promises: Promise<string>[] = [];
|
|
31
|
-
template = template.replace(/[{]{2}>\s+(\S+)([.]html)?\s*[}]{2}/g, (all: string, name: string) => {
|
|
34
|
+
template = template.replace(/[{]{2,3}>\s+(\S+)([.]html)?\s*[}]{2,3}/g, (all: string, name: string) => {
|
|
32
35
|
promises.push(
|
|
33
|
-
|
|
36
|
+
this.resources.read(`${name}.html`) // Ensure html file
|
|
34
37
|
.then(contents => this.resolveNested(contents))
|
|
35
38
|
);
|
|
36
39
|
return `$%${promises.length - 1}%$`;
|
|
@@ -43,6 +46,6 @@ export class MustacheTemplateEngine implements MailTemplateEngine {
|
|
|
43
46
|
* Interpolate text with data
|
|
44
47
|
*/
|
|
45
48
|
template(text: string, data: Record<string, unknown>): string {
|
|
46
|
-
return
|
|
49
|
+
return mustache.render(text, data);
|
|
47
50
|
}
|
|
48
51
|
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type * as nodemailer from 'nodemailer';
|
|
2
|
-
import type * as json from 'nodemailer/lib/json-transport';
|
|
3
|
-
import type * as smtp from 'nodemailer/lib/smtp-transport';
|
|
4
|
-
import type * as ses from 'nodemailer/lib/ses-transport';
|
|
5
|
-
import type * as sendmail from 'nodemailer/lib/sendmail-transport';
|
|
6
|
-
|
|
7
|
-
import { MessageOptions, SentMessage } from '../types';
|
|
8
|
-
import { MailTransport } from '../transport';
|
|
9
|
-
|
|
10
|
-
type Transport = nodemailer.Transport | json.Options | smtp.Options | ses.Options | sendmail.Options;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Nodemailer transport, takes in a transport factory as the input
|
|
14
|
-
*/
|
|
15
|
-
export class NodemailerTransport implements MailTransport {
|
|
16
|
-
#transport: nodemailer.Transporter;
|
|
17
|
-
|
|
18
|
-
constructor(transportFactory: Transport) {
|
|
19
|
-
try {
|
|
20
|
-
const nm = require('nodemailer');
|
|
21
|
-
this.#transport = nm.createTransport(transportFactory);
|
|
22
|
-
} catch (err) {
|
|
23
|
-
if (err instanceof Error) {
|
|
24
|
-
console.error('Please install nodemailer before use: "npm install nodemailer"');
|
|
25
|
-
}
|
|
26
|
-
throw err;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async send<S extends SentMessage = SentMessage>(mail: MessageOptions): Promise<S> {
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
32
|
-
const res = await this.#transport.sendMail(mail) as {
|
|
33
|
-
messageId?: string;
|
|
34
|
-
envelope?: Record<string, string>;
|
|
35
|
-
accepted?: string[];
|
|
36
|
-
rejected?: string[];
|
|
37
|
-
pending?: string[];
|
|
38
|
-
response?: string;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
if (res.rejected?.length) {
|
|
42
|
-
console.error('Unable to send emails', { recipientCount: res.rejected?.length });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
46
|
-
return res as S;
|
|
47
|
-
}
|
|
48
|
-
}
|