@pixelplex/mail-service 0.2.7 → 0.2.10

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/.gitlab-ci.yml CHANGED
@@ -2,13 +2,13 @@ stages:
2
2
  - 📦 package
3
3
 
4
4
  📦 package:
5
- image: node:20.17-alpine
5
+ image: node:22.22.1-alpine
6
6
  stage: 📦 package
7
7
  tags:
8
8
  - docker
9
9
  script:
10
10
  - echo "//registry.yarnpkg.com/:_authToken=$NPM_TOKEN" >>~/.npmrc
11
- - yarn
11
+ - yarn install --frozen-lockfile
12
12
  - yarn build
13
13
  - yarn publish --non-interactive
14
14
  only:
package/README.md CHANGED
@@ -1,98 +1,115 @@
1
1
  # Mail Service
2
2
 
3
- Library for fast implementation of the functionality of sending email messages.
3
+ Library for sending email messages through configured gateways.
4
4
 
5
- The sends messages them via email.
6
-
7
- ## How to use
8
-
9
- 1. create template for html, plain text and subject
10
- 2. add `@pixelplex/mail-service` to your application
11
- 3. Call `MailModule.forRoot` from `@pixelplex/mail-service`
12
- with specified gateways and options
13
- 4. send a message by calling `this.mailSenderService.sendEmail('test@gmail.com', { htmlPath: htmlTemplatePath, plainPath: plainTextTemplatePath, subjectPath: subjectTemplatePath }, {year: 20});` where `mailSenderService` is `MailSenderService`
14
-
15
- Currently supported gateways:
5
+ ## Supported gateways
16
6
 
17
7
  - slack
18
8
  - console
19
9
  - smtp
20
10
  - sendgrid
11
+ - resend
21
12
 
22
- Didn't understand anything? Okay, let's see more details
13
+ ## Templates
23
14
 
24
- ### Prepare templates
15
+ The service uses Handlebars as the template engine.
25
16
 
26
- The service uses Handlebars as template engine. So all your email templates should be prepared as handlebars templates.
17
+ Expected template files:
27
18
 
28
- For sending message your templates folder should include this files:
19
+ - `{name}.handlebars` for HTML body
20
+ - `{name}.subject.handlebars` for subject
21
+ - `{name}.plain.handlebars` for plain-text body
29
22
 
30
- - `{name}.handlebars` - body of your email where `{name}` is just your template name for email. For example `welcome.handlebars` for the welcome use email
31
- - `{name}.subject.handlebars` - subject (title) of your email. You can use subject field to specify subject directly. It will override subjectPath
32
- - `{name}.plain.handlebars` - subject (title) of your email. You can use plain field to specify plain directly. It will override plainPath
23
+ Example:
33
24
 
34
25
  ```handlebars
35
- # welcome.subject.handlebars Welcome, {{name}}! This is subject
26
+ # welcome.subject.handlebars Welcome, {{name}}!
36
27
  ```
37
28
 
38
29
  ```handlebars
39
30
  # welcome.handlebars
40
-
41
31
  <html>
42
32
  <head></head>
43
33
  <body>
44
34
  <p>Welcome, {{name}}!</p>
45
- <p>How are you?</p>
46
35
  </body>
47
36
  </html>
48
37
  ```
49
38
 
50
39
  ```handlebars
51
- # welcome.plain.handlebars
52
-
53
- <html>
54
- <head></head>
55
- <body>
56
- <p>Welcome, {{name}}!</p>
57
- <p>How are you?</p>
58
- </body>
59
- </html>
40
+ # welcome.plain.handlebars Welcome, {{name}}!
60
41
  ```
61
42
 
62
43
  ## Configuration
63
44
 
