@deenruv/email-plugin 1.0.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.
Files changed (76) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +85 -0
  3. package/dev-mailbox.html +218 -0
  4. package/lib/index.d.ts +13 -0
  5. package/lib/index.js +30 -0
  6. package/lib/index.js.map +1 -0
  7. package/lib/src/attachment-utils.d.ts +3 -0
  8. package/lib/src/attachment-utils.js +66 -0
  9. package/lib/src/attachment-utils.js.map +1 -0
  10. package/lib/src/common.d.ts +4 -0
  11. package/lib/src/common.js +17 -0
  12. package/lib/src/common.js.map +1 -0
  13. package/lib/src/constants.d.ts +2 -0
  14. package/lib/src/constants.js +6 -0
  15. package/lib/src/constants.js.map +1 -0
  16. package/lib/src/dev-mailbox.d.ts +14 -0
  17. package/lib/src/dev-mailbox.js +116 -0
  18. package/lib/src/dev-mailbox.js.map +1 -0
  19. package/lib/src/email-processor.d.ts +21 -0
  20. package/lib/src/email-processor.js +109 -0
  21. package/lib/src/email-processor.js.map +1 -0
  22. package/lib/src/email-send-event.d.ts +18 -0
  23. package/lib/src/email-send-event.js +24 -0
  24. package/lib/src/email-send-event.js.map +1 -0
  25. package/lib/src/event-listener.d.ts +19 -0
  26. package/lib/src/event-listener.js +25 -0
  27. package/lib/src/event-listener.js.map +1 -0
  28. package/lib/src/generator/email-generator.d.ts +25 -0
  29. package/lib/src/generator/email-generator.js +3 -0
  30. package/lib/src/generator/email-generator.js.map +1 -0
  31. package/lib/src/generator/handlebars-mjml-generator.d.ts +19 -0
  32. package/lib/src/generator/handlebars-mjml-generator.js +78 -0
  33. package/lib/src/generator/handlebars-mjml-generator.js.map +1 -0
  34. package/lib/src/generator/noop-email-generator.d.ts +11 -0
  35. package/lib/src/generator/noop-email-generator.js +13 -0
  36. package/lib/src/generator/noop-email-generator.js.map +1 -0
  37. package/lib/src/generator/react-email-generator.d.ts +7 -0
  38. package/lib/src/generator/react-email-generator.js +40 -0
  39. package/lib/src/generator/react-email-generator.js.map +1 -0
  40. package/lib/src/handler/default-email-handlers.d.ts +32 -0
  41. package/lib/src/handler/default-email-handlers.js +111 -0
  42. package/lib/src/handler/default-email-handlers.js.map +1 -0
  43. package/lib/src/handler/event-handler.d.ts +276 -0
  44. package/lib/src/handler/event-handler.js +396 -0
  45. package/lib/src/handler/event-handler.js.map +1 -0
  46. package/lib/src/handler/mock-events.d.ts +5 -0
  47. package/lib/src/handler/mock-events.js +119 -0
  48. package/lib/src/handler/mock-events.js.map +1 -0
  49. package/lib/src/plugin.d.ts +301 -0
  50. package/lib/src/plugin.js +428 -0
  51. package/lib/src/plugin.js.map +1 -0
  52. package/lib/src/sender/email-sender.d.ts +45 -0
  53. package/lib/src/sender/email-sender.js +3 -0
  54. package/lib/src/sender/email-sender.js.map +1 -0
  55. package/lib/src/sender/nodemailer-email-sender.d.ts +37 -0
  56. package/lib/src/sender/nodemailer-email-sender.js +151 -0
  57. package/lib/src/sender/nodemailer-email-sender.js.map +1 -0
  58. package/lib/src/template-loader/file-based-template-loader.d.ts +17 -0
  59. package/lib/src/template-loader/file-based-template-loader.js +37 -0
  60. package/lib/src/template-loader/file-based-template-loader.js.map +1 -0
  61. package/lib/src/template-loader/react-email-template-loader.d.ts +6 -0
  62. package/lib/src/template-loader/react-email-template-loader.js +14 -0
  63. package/lib/src/template-loader/react-email-template-loader.js.map +1 -0
  64. package/lib/src/template-loader/template-loader.d.ts +42 -0
  65. package/lib/src/template-loader/template-loader.js +3 -0
  66. package/lib/src/template-loader/template-loader.js.map +1 -0
  67. package/lib/src/types.d.ts +453 -0
  68. package/lib/src/types.js +3 -0
  69. package/lib/src/types.js.map +1 -0
  70. package/package.json +51 -0
  71. package/templates/email-address-change/body.hbs +20 -0
  72. package/templates/email-verification/body.hbs +20 -0
  73. package/templates/order-confirmation/body.hbs +133 -0
  74. package/templates/partials/footer.hbs +10 -0
  75. package/templates/partials/header.hbs +18 -0
  76. package/templates/password-reset/body.hbs +24 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nodemailer-email-sender.js","sourceRoot":"","sources":["../../../src/sender/nodemailer-email-sender.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { Injector, RequestContext } from "@deenruv/core";
