nuxt-mail 7.0.1 → 8.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.
package/README.md CHANGED
@@ -71,11 +71,11 @@ $ yarn nuxi module add nuxt-mail
71
71
 
72
72
  ## Configuration
73
73
 
74
- Add the module to the `modules` array in your `nuxt.config.js`. Note to add it to `modules` instead of `buildModules`, otherwise the server route will not be generated.
74
+ Add the module to the `modules` array in your Nuxt config:
75
75
 
76
- ```js
77
- // nuxt.config.js
78
- export default {
76
+ ```ts
77
+ // nuxt.config.ts
78
+ export default defineNuxtConfig({
79
79
  modules: [
80
80
  ['nuxt-mail', {
81
81
  message: {
@@ -97,52 +97,26 @@ export default {
97
97
  port: 587,
98
98
  },
99
99
  },
100
- // or use runtimeConfig
101
- runtimeConfig: {
102
- mail: {
103
- message: {
104
- to: 'foo@bar.de',
105
- },
106
- smtp: {
107
- host: "smtp.example.com",
108
- port: 587,
109
- },
110
- },
111
- },
112
- }
100
+ });
113
101
  ```
114
102
 
115
- The `smtp` options are required and directly passed to [nodemailer](https://nodemailer.com/smtp/). Refer to their documentation for available options. Also, you have to pass at least `to`, `cc` or `bcc` via the `message` config. This has security reasons, this way the client cannot send emails from your SMTP server to arbitrary recipients. You can actually preconfigure the message via the `message` config, so if you always want to send emails with the same subject or from address, you can configure them here.
103
+ You can also set environment variables like `NUXT_MAIL`, `NUXT_MAIL_SMTP`, `NUXT_MAIL_MESSAGE`, etc. as JSON. They will be deserialized and put into the runtime config automatically.
116
104
 
117
- The module injects the `$mail` variable, which we now use to send emails:
105
+ The `smtp` options are required and directly passed to [nodemailer](https://nodemailer.com/smtp/). Refer to their documentation for available options. Also, you have to pass at least `to`, `cc` or `bcc` via the `message` config. This has security reasons, this way the client cannot send emails from your SMTP server to arbitrary recipients. You can actually preconfigure the message via the `message` config, so if you always want to send emails with the same subject or from address, you can configure them here.
118
106
 
119
- ## Nuxt 3
107
+ Now we can send emails:
120
108
 
121
109
  ### Via composable
122
110
 
123
111
  ```html
124
112
  <script setup>
125
- const mail = useMail()
113
+ const mail = useMail();
126
114
 
127
115
  mail.send({
128
116
  from: 'John Doe',
129
117
  subject: 'Incredible',
130
118
  text: 'This is an incredible test message',
131
- })
132
- </script>
133
- ```
134
-
135
- ### Via injected variable
136
-
137
- ```html
138
- <script setup>
139
- const { $mail } = useNuxtApp()
140
-
141
- $mail.send({
142
- from: 'John Doe',
143
- subject: 'Incredible',
144
- text: 'This is an incredible test message',
145
- })
119
+ });
146
120
  </script>
147
121
  ```
148
122
 
@@ -157,10 +131,10 @@ export default {
157
131
  from: 'John Doe',
158
132
  subject: 'Incredible',
159
133
  text: 'This is an incredible test message',
160
- })
134
+ });
161
135
  },
162
136
  },
163
- }
137
+ };
164
138
  </script>
165
139
  ```
166
140
 