64
- | Name | Description | Example |
65
- | --------------- | -------------------------------------------------------- | ------------------------- |
66
- | gateways | Array of gateways to send email | `['slack']` |
67
- | customGateways | Array of custom gateways classes | `[CustomGateway]` |
68
- | smtp.host | Mail gateway host address | `smtp.gmail.com` |
69
- | smtp.port | Mail gateway port number | `586` |
70
- | smtp.username | Mail gateway username | `username` |
71
- | smtp.password | Mail gateway password | `qh05780c2qcm034579` |
72
- | \*.sender | Mail sender address | `postmail@pixelplex.io` |
73
- | slack.url | Hook URL in case you want to duplicate messages to Slack | `https://hooks.slack.com` |
74
- | sendgrid.apiKey | Sendgrid api key | `oiqur9823uiofhaoafoe` |
45
+ | Name | Description | Example |
46
+ | ------------------------- | -------------------------------------------------------- | ------------------------- |
47
+ | gateways | Array of gateways to send email | `['resend']` |
48
+ | customGateways | Array of custom gateways classes | `[CustomGateway]` |
49
+ | smtp.host | Mail gateway host address | `smtp.gmail.com` |
50
+ | smtp.port | Mail gateway port number | `586` |
51
+ | smtp.username | Mail gateway username | `username` |
52
+ | smtp.password | Mail gateway password | `qh05780c2qcm034579` |
53
+ | \*.sender | Mail sender address | `postmail@pixelplex.io` |
54
+ | slack.url | Hook URL in case you want to duplicate messages to Slack | `https://hooks.slack.com` |
55
+ | sendgrid.apiKey | Sendgrid API key | `oiqur9823uiofhaoafoe` |
56
+ | sendgrid.senderName | Optional sender display name | `Acme` |
57
+ | sendgrid.replyTo | Optional reply-to email address | `support@example.com` |
58
+ | sendgrid.timeoutMs | Optional HTTP request timeout in milliseconds | `12000` |
59
+ | sendgrid.trackingSettings | Optional SendGrid SDK tracking settings | See example below |
60
+ | resend.apiKey | Resend API key | `re_xxxxxxxxx` |
61
+
62
+ ### SendGrid config
63
+
64
+ ```typescript
65
+ export const mailConfig = {
66
+ gateways: ['sendgrid'],
67
+ sendgrid: {
68
+ apiKey: process.env.SENDGRID_API_KEY,
69
+ sender: 'noreply@example.com',
70
+ senderName: 'Acme',
71
+ replyTo: 'support@example.com',
72
+ timeoutMs: 12000,
73
+ trackingSettings: {
74
+ clickTracking: { enable: false, enableText: false },
75
+ openTracking: { enable: false },
76
+ },
77
+ },
78
+ };
79
+ ```
80
+
81
+ All new SendGrid options are optional. Existing string senders, including formatted addresses,
82
+ continue to work. Each gateway instance owns its SendGrid client, so modules with different
83
+ keys and timeouts do not affect one another. Provider errors are propagated to the caller;
84
+ the gateway does not retry automatically.
85
+
86
+ ### Resend config
75
87
 
76
- ### Trigger new message sending
88
+ ```typescript
89
+ export const mailConfig = {
90
+ gateways: ['resend'],
91
+ resend: {
92
+ apiKey: process.env.RESEND_API_KEY,
93
+ sender: process.env.MAIL_SENDER,
94
+ },
95
+ };
96
+ ```
77
97
 
78
- **1. Install npm package**
98
+ ## Usage
79
99
 
80
100
  ```bash
81
101
  yarn add @pixelplex/mail-service
82
102
  ```
83
103
 
84
- **2. Import MailModule** in your module you'll send mail from:
85
-
86
104
  ```typescript
87
105
  import { Module } from '@nestjs/common';
88
106
  import { MailModule } from '@pixelplex/mail-service';
89
107
  import { AppService } from './app.service';
90
108
 
91
109
  @Module({
92
- controllers: [],
93
110
  imports: [
94
111
  MailModule.forRoot({
95
- gateways: ['slack', 'smtp', 'console'],
112
+ gateways: ['slack', 'smtp', 'console', 'resend'],
96
113
  slack: { url: 'hooks.slack.com' },
97
114
  smtp: {
98
115
  username: 'postmail@pixelplex.io',
@@ -101,6 +118,10 @@ import { AppService } from './app.service';
101
118
  port: 678,
102
119
  password: 'password',
103
120
  },
121
+ resend: {
122
+ apiKey: RESEND_API_KEY,
123
+ sender: MAIL_SENDER,
124
+ },
104
125
  }),
105
126
  ],
106
127
  providers: [AppService],
@@ -108,35 +129,50 @@ import { AppService } from './app.service';
108
129
  export class AppModule {}
109
130
  ```
110
131
 
