@travetto/email 2.1.6 → 2.2.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 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#L36) input.
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
- ## Nodmailer - Extension
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.1.6",
4
+ "version": "2.2.1",
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.1.4",
28
- "@travetto/di": "^2.1.4",
27
+ "@travetto/config": "^2.2.1",
28
+ "@travetto/di": "^2.2.1",
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<SentMessage> {
24
- const res = await this.#transport.sendMail(mail as nodemailer.SendMailOptions) as {
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
- return res;
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<unknown> {
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<unknown> {
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([
@@ -88,10 +88,10 @@ export class MailService {
88
88
  // NOTE: The leading space on the content type is to force node mailer to not do anything fancy with
89
89
  content: html, contentDisposition: 'inline', contentTransferEncoding: '7bit', contentType: ' text/html; charset=utf-8'
90
90
  });
91
- // @ts-ignore
91
+ // @ts-expect-error
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<SentMessage>;
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<SentMessage> {
17
- return {};
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 | NodeJS.ReadableStream;
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?: string;
28
- contentDisposition?: string;
28
+ contentTransferEncoding?: false | '7bit' | 'base64' | 'quoted-printable';
29
+ contentDisposition?: 'attachment' | 'inline';
29
30
  headers?: Record<string, string | string[]>;
30
- raw?: string | Buffer | NodeJS.ReadableStream | AttachmentLike;
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>();