2
+ import { LoadTemplateInput, Partial } from "../types";
3
+ import { TemplateLoader } from "./template-loader";
4
+ /**
5
+ * @description
6
+ * Loads email templates from the local file system. This is the default
7
+ * loader used by the EmailPlugin.
8
+ *
9
+ * @docsCategory core plugins/EmailPlugin
10
+ * @docsPage TemplateLoader
11
+ */
12
+ export declare class FileBasedTemplateLoader implements TemplateLoader {
13
+ private templatePath;
14
+ constructor(templatePath: string);
15
+ loadTemplate(_injector: Injector, _ctx: RequestContext, { type, templateName }: LoadTemplateInput): Promise<string>;
16
+ loadPartials(): Promise<Partial[]>;
17
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FileBasedTemplateLoader = void 0;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const path_1 = __importDefault(require("path"));
9
+ /**
10
+ * @description
11
+ * Loads email templates from the local file system. This is the default
12
+ * loader used by the EmailPlugin.
13
+ *
14
+ * @docsCategory core plugins/EmailPlugin
15
+ * @docsPage TemplateLoader
16
+ */
17
+ class FileBasedTemplateLoader {
18
+ constructor(templatePath) {
19
+ this.templatePath = templatePath;
20
+ }
21
+ async loadTemplate(_injector, _ctx, { type, templateName }) {
22
+ const templatePath = path_1.default.join(this.templatePath, type, templateName);
23
+ return promises_1.default.readFile(templatePath, "utf-8");
24
+ }
25
+ async loadPartials() {
26
+ const partialsPath = path_1.default.join(this.templatePath, "partials");
27
+ const partialsFiles = await promises_1.default.readdir(partialsPath);
28
+ return Promise.all(partialsFiles.map(async (file) => {
29
+ return {
30
+ name: path_1.default.basename(file, ".hbs"),
31
+ content: await promises_1.default.readFile(path_1.default.join(partialsPath, file), "utf-8"),
32
+ };
33
+ }));
34
+ }
35
+ }
36
+ exports.FileBasedTemplateLoader = FileBasedTemplateLoader;
37
+ //# sourceMappingURL=file-based-template-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-based-template-loader.js","sourceRoot":"","sources":["../../../src/template-loader/file-based-template-loader.ts"],"names":[],"mappings":";;;;;;AACA,2DAA6B;AAC7B,gDAAwB;AAMxB;;;;;;;GAOG;AACH,MAAa,uBAAuB;IAClC,YAAoB,YAAoB;QAApB,iBAAY,GAAZ,YAAY,CAAQ;IAAG,CAAC;IAE5C,KAAK,CAAC,YAAY,CAChB,SAAmB,EACnB,IAAoB,EACpB,EAAE,IAAI,EAAE,YAAY,EAAqB;QAEzC,MAAM,YAAY,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;QACtE,OAAO,kBAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,YAAY,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAC9D,MAAM,aAAa,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACrD,OAAO,OAAO,CAAC,GAAG,CAChB,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YAC/B,OAAO;gBACL,IAAI,EAAE,cAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBACjC,OAAO,EAAE,MAAM,kBAAE,CAAC,QAAQ,CAAC,cAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC;aACnE,CAAC;QACJ,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;CACF;AAxBD,0DAwBC"}
@@ -0,0 +1,6 @@
1
+ import { Injector, RequestContext } from "@deenruv/core";
2
+ import { TemplateLoader } from "./template-loader.js";
3
+ import { LoadTemplateInput } from "../types.js";
4
+ export declare class ReactComponentLoader implements TemplateLoader {
5
+ loadTemplate(_1: Injector, ctx: RequestContext, { type }: LoadTemplateInput): Promise<string>;
6
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReactComponentLoader = void 0;
4
+ class ReactComponentLoader {
5
+ async loadTemplate(_1, ctx, { type }) {
6
+ const template = {
7
+ type,
8
+ ctx: ctx.serialize(),
9
+ };
10
+ return JSON.stringify(template);
11
+ }
12
+ }
13
+ exports.ReactComponentLoader = ReactComponentLoader;
14
+ //# sourceMappingURL=react-email-template-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-email-template-loader.js","sourceRoot":"","sources":["../../../src/template-loader/react-email-template-loader.ts"],"names":[],"mappings":";;;AAKA,MAAa,oBAAoB;IAC/B,KAAK,CAAC,YAAY,CAChB,EAAY,EACZ,GAAmB,EACnB,EAAE,IAAI,EAAqB;QAE3B,MAAM,QAAQ,GAAe;YAC3B,IAAI;YACJ,GAAG,EAAE,GAAG,CAAC,SAAS,EAAE;SACrB,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;CACF;AAZD,oDAYC"}
@@ -0,0 +1,42 @@
1
+ import { Injector, RequestContext } from "@deenruv/core";
2
+ import { LoadTemplateInput, Partial } from "../types";
3
+ /**
4
+ * @description
5
+ * Loads email templates based on the given request context, type and template name
6
+ * and return the template as a string.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { EmailPlugin, TemplateLoader } from '\@deenruv/email-plugin';
11
+ *
12
+ * class MyTemplateLoader implements TemplateLoader {
13
+ * loadTemplate(injector, ctx, { type, templateName }){
14
+ * return myCustomTemplateFunction(ctx);
15
+ * }
16
+ * }
17
+ *
18
+ * // In deenruv-config.ts:
19
+ * ...
20
+ * EmailPlugin.init({
21
+ * templateLoader: new MyTemplateLoader()
22
+ * ...
23
+ * })
24
+ * ```
25
+ *
26
+ * @docsCategory core plugins/EmailPlugin
27
+ * @docsPage TemplateLoader
28
+ * @docsWeight 0
29
+ */
30
+ export interface TemplateLoader {
31
+ /**
32
+ * @description
33
+ * Load template and return it's content as a string
34
+ */
35
+ loadTemplate(injector: Injector, ctx: RequestContext, input: LoadTemplateInput): Promise<string>;
36
+ /**
37
+ * @description
38
+ * Load partials and return their contents.
39
+ * This method is only called during initialization, i.e. during server startup.
40
+ */
41
+ loadPartials?(): Promise<Partial[]>;
42
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=template-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-loader.js","sourceRoot":"","sources":["../../../src/template-loader/template-loader.ts"],"names":[],"mappings":""}
@@ -0,0 +1,453 @@
1
+ import { LanguageCode } from "@deenruv/common/lib/generated-types";
2
+ import { Omit } from "@deenruv/common/lib/omit";
3
+ import { Injector, RequestContext, SerializedRequestContext, DeenruvEvent } from "@deenruv/core";
4
+ import { Attachment } from "nodemailer/lib/mailer";
5
+ import SESTransport from "nodemailer/lib/ses-transport";
6
+ import SMTPTransport from "nodemailer/lib/smtp-transport";
7
+ import { EmailGenerator } from "./generator/email-generator";
8
+ import { EmailEventHandler } from "./handler/event-handler";
9
+ import { EmailSender } from "./sender/email-sender";
10
+ import { TemplateLoader } from "./template-loader/template-loader";
11
+ import type { FC } from "react";
12
+ /**
13
+ * @description
14
+ * A DeenruvEvent which also includes a `ctx` property containing the current
15
+ * {@link RequestContext}, which is used to determine the channel and language
16
+ * to use when generating the email.
17
+ *
18
+ * @docsCategory core plugins/EmailPlugin
19
+ * @docsPage Email Plugin Types
20
+ */
21
+ export type EventWithContext = DeenruvEvent & {
22
+ ctx: RequestContext;
23
+ };
24
+ /**
25
+ * @description
26
+ * A DeenruvEvent with a {@link RequestContext} and a `data` property which contains the
27
+ * value resolved from the {@link EmailEventHandler}`.loadData()` callback.
28
+ *
29
+ * @docsCategory core plugins/EmailPlugin
30
+ * @docsPage Email Plugin Types
31
+ */
32
+ export type EventWithAsyncData<Event extends EventWithContext, R> = Event & {
33
+ data: R;
34
+ };
35
+ /**
36
+ * @description
37
+ * Allows you to dynamically load the "globalTemplateVars" key async and access Deenruv services
38
+ * to create the object. This is not a requirement. You can also specify a simple static object if your
39
+ * projects doesn't need to access async or dynamic values.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ *
44
+ * EmailPlugin.init({
45
+ * globalTemplateVars: async (ctx, injector) => {
46
+ * const myAsyncService = injector.get(MyAsyncService);
47
+ * const asyncValue = await myAsyncService.get(ctx);
48
+ * const channel = ctx.channel;
49
+ * const { primaryColor } = channel.customFields.theme;
50
+ * const theme = {
51
+ * primaryColor,
52
+ * asyncValue,
53
+ * };
54
+ * return theme;
55
+ * }
56
+ * [...]
57
+ * })
58
+ *
59
+ * ```
60
+ *
61
+ * @docsCategory core plugins/EmailPlugin
62
+ * @docsPage EmailPluginOptions
63
+ * @since 2.3.0
64
+ */
65
+ export type GlobalTemplateVarsFn = (ctx: RequestContext, injector: Injector) => Promise<{
66
+ [key: string]: any;
67
+ }>;
68
+ /**
69
+ * @description
70
+ * Configuration for the EmailPlugin.
71
+ *
72
+ * @docsCategory core plugins/EmailPlugin
73
+ * @docsPage EmailPluginOptions
74
+ * @docsWeight 0
75
+ * */
76
+ export interface EmailPluginOptions {
77
+ /**
78
+ * @description
79
+ * Boolean flag to indicate whether the email templates are written in react-email, and should be handled by it .
80
+ */
81
+ useReactEmail?: boolean;
82
+ /**
83
+ * @description
84
+ * The path to the location of the email templates. In a default Deenruv installation,
85
+ * the templates are installed to `<project root>/deenruv/email/templates`.
86
+ *
87
+ * @deprecated Use `templateLoader` to define a template path: `templateLoader: new FileBasedTemplateLoader('../your-path/templates')`
88
+ */
89
+ templatePath?: string;
90
+ /**
91
+ * @description
92
+ * An optional TemplateLoader which can be used to load templates from a custom location or async service.
93
+ * The default uses the FileBasedTemplateLoader which loads templates from `<project root>/deenruv/email/templates`
94
+ *
95
+ * @since 2.0.0
96
+ */
97
+ templateLoader?: TemplateLoader;
98
+ /**
99
+ * @description
100
+ * Configures how the emails are sent.
101
+ */
102
+ transport: EmailTransportOptions | ((injector?: Injector, ctx?: RequestContext) => EmailTransportOptions | Promise<EmailTransportOptions>);
103
+ /**
104
+ * @description
105
+ * An array of {@link EmailEventHandler}s which define which Deenruv events will trigger
106
+ * emails, and how those emails are generated.
107
+ */
108
+ handlers: Array<EmailEventHandler<string, any>>;
109
+ /**
110
+ * @description
111
+ * An object containing variables which are made available to all templates. For example,
112
+ * the storefront URL could be defined here and then used in the "email address verification"
113
+ * email. Use the GlobalTemplateVarsFn if you need to retrieve variables from Deenruv or
114
+ * plugin services.
115
+ */
116
+ globalTemplateVars?: {
117
+ [key: string]: any;
118
+ } | GlobalTemplateVarsFn;
119
+ /**
120
+ * @description
121
+ * An optional allowed EmailSender, used to allow custom implementations of the send functionality
122
+ * while still utilizing the existing emailPlugin functionality.
123
+ *
124
+ * @default NodemailerEmailSender
125
+ */
126
+ emailSender?: EmailSender;
127
+ /**
128
+ * @description
129
+ * An optional allowed EmailGenerator, used to allow custom email generation functionality to
130
+ * better match with custom email sending functionality.
131
+ *
132
+ * @default HandlebarsMjmlGenerator
133
+ */
134
+ emailGenerator?: EmailGenerator;
135
+ }
136
+ /**
137
+ * EmailPLuginOptions type after initialization, where templateLoader and themeInjector are no longer optional
138
+ */
139
+ export type InitializedEmailPluginOptions = EmailPluginOptions & {
140
+ templateLoader: TemplateLoader;
141
+ };
142
+ /**
143
+ * @description
144
+ * Configuration for running the EmailPlugin in development mode.
145
+ *
146
+ * @docsCategory core plugins/EmailPlugin
147
+ * @docsPage EmailPluginOptions
148
+ */
149
+ export interface EmailPluginDevModeOptions extends Omit<EmailPluginOptions, "transport"> {
150
+ devMode: true;
151
+ /**
152
+ * @description
153
+ * The path to which html email files will be saved rather than being sent.
154
+ */
155
+ outputPath: string;
156
+ /**
157
+ * @description
158
+ * The route to the dev mailbox server.
159
+ */
160
+ route: string;
161
+ }
162
+ /**
163
+ * @description
164
+ * A union of all the possible transport options for sending emails.
165
+ *
166
+ * @docsCategory core plugins/EmailPlugin
167
+ * @docsPage Transport Options
168
+ */
169
+ export type EmailTransportOptions = SMTPTransportOptions | SendmailTransportOptions | FileTransportOptions | NoopTransportOptions | SESTransportOptions | TestingTransportOptions;
170
+ /**
171
+ * @description
172
+ * The SMTP transport options of [Nodemailer](https://nodemailer.com/smtp/)
173
+ *
174
+ * @docsCategory core plugins/EmailPlugin
175
+ * @docsPage Transport Options
176
+ */
177
+ export interface SMTPTransportOptions extends SMTPTransport.Options {
178
+ type: "smtp";
179
+ /**
180
+ * @description
181
+ * If true, uses the configured {@link DeenruvLogger} to log messages from Nodemailer as it interacts with
182
+ * the SMTP server.
183
+ *
184
+ * @default false
185
+ */
186
+ logging?: boolean;
187
+ }
188
+ /**
189
+ * @description
190
+ * The SES transport options of [Nodemailer](https://nodemailer.com/transports/ses//)
191
+ *
192
+ * See [Nodemailers's SES docs](https://nodemailer.com/transports/ses/) for more details
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * import { SES, SendRawEmailCommand } from '\@aws-sdk/client-ses'
197
+ *
198
+ * const ses = new SES({
199
+ * apiVersion: '2010-12-01',
200
+ * region: 'eu-central-1',
201
+ * credentials: {
202
+ * accessKeyId: process.env.SES_ACCESS_KEY || '',
203
+ * secretAccessKey: process.env.SES_SECRET_KEY || '',
204
+ * },
205
+ * })
206
+ *
207
+ * const config: DeenruvConfig = {
208
+ * // Add an instance of the plugin to the plugins array
209
+ * plugins: [
210
+ * EmailPlugin.init({
211
+ * handler: defaultEmailHandlers,
212
+ * templatePath: path.join(__dirname, 'static/email/templates'),
213
+ * transport: {
214
+ * type: 'ses',
215
+ * SES: { ses, aws: { SendRawEmailCommand } },
216
+ * sendingRate: 10, // optional messages per second sending rate
217
+ * },
218
+ * }),
219
+ * ],
220
+ * };
221
+ * ```
222
+ * @docsCategory core plugins/EmailPlugin
223
+ * @docsPage Transport Options
224
+ */
225
+ export interface SESTransportOptions extends SESTransport.Options {
226
+ type: "ses";
227
+ }
228
+ /**
229
+ * @description
230
+ * Uses the local Sendmail program to send the email.
231
+ *
232
+ * @docsCategory core plugins/EmailPlugin
233
+ * @docsPage Transport Options
234
+ */
235
+ export interface SendmailTransportOptions {
236
+ type: "sendmail";
237
+ /** path to the sendmail command (defaults to ‘sendmail’) */
238
+ path?: string;
239
+ /** either ‘windows’ or ‘unix’ (default). Forces all newlines in the output to either use Windows syntax <CR><LF> or Unix syntax <LF> */
240
+ newline?: string;
241
+ }
242
+ /**
243
+ * @description
244
+ * Outputs the email as an HTML file for development purposes.
245
+ *
246
+ * @docsCategory core plugins/EmailPlugin
247
+ * @docsPage Transport Options
248
+ */
249
+ export interface FileTransportOptions {
250
+ type: "file";
251
+ /** The directory in which the emails will be saved */
252
+ outputPath: string;
253
+ /** When set to true, a raw text file will be output rather than an HTML file */
254
+ raw?: boolean;
255
+ }
256
+ /**
257
+ * @description
258
+ * Does nothing with the generated email. Intended for use in testing where we don't care about the email transport,
259
+ * or when using a custom {@link EmailSender} which does not require transport options.
260
+ *
261
+ * @docsCategory core plugins/EmailPlugin
262
+ * @docsPage Transport Options
263
+ */
264
+ export interface NoopTransportOptions {
265
+ type: "none";
266
+ }
267
+ /**
268
+ * @description
269
+ * The final, generated email details to be sent.
270
+ *
271
+ * @docsCategory core plugins/EmailPlugin
272
+ * @docsPage Email Plugin Types
273
+ */
274
+ export interface EmailDetails<Type extends "serialized" | "unserialized" = "unserialized"> {
275
+ from: string;
276
+ recipient: string;
277
+ subject: string;
278
+ body: string;
279
+ attachments: Array<Type extends "serialized" ? SerializedAttachment : Attachment>;
280
+ cc?: string;
281
+ bcc?: string;
282
+ replyTo?: string;
283
+ }
284
+ /**
285
+ * @description
286
+ * Forwards the raw GeneratedEmailContext object to a provided callback, for use in testing.
287
+ *
288
+ * @docsCategory core plugins/EmailPlugin
289
+ * @docsPage Transport Options
290
+ */
291
+ export interface TestingTransportOptions {
292
+ type: "testing";
293
+ /**
294
+ * @description
295
+ * Callback to be invoked when an email would be sent.
296
+ */
297
+ onSend: (details: EmailDetails) => void;
298
+ }
299
+ /**
300
+ * @description
301
+ * A function used to load async data for use by an {@link EmailEventHandler}.
302
+ *
303
+ * @docsCategory core plugins/EmailPlugin
304
+ * @docsPage Email Plugin Types
305
+ */
306
+ export type LoadDataFn<Event extends EventWithContext, R> = (context: {
307
+ event: Event;
308
+ injector: Injector;
309
+ }) => Promise<R>;
310
+ export type OptionalToNullable<O> = {
311
+ [K in keyof O]-?: undefined extends O[K] ? NonNullable<O[K]> | null : O[K];
312
+ };
313
+ /**
314
+ * @description
315
+ * An object defining a file attachment for an email. Based on the object described
316
+ * [here in the Nodemailer docs](https://nodemailer.com/message/attachments/), but
317
+ * only uses the `path` property to define a filesystem path or a URL pointing to
318
+ * the attachment file.
319
+ *
320
+ * @docsCategory core plugins/EmailPlugin
321
+ * @docsPage Email Plugin Types
322
+ */
323
+ export type EmailAttachment = Omit<Attachment, "raw"> & {
324
+ path?: string;
325
+ };
326
+ export type SerializedAttachment = OptionalToNullable<Omit<EmailAttachment, "content"> & {
327
+ content: string | null;
328
+ }>;
329
+ export type IntermediateEmailDetails = {
330
+ ctx: SerializedRequestContext;
331
+ type: string;
332
+ from: string;
333
+ recipient: string;
334
+ templateVars: any;
335
+ subject: string;
336
+ templateFile: string;
337
+ attachments: SerializedAttachment[];
338
+ cc?: string;
339
+ bcc?: string;
340
+ replyTo?: string;
341
+ };
342
+ /**
343
+ * @description
344
+ * Configures the {@link EmailEventHandler} to handle a particular channel & languageCode
345
+ * combination.
346
+ *
347
+ * @deprecated Use a custom {@link TemplateLoader} instead.
348
+ */
349
+ export interface EmailTemplateConfig {
350
+ /**
351
+ * @description
352
+ * Specifies the channel to which this configuration will apply. If set to `'default'`, it will be applied to all
353
+ * channels.
354
+ */
355
+ channelCode: string | "default";
356
+ /**
357
+ * @description
358
+ * Specifies the languageCode to which this configuration will apply. If set to `'default'`, it will be applied to all
359
+ * languages.
360
+ */
361
+ languageCode: LanguageCode | "default";
362
+ /**
363
+ * @description
364
+ * Defines the file name of the Handlebars template file to be used to when generating this email.
365
+ */
366
+ templateFile: string;
367
+ /**
368
+ * @description
369
+ * A string defining the email subject line. Handlebars variables defined in the `templateVars` object may
370
+ * be used inside the subject.
371
+ */
372
+ subject: string;
373
+ }
374
+ export interface LoadTemplateInput {
375
+ type: string;
376
+ templateName: string;
377
+ templateVars: any;
378
+ }
379
+ export interface Partial {
380
+ name: string;
381
+ content: string;
382
+ }
383
+ /**
384
+ * @description
385
+ * A function used to define template variables available to email templates.
386
+ * See {@link EmailEventHandler}.setTemplateVars().
387
+ *
388
+ * @docsCategory core plugins/EmailPlugin
389
+ * @docsPage Email Plugin Types
390
+ */
391
+ export type SetTemplateVarsFn<Event> = (event: Event, globals: {
392
+ [key: string]: any;
393
+ }) => {
394
+ [key: string]: any;
395
+ };
396
+ /**
397
+ * @description
398
+ * A function used to define attachments to be sent with the email.
399
+ * See https://nodemailer.com/message/attachments/ for more information about
400
+ * how attachments work in Nodemailer.
401
+ *
402
+ * @docsCategory core plugins/EmailPlugin
403
+ * @docsPage Email Plugin Types
404
+ */
405
+ export type SetAttachmentsFn<Event> = (event: Event) => EmailAttachment[] | Promise<EmailAttachment[]>;
406
+ /**
407
+ * @description
408
+ * A function used to define the subject to be sent with the email.
409
+ * @docsCategory core plugins/EmailPlugin
410
+ * @docsPage Email Plugin Types
411
+ */
412
+ export type SetSubjectFn<Event> = (event: Event, ctx: RequestContext, injector: Injector) => string | Promise<string>;
413
+ /**
414
+ * @description
415
+ * Optional address-related fields for sending the email.
416
+ *
417
+ * @since 1.1.0
418
+ * @docsCategory core plugins/EmailPlugin
419
+ * @docsPage Email Plugin Types
420
+ */
421
+ export interface OptionalAddressFields {
422
+ /**
423
+ * @description
424
+ * Comma separated list of recipients email addresses that will appear on the _Cc:_ field
425
+ */
426
+ cc?: string;
427
+ /**
428
+ * @description
429
+ * Comma separated list of recipients email addresses that will appear on the _Bcc:_ field
430
+ */
431
+ bcc?: string;
432
+ /**
433
+ * @description
434
+ * An email address that will appear on the _Reply-To:_ field
435
+ */
436
+ replyTo?: string;
437
+ }
438
+ /**
439
+ * @description
440
+ * A function used to set the {@link OptionalAddressFields}.
441
+ *
442
+ * @since 1.1.0
443
+ * @docsCategory core plugins/EmailPlugin
444
+ * @docsPage Email Plugin Types
445
+ */
446
+ export type SetOptionalAddressFieldsFn<Event> = (event: Event) => OptionalAddressFields | Promise<OptionalAddressFields>;
447
+ export interface LoaderBody {
448
+ type: string;
449
+ ctx: SerializedRequestContext;
450
+ }
451
+ export interface ReactEmailSenderPluginOptions {
452
+ templates: Record<string, (ctx: RequestContext) => FC<any>>;
453
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@deenruv/email-plugin",
3
+ "version": "1.0.0",
4
+ "license": "MIT",
5
+ "main": "lib/index.js",
6
+ "types": "lib/index.d.ts",
7
+ "files": [
8
+ "lib/**/*",
9
+ "templates/**/*",
10
+ "dev-mailbox.html"
11
+ ],
12
+ "homepage": "https://deenruv.com/",
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "dependencies": {
17
+ "@nestjs/common": "^10.3.10",
18
+ "@types/nodemailer": "^6.4.9",
19
+ "dateformat": "^3.0.3",
20
+ "express": "^4.18.2",
21
+ "fs-extra": "^11.2.0",
22
+ "handlebars": "^4.7.8",
23
+ "mjml": "^4.14.1",
24
+ "nodemailer": "^6.9.4",
25
+ "react-email": "4.0.3",
26
+ "@react-email/components": "^0.0.35",
27
+ "@react-email/render": "1.0.5",
28
+ "@deenruv/common": "^1.0.0"
29
+ },
30
+ "peerDependencies": {
31
+ "@deenruv/core": "^0.1.0",
32
+ "@nestjs/core": "^10.3.10"
33
+ },
34
+ "devDependencies": {
35
+ "@types/dateformat": "^3.0.1",
36
+ "@types/express": "^4.17.21",
37
+ "@types/fs-extra": "^11.0.4",
38
+ "@types/mjml": "^4.7.4",
39
+ "rimraf": "^5.0.5",
40
+ "typescript": "5.3.3",
41
+ "@types/react": "^18.2.0",
42
+ "@deenruv/core": "^1.0.0"
43
+ },
44
+ "scripts": {
45
+ "watch": "tsc -p ./tsconfig.build.json --watch",
46
+ "build": "rimraf lib && tsc -p ./tsconfig.build.json",
47
+ "lint": "eslint .",
48
+ "lint:fix": "eslint --fix .",
49
+ "test": "vitest --config vitest.config.mts --run"
50
+ }
51
+ }
@@ -0,0 +1,20 @@
1
+ {{> header title="Verify Your New Email Address" }}
2
+
3
+ <mj-section background-color="#fafafa">
4
+ <mj-column>
5
+ <mj-text color="#525252">
6
+ We received a request to change your registered email address to this one.
7
+ Click the button below to verify this address and complete the process:
8
+ </mj-text>
9
+
10
+ <mj-button font-family="Helvetica"
11
+ background-color="#f45e43"
12
+ color="white"
13
+ href="{{ changeEmailAddressUrl }}?token={{ identifierChangeToken }}">
14
+ Verify Me!
15
+ </mj-button>
16
+ </mj-column>
17
+ </mj-section>
18
+
19
+
20
+ {{> footer }}