111
- **3. Call sendEmail** to send your mail:
112
-
113
132
  ```typescript
114
133
  import { Injectable } from '@nestjs/common';
115
134
  import { MailSenderService } from '@pixelplex/mail-service';
116
135
 
117
136
  @Injectable()
118
137
  export class AppService {
119
- constructor(private mailSenderService: MailSenderService) {}
138
+ constructor(private readonly mailSenderService: MailSenderService) {}
120
139
 
121
- async onModuleInit() {
122
- this.mailSenderService.sendEmail(
140
+ async sendWelcomeEmail() {
141
+ await this.mailSenderService.sendEmail(
123
142
  'test@gmail.com',
124
- // additionaly you can use plain: plainText, subject: subjectText to specify plain or subject directly
125
- // if so, plainPath or subjectPath will be ignored
126
- { htmlPath: htmlTemplatePath, plainPath: plainTextTemplatePath, subjectPath: subjectTemplatePath },
143
+ {
144
+ htmlPath: htmlTemplatePath,
145
+ plainPath: plainTextTemplatePath,
146
+ subjectPath: subjectTemplatePath,
147
+ },
127
148
  { year: 20 },
128
149
  );
129
150
  }
130
151
  }
131
152
  ```
132
153
 
133
- `{year: 20}` is the object with data which will used as payload data during processing your handlebars template.
154
+ `{ year: 20 }` is the Handlebars context passed into the templates.
155
+
156
+ React templates are not supported at the moment. The package supports the same Handlebars-based flow as before, including for the new `resend` gateway.
157
+
158
+ ## 0.2.10 compatibility
159
+
160
+ Dependency updates include Nodemailer 10.3.1 for security fixes. It bundles its own types and requires Node.js 20+
161
+ (the existing NestJS 11 dependency already requires Node.js 20+). SMTP text, HTML and attachments are covered by MIME tests.
162
+ ESLint stays on 9.39.5 because the installed `eslint-plugin-import` does not support ESLint 10.
134
163
 
135
- ### Custom gateways
164
+ The release audit has no high/critical findings. Remaining advisories: moderate `glob`/`minimatch` in development
165
+ tools (fixes require incompatible major updates), and low `deepmerge` including SendGrid's runtime dependencies
166
+ (no patched release available). Run `yarn audit` for all dependencies or `yarn audit --groups dependencies` for runtime only.
136
167
 
137
- To add custom gateways, provide class, that extends IGateway to customGateways options
168
+ ## Custom gateways
169
+
170
+ To add a custom gateway, provide a class that implements `IGateway` in `customGateways`.
138
171
 
139
172
  ```typescript
173
+ import { Injectable } from '@nestjs/common';
174
+ import { Content, IGateway } from '@pixelplex/mail-service';
175
+
140
176
  @Injectable()
141
177
  class CustomGateway implements IGateway {
142
178
  async send(to: string, content: Content): Promise<void> {
@@ -144,5 +180,8 @@ class CustomGateway implements IGateway {
144
180
  }
145
181
  }
146
182
 
147
- MailModule.forRoot({ customGateways: [CustomGateway] });
183
+ MailModule.forRoot({
184
+ gateways: ['console'],
185
+ customGateways: [CustomGateway],
186
+ });
148
187
  ```
@@ -7,5 +7,6 @@ export declare enum GATEWAY {
7
7
  SMTP = "smtp",
8
8
  SLACK = "slack",
9
9
  CONSOLE = "console",
10
- SENDGRID = "sendgrid"
10
+ SENDGRID = "sendgrid",
11
+ RESEND = "resend"
11
12
  }
@@ -13,5 +13,6 @@ var GATEWAY;
13
13
  GATEWAY["SLACK"] = "slack";
14
14
  GATEWAY["CONSOLE"] = "console";
15
15
  GATEWAY["SENDGRID"] = "sendgrid";
16
+ GATEWAY["RESEND"] = "resend";
16
17
  })(GATEWAY || (exports.GATEWAY = GATEWAY = {}));