@@ -168,9 +142,9 @@ export default {
168
142
 
169
143
  It is also possible to provide multiple message configurations by changing the `message` config into an array.
170
144
 
171
- ```js
172
- // nuxt.config.js
173
- export default {
145
+ ```ts
146
+ // nuxt.config.ts
147
+ export default defineNuxtConfig({
174
148
  modules: [
175
149
  ['nuxt-mail', {
176
150
  message: [
@@ -180,29 +154,29 @@ export default {
180
154
  ...
181
155
  }],
182
156
  ],
183
- }
157
+ });
184
158
  ```
185
159
 
186
160
  Then you can reference the config like this:
187
161
 
188
- ```js
162
+ ```ts
189
163
  mail.send({
190
164
  config: 'support',
191
165
  from: 'John Doe',
192
166
  subject: 'Incredible',
193
167
  text: 'This is an incredible test message',
194
- })
168
+ });
195
169
  ```
196
170
 
197
171
  Or via index (in which case you do not need the `name` property):
198
172
 
199
- ```js
173
+ ```ts
200
174
  mail.send({
201
175
  config: 1, // Resolves to 'support'
202
176
  from: 'John Doe',
203
177
  subject: 'Incredible',
204
178
  text: 'This is an incredible test message',
205
- })
179
+ });
206
180
  ```
207
181
 
208
182
  Also, the module does not work for static sites (via `nuxt generate`) because the module creates a server route.
@@ -213,9 +187,9 @@ Also, the module does not work for static sites (via `nuxt generate`) because th
213
187
 
214
188
  You have to setup an [app-specific password](https://myaccount.google.com/apppasswords) to log into the SMTP server. Then, add the following config to your `nuxt-mail` config. Looks like there are multiple ways to configure Gmail, so it's best to try out the options:
215
189
 
216
- ```js
217
- // nuxt.config.js
218
- export default {
190
+ ```ts
191
+ // nuxt.config.ts
192
+ export default defineNuxtConfig({
219
193
  modules: [
220
194
  ['nuxt-mail', {
221
195
  smtp: {
@@ -227,12 +201,12 @@ export default {
227
201
  },
228
202
  }],
229
203
  ],
230
- }
204
+ });
231
205
  ```
232
206
 
233
- ```js
234
- // nuxt.config.js
235
- export default {
207
+ ```ts
208
+ // nuxt.config.ts
209
+ export default defineNuxtConfig({
236
210
  modules: [
237
211
  ['nuxt-mail', {
238
212
  smtp: {
@@ -245,7 +219,7 @@ export default {
245
219
  },
246
220
  }],
247
221
  ],
248
- }
222
+ });
249
223
  ```
250
224
 
251
225
  Missing something? Add your service here via a [pull request](https://github.com/dword-design/nuxt-mail/pulls).
@@ -0,0 +1,3 @@
1
+ import type { MailOptions } from './types';
2
+ declare const _default: (options: MailOptions) => void;
3
+ export default _default;
@@ -0,0 +1,11 @@
1
+ export default options => {
2
+ if (!options.smtp) {
3
+ throw new Error("SMTP config is missing.");
4
+ }
5
+ if (options.message.length === 0) {
6
+ throw new Error("You have to provide at least one config.");
7
+ }
8
+ if (options.message.some(c => !c.to && !c.cc && !c.bcc)) {
9
+ throw new Error("You have to provide to/cc/bcc in all configs.");
10
+ }
11
+ };
package/dist/module.d.ts CHANGED
@@ -1,21 +1,8 @@
1
- import type { SendMailOptions, TransportOptions } from 'nodemailer';
2
- type Message = SendMailOptions & {
3
- name?: string;
4
- };
5
- type MailOptions = {
6
- message?: Message | Message[];
7
- smtp: TransportOptions;
8
- };
9
- declare const _default: import("@nuxt/schema").NuxtModule<import("@nuxt/schema").ModuleOptions, import("@nuxt/schema").ModuleOptions, false>;
10
- export default _default;
1
+ import type { MailOptionsInput } from './types';
11
2
  declare module '@nuxt/schema' {
12
- interface NuxtConfig {
13
- ['mail']?: MailOptions;
14
- }
15
- interface NuxtOptions {
16
- ['mail']?: MailOptions;
17
- }
18
3
  interface RuntimeConfig {
19
- mail?: MailOptions;
4
+ mail: MailOptionsInput;
20
5
  }
21
6
  }
7
+ declare const _default: import("@nuxt/schema").NuxtModule<MailOptionsInput, MailOptionsInput, false>;
8
+ export default _default;
package/dist/module.js CHANGED
@@ -1,45 +1,27 @@
1
- import P from "node:path";
2
- import { addImports, addPlugin, addServerHandler, addTemplate, createResolver, defineNuxtModule } from "@nuxt/kit";
3
- import fs from "fs-extra";
4
- import nuxtAliasPath from "nuxt-alias-path";
5
- import parsePackagejsonName from "parse-packagejson-name";
1
+ import { addImports, addPlugin, addServerHandler, addServerPlugin, createResolver, defineNuxtModule, useRuntimeConfig } from "@nuxt/kit";
2
+ import defu from "defu";
3
+ import checkOptions from "./check-options.js";
4
+ import normalizeOptions from "./normalize-options.js";
6
5
  const resolver = createResolver(import.meta.url);
7
- const packageConfig = fs.readJsonSync(resolver.resolve("../package.json"));
8
- const moduleName = parsePackagejsonName(packageConfig.name).fullName;
9
6
  export default defineNuxtModule({
10
- setup: async (options, nuxt) => {
11
- options = {
12
- ...nuxt.options.runtimeConfig.mail,
13
- ...nuxt.options.mail,
14
- ...options
15
- };
7
+ meta: {
8
+ compatibility: {
9
+ nuxt: ">=3.0.0"
10
+ },
11
+ configKey: "mail",
12
+ name: "nuxt-mail"
13
+ },
14
+ setup: (optionsInput, nuxt) => {
15
+ const options = defu(optionsInput, nuxt.options.runtimeConfig.mail, {
16
+ message: [],
17
+ smtp: null
18
+ });
19
+ nuxt.options.runtimeConfig.mail = normalizeOptions(options);
16
20
  if (!nuxt.options._prepare) {
17
- if (!options.smtp) {
18
- throw new Error("SMTP config is missing.");
19
- }
20
- if (Array.isArray(options.message) && options.message.length === 0 || !options.message) {
21
- throw new Error("You have to provide at least one config.");
22
- }
23
- }
24
- if (!Array.isArray(options.message)) {
25
- options.message = [options.message];
26
- }
27
- if (!nuxt.options._prepare && options.message.some(c => !c.to && !c.cc && !c.bcc)) {
28
- throw new Error("You have to provide to/cc/bcc in all configs.");
21
+ const resolvedOptions = normalizeOptions(useRuntimeConfig().mail);
22
+ checkOptions(resolvedOptions);
29
23
  }
30
- addTemplate({
31
- filename: P.join(moduleName, "options.mjs"),
32
- getContents: () => `export default ${JSON.stringify(options, void 0, 2)}`,
33
- write: true
34
- });
35
- const sendTemplatePathWithoutExt = resolver.resolve("./send");
36
- const sendTemplatePath = (await fs.exists(`${sendTemplatePathWithoutExt}.ts`)) ? `${sendTemplatePathWithoutExt}.ts` : `${sendTemplatePathWithoutExt}.js`;
37
- addTemplate({
38
- filename: P.join(moduleName, "send.mjs"),
39
- getContents: () => fs.readFile(sendTemplatePath, "utf8"),
40
- write: true
41
- });
42
- nuxt.options.alias["#mail"] = nuxtAliasPath(moduleName, nuxt);
24
+ addServerPlugin(resolver.resolve("./server-plugin"));
43
25
  addServerHandler({
44
26
  handler: resolver.resolve("./server-handler.post"),
45
27
  route: "/mail/send"
@@ -0,0 +1,6 @@
1
+ import type { MailOptionsInput } from './types';
2
+ declare const _default: (options: MailOptionsInput) => {
3
+ message: import("./types").Message[];
4
+ smtp: import("nodemailer").TransportOptions;
5
+ };
6
+ export default _default;
@@ -0,0 +1,10 @@
1
+ const normalizeMessage = message => {
2
+ if (Array.isArray(message)) {
3
+ return message;
4
+ }
5
+ return [message];
6
+ };
7
+ export default options => ({
8
+ ...options,
9
+ message: normalizeMessage(options.message)
10
+ });
package/dist/plugin.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { FetchError } from "ofetch";
1
2
  import { defineNuxtPlugin } from "#imports";
2
3
  export default defineNuxtPlugin(() => ({
3
4
  provide: {
@@ -9,7 +10,10 @@ export default defineNuxtPlugin(() => ({
9
10
  method: "POST"
10
11
  });
11
12
  } catch (error) {
12
- throw new Error(error.response._data.statusMessage);
13
+ if (error instanceof FetchError) {
14
+ throw new TypeError(error.response?._data.statusMessage);
15
+ }
16
+ throw error;
13
17
  }
14
18
  }
15
19
  }
package/dist/send.d.ts CHANGED
@@ -1,2 +1,4 @@
1
- declare const _default: (body: any, options: any, transport: any) => Promise<void>;
1
+ import type { Transporter } from 'nodemailer';
2
+ import type { MailOptions, MessageWithConfigInput } from './types';
3
+ declare const _default: (bodyInput: MessageWithConfigInput, options: MailOptions, transport: Transporter) => Promise<void>;
2
4
  export default _default;
package/dist/send.js CHANGED
@@ -1,16 +1,24 @@
1
+ import defu from "defu";
1
2
  import { omit } from "lodash-es";
2
- export default async (body, options, transport) => {
3
- body = {
4
- config: 0,
5
- ...body
6
- };
7
- if (typeof body.config === "string") {
8
- const configIndex = options.message.findIndex(_ => _.name === body.config);
3
+ const resolveConfig = (bodyInput, options) => {
4
+ const bodyWithDefaults = defu(bodyInput, {
5
+ config: 0
6
+ });
7
+ if (typeof bodyWithDefaults.config === "string") {
8
+ const configIndex = options.message.findIndex(_ => _.name === bodyWithDefaults.config);
9
9
  if (configIndex === -1) {
10
- throw new Error(`Message config with name '${body.config}' not found.`);
10
+ throw new Error(`Message config with name '${bodyWithDefaults.config}' not found.`);
11
11
  }
12
- body.config = configIndex;
13
- } else if (!options.message[body.config]) {
12
+ return {
13
+ ...bodyWithDefaults,
14
+ config: configIndex
15
+ };
16
+ }
17
+ return bodyWithDefaults;
18
+ };
19
+ export default async (bodyInput, options, transport) => {
20
+ const body = resolveConfig(bodyInput, options);
21
+ if (!options.message[body.config]) {
14
22
  throw new Error(`Message config not found at index ${body.config}.`);
15
23
  }
16
24
  await transport.sendMail({
@@ -1,15 +1,20 @@
1
1
  import { createError, defineEventHandler, readBody } from "h3";
2
2
  import nodemailer from "nodemailer";
3
- import options from "#mail/options.mjs";
4
- import send from "#mail/send.mjs";
5
- const transport = nodemailer.createTransport(options.smtp);
3
+ import { useRuntimeConfig } from "#imports";
4
+ import normalizeOptions from "./normalize-options.js";
5
+ import send from "./send.js";
6
+ const options = normalizeOptions(useRuntimeConfig().mail);
7
+ let transport = null;
6
8
  export default defineEventHandler(async event => {
9
+ if (!transport) {
10
+ transport = nodemailer.createTransport(options.smtp);
11
+ }
7
12
  try {
8
13
  await send(await readBody(event), options, transport);
9
14
  } catch (error) {
10
15
  throw createError({
11
16
  statusCode: 500,
12
- statusMessage: error.message
17
+ statusMessage: error instanceof Error ? error.message : String(error)
13
18
  });
14
19
  }
15
20
  return "";
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nitropack").NitroAppPlugin;
2
+ export default _default;
@@ -0,0 +1,6 @@
1
+ import { defineNitroPlugin } from "nitropack/runtime";
2
+ import { useRuntimeConfig } from "#imports";
3
+ import checkOptions from "./check-options.js";
4
+ import normalizeOptions from "./normalize-options.js";
5
+ const options = normalizeOptions(useRuntimeConfig().mail);
6
+ export default defineNitroPlugin(() => checkOptions(options));
@@ -0,0 +1,29 @@
1
+ import type { SendMailOptions, TransportOptions } from 'nodemailer';
2
+
3
+ export interface MailOptions {
4
+ message: Message[];
5
+ smtp: TransportOptions | null;
6
+ }
7
+
8
+ export interface Message extends Omit<SendMailOptions, 'to' | 'cc' | 'bcc'> {
9
+ to: SendMailOptions['to'];
10
+ cc: SendMailOptions['cc'];
11
+ bcc: SendMailOptions['bcc'];
12
+ name?: string;
13
+ }
14
+
15
+ export interface MailOptionsInput extends Omit<MailOptions, 'message'> {
16
+ message: MailOptions['message'] | Message;
17
+ smtp: TransportOptions;
18
+ }
19
+
20
+ export interface MessageWithConfig extends Message {
21
+ config: number;
22
+ }
23
+
24
+ export interface MessageWithConfigInput extends Omit<
25
+ MessageWithConfig,
26
+ 'config'
27
+ > {
28
+ config?: MessageWithConfig['config'] | string;
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-mail",
3
- "version": "7.0.1",
3
+ "version": "8.0.0",
4
4
  "description": "Adds email sending capability to a Nuxt.js app. Adds a server route, an injected variable, and uses nodemailer to send emails.",
5
5
  "keywords": [
6
6
  "email",
@@ -26,10 +26,8 @@
26
26
  "type": "module",
27
27
  "exports": {
28
28
  ".": {
29
- "import": {
30
- "default": "./dist/module.js",
31
- "types": "./dist/module.d.ts"
32
- }
29
+ "default": "./dist/module.js",
30
+ "types": "./dist/module.d.ts"
33
31
  }
34
32
  },
35
33
  "main": "dist/module.js",
@@ -49,34 +47,38 @@
49
47
  "verify": "base verify"
50
48
  },
51
49
  "dependencies": {
52
- "@nuxt/kit": "^3.17.4",
53
- "fs-extra": "^11.3.0",
54
- "h3": "^1.15.3",
50
+ "@nuxt/kit": "^4.2.1",
51
+ "defu": "^6.1.4",
55
52
  "lodash-es": "^4.17.21",
56
- "nodemailer": "^7.0.3",
57
- "nuxt-alias-path": "^2.0.0",
58
- "parse-packagejson-name": "^1.0.1"
53
+ "nodemailer": "^7.0.11"
59
54
  },
60
55
  "devDependencies": {
61
- "@dword-design/base": "^15.1.2",
62
- "@dword-design/base-config-nuxt-module": "^3.0.0",
63
- "@playwright/browser-chromium": "^1.54.1",
64
- "@playwright/test": "^1.54.1",
65
- "@types/nodemailer": "^6.4.17",
66
- "axios": "^1.9.0",
56
+ "@dword-design/base": "^16.1.4",
57
+ "@dword-design/base-config-nuxt-module": "^5.0.0",
58
+ "@playwright/browser-chromium": "^1.57.0",
59
+ "@playwright/test": "^1.57.0",
60
+ "@types/fs-extra": "^11.0.4",
61
+ "@types/lodash-es": "^4.17.12",
62
+ "@types/nodemailer": "^7.0.4",
63
+ "axios": "^1.13.2",
67
64
  "endent": "npm:@dword-design/endent@^1.4.7",
68
- "execa": "^9.6.0",
65
+ "execa": "^9.6.1",
69
66
  "get-port": "^7.1.0",
70
- "nuxt": "^3.17.4",
67
+ "nuxt": "^4.2.1",
71
68
  "nuxt-dev-ready": "^5.0.1",
72
69
  "output-files": "^3.0.0",
73
- "port-ready": "^0.1.0",
70
+ "port-ready": "npm:@dword-design/port-ready-fork@^0.0.3",
74
71
  "smtp-tester": "npm:@dword-design/smtp-tester-fork@^0.0.1",
75
72
  "tree-kill-promise": "^4.0.0"
76
73
  },
74
+ "peerDependencies": {
75
+ "h3": "*",
76
+ "nitropack": "*",
77
+ "ofetch": "*"
78
+ },
77
79
  "packageManager": "pnpm@10.13.1+sha512.37ebf1a5c7a30d5fabe0c5df44ee8da4c965ca0c5af3dbab28c3a1681b70a256218d05c81c9c0dcf767ef6b8551eb5b960042b9ed4300c59242336377e01cfad",
78
80
  "engines": {
79
- "node": ">=20"
81
+ "node": ">=22"
80
82
  },
81
83
  "publishConfig": {
82
84
  "access": "public"