@travetto/email 2.1.7 → 2.2.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/README.md +2 -2
- package/package.json +3 -3
- package/src/extension/nodemailer.ts +5 -3
- package/src/service.ts +7 -7
- package/src/template.ts +1 -1
- package/src/transport.ts +4 -3
- package/src/types.ts +5 -4
- package/src/util.ts +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
npm install @travetto/email
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
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#L15) 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 [MessageOptions](https://github.com/travetto/travetto/tree/main/module/email/src/types.ts#
|
|
11
|
+
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#L15) 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 [MessageOptions](https://github.com/travetto/travetto/tree/main/module/email/src/types.ts#L37) input.
|
|
12
12
|
|
|
13
13
|
To expose the necessary email transport, the following pattern is commonly used:
|
|
14
14
|
|
|
@@ -35,7 +35,7 @@ By design, sending an email requires the sender to specify the html, text option
|
|
|
35
35
|
* `resources/<key>.compiled.subject`
|
|
36
36
|
With `.html` being the only required field. The [Email Templating](https://github.com/travetto/travetto/tree/main/module/email-template#readme "Email templating module") module supports this format, and will generate files accordingly. Also, note that `<key>` can include slashes, allowing for nesting folders.
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Nodemailer - Extension
|
|
39
39
|
|
|
40
40
|
Given the integration with [nodemailer](https://nodemailer.com/about/), all extensions should be usable out of the box. The primary [nodemailer](https://nodemailer.com/about/) modules are provided (assuming dependencies are installed):
|
|
41
41
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/email",
|
|
3
3
|
"displayName": "Email",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"description": "Email transmission module.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"email",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"directory": "module/email"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@travetto/config": "^2.
|
|
28
|
-
"@travetto/di": "^2.
|
|
27
|
+
"@travetto/config": "^2.2.0",
|
|
28
|
+
"@travetto/di": "^2.2.0",
|
|
29
29
|
"@types/mustache": "^4.1.3",
|
|
30
30
|
"mustache": "^4.2.0"
|
|
31
31
|
},
|
|
@@ -20,8 +20,9 @@ export class NodemailerTransport implements MailTransport {
|
|
|
20
20
|
this.#transport = nodemailer.createTransport(transportFactory);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
async send(mail: MessageOptions): Promise<
|
|
24
|
-
|
|
23
|
+
async send<S extends SentMessage = SentMessage>(mail: MessageOptions): Promise<S> {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
25
|
+
const res = await this.#transport.sendMail(mail) as {
|
|
25
26
|
messageId?: string;
|
|
26
27
|
envelope?: Record<string, string>;
|
|
27
28
|
accepted?: string[];
|
|
@@ -34,6 +35,7 @@ export class NodemailerTransport implements MailTransport {
|
|
|
34
35
|
console.error('Unable to send emails', { recipientCount: res.rejected?.length });
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
39
|
+
return res as S;
|
|
38
40
|
}
|
|
39
41
|
}
|
package/src/service.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { ResourceManager } from '@travetto/base';
|
|
|
2
2
|
import { Injectable } from '@travetto/di';
|
|
3
3
|
import { EnvUtil } from '@travetto/boot';
|
|
4
4
|
|
|
5
|
-
import { MessageOptions } from './types';
|
|
5
|
+
import { MessageOptions, SentMessage } from './types';
|
|
6
6
|
import { MailTransport } from './transport';
|
|
7
7
|
import { MailTemplateEngine } from './template';
|
|
8
8
|
import { MailUtil } from './util';
|
|
@@ -28,8 +28,8 @@ export class MailService {
|
|
|
28
28
|
/**
|
|
29
29
|
* Send multiple messages.
|
|
30
30
|
*/
|
|
31
|
-
async sendAll(messages: MessageOptions[], base: Partial<MessageOptions> = {}) {
|
|
32
|
-
return Promise.all(messages.map(msg => this.send({
|
|
31
|
+
async sendAll<S extends SentMessage = SentMessage>(messages: MessageOptions[], base: Partial<MessageOptions> = {}): Promise<S[]> {
|
|
32
|
+
return Promise.all(messages.map(msg => this.send<S>({
|
|
33
33
|
...base,
|
|
34
34
|
...msg,
|
|
35
35
|
...(msg.context || base.context ? {
|
|
@@ -44,7 +44,7 @@ export class MailService {
|
|
|
44
44
|
/**
|
|
45
45
|
* Send a pre compiled email that has a relevant html, subject and optional text file associated
|
|
46
46
|
*/
|
|
47
|
-
async sendCompiled(key: string, msg: Omit<MessageOptions, 'html' | 'text' | 'subject'>): Promise<
|
|
47
|
+
async sendCompiled<S extends SentMessage = SentMessage>(key: string, msg: Omit<MessageOptions, 'html' | 'text' | 'subject'>): Promise<S> {
|
|
48
48
|
// Bypass cache if in dynamic mode
|
|
49
49
|
if (EnvUtil.isDynamic() || !this.#compiled.has(key)) {
|
|
50
50
|
const [html, text, subject] = await Promise.all([
|
|
@@ -55,13 +55,13 @@ export class MailService {
|
|
|
55
55
|
|
|
56
56
|
this.#compiled.set(key, { html, text, subject });
|
|
57
57
|
}
|
|
58
|
-
return this.send({ ...msg, ...this.#compiled.get(key)! });
|
|
58
|
+
return this.send<S>({ ...msg, ...this.#compiled.get(key)! });
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Send a single message
|
|
63
63
|
*/
|
|
64
|
-
async send(msg: MessageOptions): Promise<
|
|
64
|
+
async send<S extends SentMessage>(msg: MessageOptions): Promise<S> {
|
|
65
65
|
// Template if context is provided
|
|
66
66
|
if (msg.context) {
|
|
67
67
|
const [html, text, subject] = await Promise.all([
|
|
@@ -92,6 +92,6 @@ export class MailService {
|
|
|
92
92
|
delete msg.html; // This is a hack to fix nodemailer
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
return this.#transport.send(msg);
|
|
95
|
+
return this.#transport.send<S>(msg);
|
|
96
96
|
}
|
|
97
97
|
}
|
package/src/template.ts
CHANGED
|
@@ -42,7 +42,7 @@ export class MustacheTemplateEngine implements MailTemplateEngine {
|
|
|
42
42
|
/**
|
|
43
43
|
* Interpolate text with data
|
|
44
44
|
*/
|
|
45
|
-
template(text: string, data: Record<string, unknown>) {
|
|
45
|
+
template(text: string, data: Record<string, unknown>): string {
|
|
46
46
|
return Mustache.render(text, data);
|
|
47
47
|
}
|
|
48
48
|
}
|
package/src/transport.ts
CHANGED
|
@@ -6,14 +6,15 @@ import { MessageOptions, SentMessage } from './types';
|
|
|
6
6
|
* @concrete ./internal/types:MailTransportTarget
|
|
7
7
|
*/
|
|
8
8
|
export interface MailTransport {
|
|
9
|
-
send(mail: MessageOptions): Promise<
|
|
9
|
+
send<S extends SentMessage = SentMessage>(mail: MessageOptions): Promise<S>;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Transport that consumes messages without sending
|
|
14
14
|
*/
|
|
15
15
|
export class NullTransport implements MailTransport {
|
|
16
|
-
async send(mail: MessageOptions): Promise<
|
|
17
|
-
|
|
16
|
+
async send<S extends SentMessage = SentMessage>(mail: MessageOptions): Promise<S> {
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
18
|
+
return {} as S;
|
|
18
19
|
}
|
|
19
20
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Readable } from 'stream';
|
|
1
2
|
import { Url } from 'url';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -12,7 +13,7 @@ export interface Address {
|
|
|
12
13
|
* An attachment for the email
|
|
13
14
|
*/
|
|
14
15
|
interface AttachmentLike {
|
|
15
|
-
content?: string | Buffer |
|
|
16
|
+
content?: string | Buffer | Readable;
|
|
16
17
|
path?: string | Url;
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -24,10 +25,10 @@ export interface Attachment extends AttachmentLike {
|
|
|
24
25
|
cid?: string;
|
|
25
26
|
encoding?: string;
|
|
26
27
|
contentType?: string;
|
|
27
|
-
contentTransferEncoding?:
|
|
28
|
-
contentDisposition?:
|
|
28
|
+
contentTransferEncoding?: false | '7bit' | 'base64' | 'quoted-printable';
|
|
29
|
+
contentDisposition?: 'attachment' | 'inline';
|
|
29
30
|
headers?: Record<string, string | string[]>;
|
|
30
|
-
raw?: string | Buffer |
|
|
31
|
+
raw?: string | Buffer | Readable | AttachmentLike;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/**
|
package/src/util.ts
CHANGED
|
@@ -9,7 +9,7 @@ export class MailUtil {
|
|
|
9
9
|
*
|
|
10
10
|
* @param html
|
|
11
11
|
*/
|
|
12
|
-
static async extractImageAttachments(html: string) {
|
|
12
|
+
static async extractImageAttachments(html: string): Promise<{ html: string, attachments: Attachment[] }> {
|
|
13
13
|
let idx = 0;
|
|
14
14
|
const attachments: Attachment[] = [];
|
|
15
15
|
const contentMap = new Map<string, string>();
|