17
18
  //# sourceMappingURL=mail.constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mail.constants.js","sourceRoot":"","sources":["../../src/constants/mail.constants.ts"],"names":[],"mappings":";;;AAAA,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,uDAA8B,CAAA;IAC9B,iEAAwC,CAAA;IACxC,mEAA0C,CAAA;AAC5C,CAAC,EAJW,qBAAqB,qCAArB,qBAAqB,QAIhC;AAED,IAAY,OAKX;AALD,WAAY,OAAO;IACjB,wBAAa,CAAA;IACb,0BAAe,CAAA;IACf,8BAAmB,CAAA;IACnB,gCAAqB,CAAA;AACvB,CAAC,EALW,OAAO,uBAAP,OAAO,QAKlB"}
1
+ {"version":3,"file":"mail.constants.js","sourceRoot":"","sources":["../../src/constants/mail.constants.ts"],"names":[],"mappings":";;;AAAA,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,uDAA8B,CAAA;IAC9B,iEAAwC,CAAA;IACxC,mEAA0C,CAAA;AAC5C,CAAC,EAJW,qBAAqB,qCAArB,qBAAqB,QAIhC;AAED,IAAY,OAMX;AAND,WAAY,OAAO;IACjB,wBAAa,CAAA;IACb,0BAAe,CAAA;IACf,8BAAmB,CAAA;IACnB,gCAAqB,CAAA;IACrB,4BAAiB,CAAA;AACnB,CAAC,EANW,OAAO,uBAAP,OAAO,QAMlB"}
@@ -10,6 +10,7 @@ class GatewayFactory {
10
10
  [constants_1.GATEWAY.CONSOLE]: gateways_1.ConsoleGateway,
11
11
  [constants_1.GATEWAY.SMTP]: gateways_1.SmtpGateway,
12
12
  [constants_1.GATEWAY.SENDGRID]: gateways_1.SendgridGateway,
13
+ [constants_1.GATEWAY.RESEND]: gateways_1.ResendGateway,
13
14
  };
14
15
  return gateways[gateway];
15
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.factory.js","sourceRoot":"","sources":["../../src/factories/gateway.factory.ts"],"names":[],"mappings":";;;AAAA,4CAAuC;AACvC,0CAAyF;AAGzF,MAAa,cAAc;IACzB,MAAM,CAAC,UAAU,CAAC,OAAgB;QAChC,MAAM,QAAQ,GAAG;YACf,CAAC,mBAAO,CAAC,KAAK,CAAC,EAAE,uBAAY;YAC7B,CAAC,mBAAO,CAAC,OAAO,CAAC,EAAE,yBAAc;YACjC,CAAC,mBAAO,CAAC,IAAI,CAAC,EAAE,sBAAW;YAC3B,CAAC,mBAAO,CAAC,QAAQ,CAAC,EAAE,0BAAe;SACpC,CAAC;QAEF,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;CACF;AAXD,wCAWC"}
1
+ {"version":3,"file":"gateway.factory.js","sourceRoot":"","sources":["../../src/factories/gateway.factory.ts"],"names":[],"mappings":";;;AAAA,4CAAuC;AACvC,0CAAwG;AAGxG,MAAa,cAAc;IACzB,MAAM,CAAC,UAAU,CAAC,OAAgB;QAChC,MAAM,QAAQ,GAAG;YACf,CAAC,mBAAO,CAAC,KAAK,CAAC,EAAE,uBAAY;YAC7B,CAAC,mBAAO,CAAC,OAAO,CAAC,EAAE,yBAAc;YACjC,CAAC,mBAAO,CAAC,IAAI,CAAC,EAAE,sBAAW;YAC3B,CAAC,mBAAO,CAAC,QAAQ,CAAC,EAAE,0BAAe;YACnC,CAAC,mBAAO,CAAC,MAAM,CAAC,EAAE,wBAAa;SAChC,CAAC;QAEF,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;CACF;AAZD,wCAYC"}
@@ -1,4 +1,5 @@
1
1
  export * from './console.gateway';
2
+ export * from './resend.gateway';
2
3
  export * from './sendgrid.gateway';
3
4
  export * from './slack.gateway';
4
5
  export * from './smtp.gateway';
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./console.gateway"), exports);
18
+ __exportStar(require("./resend.gateway"), exports);
18
19
  __exportStar(require("./sendgrid.gateway"), exports);
19
20
  __exportStar(require("./slack.gateway"), exports);
20
21
  __exportStar(require("./smtp.gateway"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gateways/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,qDAAmC;AACnC,kDAAgC;AAChC,iDAA+B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gateways/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,mDAAiC;AACjC,qDAAmC;AACnC,kDAAgC;AAChC,iDAA+B"}
@@ -0,0 +1,12 @@
1
+ import { IGateway } from '../interfaces';
2
+ import { Content, ResendOptions } from '../types';
3
+ export declare class ResendGateway implements IGateway {
4
+ private readonly resendOptions;
5
+ private readonly logger;
6
+ private readonly client;
7
+ constructor(resendOptions: ResendOptions);
8
+ send(to: string, content: Content): Promise<void>;
9
+ private prepareAttachments;
10
+ private getAttachmentContent;
11
+ private createSendError;
12
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ResendGateway = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const constants_1 = require("../constants");
18
+ const decorators_1 = require("../decorators");
19
+ const utils_1 = require("../utils");
20
+ const { Resend } = require('resend');
21
+ let ResendGateway = class ResendGateway {
22
+ constructor(resendOptions) {
23
+ this.resendOptions = resendOptions;
24
+ this.logger = new common_1.Logger('Mail::ResendGateway');
25
+ if (!(resendOptions === null || resendOptions === void 0 ? void 0 : resendOptions.apiKey)) {
26
+ throw new Error('Resend gateway requires "resend.apiKey"');
27
+ }
28
+ if (!(resendOptions === null || resendOptions === void 0 ? void 0 : resendOptions.sender)) {
29
+ throw new Error('Resend gateway requires "resend.sender"');
30
+ }
31
+ this.client = new Resend(resendOptions.apiKey);
32
+ }
33
+ async send(to, content) {
34
+ const { error } = await this.client.emails.send(Object.assign(Object.assign({ to, from: this.resendOptions.sender, subject: content.subject, html: content.html }, (content.plain ? { text: content.plain } : {})), (content.attachments ? { attachments: this.prepareAttachments(content.attachments) } : {})));
35
+ if (error) {
36
+ throw this.createSendError(error);
37
+ }
38
+ this.logger.debug(`Message to ${to} sent with resend`);
39
+ }
40
+ prepareAttachments(attachments) {
41
+ return attachments.map((attachment) => ({
42
+ content: this.getAttachmentContent(attachment),
43
+ filename: attachment.filename,
44
+ contentType: attachment.mimeType,
45
+ }));
46
+ }
47
+ getAttachmentContent(attachment) {
48
+ if ((0, utils_1.isBuffer)(attachment.content)) {
49
+ return attachment.content.toString('base64');
50
+ }
51
+ return attachment.encoding === 'base64' ? attachment.content : Buffer.from(attachment.content).toString('base64');
52
+ }
53
+ createSendError(error) {
54
+ const sendError = new Error(`Failed to send mail with resend: ${error.message}`);
55
+ sendError.name = 'ResendGatewayError';
56
+ Object.assign(sendError, { cause: error });
57
+ return sendError;
58
+ }
59
+ };
60
+ exports.ResendGateway = ResendGateway;
61
+ exports.ResendGateway = ResendGateway = __decorate([
62
+ (0, common_1.Injectable)(),
63
+ __param(0, (0, decorators_1.InjectGatewayOptions)(constants_1.GATEWAY.RESEND)),
64
+ __metadata("design:paramtypes", [Object])
65
+ ], ResendGateway);
66
+ //# sourceMappingURL=resend.gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resend.gateway.js","sourceRoot":"","sources":["../../src/gateways/resend.gateway.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { Attachment, Content, SendGridAttachment, SendgridOptions } from '../typ
3
3
  export declare class SendgridGateway implements IGateway {
4
4
  private readonly sendgridOptions;
5
5
  private readonly logger;
6
+ private readonly client;
6
7
  constructor(sendgridOptions: SendgridOptions);
7
8
  send(to: string, content: Content): Promise<void>;
8
9
  prepareAttachments(attachments: Attachment[]): SendGridAttachment[];
@@ -11,13 +11,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
- var __importDefault = (this && this.__importDefault) || function (mod) {
15
- return (mod && mod.__esModule) ? mod : { "default": mod };
16
- };
17
14
  Object.defineProperty(exports, "__esModule", { value: true });
18
15
  exports.SendgridGateway = void 0;
19
16
  const common_1 = require("@nestjs/common");
20
- const mail_1 = __importDefault(require("@sendgrid/mail"));
17
+ const mail_1 = require("@sendgrid/mail");
21
18
  const constants_1 = require("../constants");
22
19
  const decorators_1 = require("../decorators");
23
20
  const utils_1 = require("../utils");
@@ -25,10 +22,19 @@ let SendgridGateway = class SendgridGateway {
25
22
  constructor(sendgridOptions) {
26
23
  this.sendgridOptions = sendgridOptions;
27
24
  this.logger = new common_1.Logger('Mail::SendgridGateway');
28
- mail_1.default.setApiKey(sendgridOptions.apiKey);
25
+ this.client = new mail_1.MailService();
26
+ this.client.setApiKey(sendgridOptions.apiKey);
27
+ if (sendgridOptions.timeoutMs !== undefined) {
28
+ this.client.setTimeout(sendgridOptions.timeoutMs);
29
+ }
29
30
  }
30
31
  async send(to, content) {
31
- await mail_1.default.send(Object.assign({ to, from: this.sendgridOptions.sender, subject: content.subject, html: content.html, text: content.plain }, (content.attachments ? { attachments: this.prepareAttachments(content.attachments) } : {})));
32
+ if (!this.sendgridOptions.apiKey) {
33
+ throw new Error('SendGrid gateway requires "sendgrid.apiKey"');
34
+ }
35
+ await this.client.send(Object.assign(Object.assign(Object.assign({ to, from: this.sendgridOptions.senderName
36
+ ? { email: this.sendgridOptions.sender, name: this.sendgridOptions.senderName }
37
+ : this.sendgridOptions.sender, subject: content.subject, html: content.html, text: content.plain }, (this.sendgridOptions.replyTo ? { replyTo: this.sendgridOptions.replyTo } : {})), (this.sendgridOptions.trackingSettings ? { trackingSettings: this.sendgridOptions.trackingSettings } : {})), (content.attachments ? { attachments: this.prepareAttachments(content.attachments) } : {})));
32
38
  this.logger.debug(`Message to ${to} sent with sendgrid`);
33
39
  }
34
40
  prepareAttachments(attachments) {
@@ -1 +1 @@
1
- {"version":3,"file":"sendgrid.gateway.js","sourceRoot":"","sources":["../../src/gateways/sendgrid.gateway.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,0DAAoC;AAEpC,4CAAuC;AACvC,8CAAqD;AAGrD,oCAAoC;AAG7B,IAAM,eAAe,GAArB,MAAM,eAAe;IAG1B,YAAoD,eAAiD;QAAhC,oBAAe,GAAf,eAAe,CAAiB;QAFpF,WAAM,GAAG,IAAI,eAAM,CAAC,uBAAuB,CAAC,CAAC;QAG5D,cAAM,CAAC,SAAS,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAU,EAAE,OAAgB;QACrC,MAAM,cAAM,CAAC,IAAI,iBACf,EAAE,EACF,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM,EACjC,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,IAAI,EAAE,OAAO,CAAC,KAAK,IAChB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC7F,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IAC3D,CAAC;IAED,kBAAkB,CAAC,WAAyB;QAC1C,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACtC,OAAO,EAAE,IAAA,gBAAQ,EAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO;YAClG,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,IAAI,EAAE,UAAU,CAAC,QAAQ;SAC1B,CAAC,CAAC,CAAC;IACN,CAAC;CACF,CAAA;AA3BY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;IAIE,WAAA,IAAA,iCAAoB,EAAC,mBAAO,CAAC,QAAQ,CAAC,CAAA;;GAHxC,eAAe,CA2B3B"}
1
+ {"version":3,"file":"sendgrid.gateway.js","sourceRoot":"","sources":["../../src/gateways/sendgrid.gateway.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,yCAA6C;AAE7C,4CAAuC;AACvC,8CAAqD;AAGrD,oCAAoC;AAG7B,IAAM,eAAe,GAArB,MAAM,eAAe;IAI1B,YAAoD,eAAiD;QAAhC,oBAAe,GAAf,eAAe,CAAiB;QAHpF,WAAM,GAAG,IAAI,eAAM,CAAC,uBAAuB,CAAC,CAAC;QAC7C,WAAM,GAAG,IAAI,kBAAW,EAAE,CAAC;QAG1C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAE9C,IAAI,eAAe,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAU,EAAE,OAAgB;QACrC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QAED,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,6CACpB,EAAE,EACF,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,UAAU;gBACnC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE;gBAC/E,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAC/B,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,IAAI,EAAE,OAAO,CAAC,KAAK,IAChB,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC/E,CAAC,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC1G,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC7F,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IAC3D,CAAC;IAED,kBAAkB,CAAC,WAAyB;QAC1C,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACtC,OAAO,EAAE,IAAA,gBAAQ,EAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO;YAClG,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,IAAI,EAAE,UAAU,CAAC,QAAQ;SAC1B,CAAC,CAAC,CAAC;IACN,CAAC;CACF,CAAA;AAxCY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;IAKE,WAAA,IAAA,iCAAoB,EAAC,mBAAO,CAAC,QAAQ,CAAC,CAAA;;GAJxC,eAAe,CAwC3B"}
@@ -2,6 +2,7 @@ export * from './mail.types';
2
2
  export * from './decorators.types';
3
3
  export * from './gateway.class';
4
4
  export * from './options.types';
5
+ export * from './resend.types';
5
6
  export * from './sendgrid.types';
6
7
  export * from './slack.types';
7
8
  export * from './smtp.types';
@@ -18,6 +18,7 @@ __exportStar(require("./mail.types"), exports);
18
18
  __exportStar(require("./decorators.types"), exports);
19
19
  __exportStar(require("./gateway.class"), exports);
20
20
  __exportStar(require("./options.types"), exports);
21
+ __exportStar(require("./resend.types"), exports);
21
22
  __exportStar(require("./sendgrid.types"), exports);
22
23
  __exportStar(require("./slack.types"), exports);
23
24
  __exportStar(require("./smtp.types"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,qDAAmC;AACnC,kDAAgC;AAChC,kDAAgC;AAChC,mDAAiC;AACjC,gDAA8B;AAC9B,+CAA6B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,qDAAmC;AACnC,kDAAgC;AAChC,kDAAgC;AAChC,iDAA+B;AAC/B,mDAAiC;AACjC,gDAA8B;AAC9B,+CAA6B"}
@@ -1,9 +1,10 @@
1
1
  import { ExtendsOrEmpty } from '../utils';
2
2
  import { GatewayClass } from './gateway.class';
3
+ import { ResendOptions } from './resend.types';
3
4
  import { SendgridOptions } from './sendgrid.types';
4
5
  import { SlackOptions } from './slack.types';
5
6
  import { SmtpOptions } from './smtp.types';
6
- export type Gateway = 'smtp' | 'console' | 'slack' | 'sendgrid';
7
+ export type Gateway = 'smtp' | 'console' | 'slack' | 'sendgrid' | 'resend';
7
8
  export type MailOptions<TGateway extends Gateway = Gateway> = {
8
9
  readonly gateways: [TGateway, ...TGateway[]];
9
10
  readonly customGateways?: [GatewayClass, ...GatewayClass[]];
@@ -13,4 +14,6 @@ export type MailOptions<TGateway extends Gateway = Gateway> = {
13
14
  slack: SlackOptions;
14
15
  }> & ExtendsOrEmpty<'sendgrid', TGateway, {
15
16
  sendgrid: SendgridOptions;
17
+ }> & ExtendsOrEmpty<'resend', TGateway, {
18
+ resend: ResendOptions;
16
19
  }>;
@@ -0,0 +1,4 @@
1
+ export type ResendOptions = {
2
+ readonly apiKey: string;
3
+ readonly sender: string;
4
+ };
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=resend.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resend.types.js","sourceRoot":"","sources":["../../src/types/resend.types.ts"],"names":[],"mappings":""}
@@ -1,6 +1,11 @@
1
+ import type { MailDataRequired } from '@sendgrid/mail';
1
2
  export type SendgridOptions = {
2
3
  readonly apiKey: string;
3
4
  readonly sender: string;
5
+ readonly senderName?: string;
6
+ readonly replyTo?: string;
7
+ readonly timeoutMs?: number;
8
+ readonly trackingSettings?: MailDataRequired['trackingSettings'];
4
9
  };
5
10
  export type SendGridAttachment = {
6
11
  content: string;