@nexusts/mail 0.7.0 → 0.7.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 +2 -2
- package/dist/index.d.ts +8 -0
- package/dist/index.js +3 -19
- package/dist/index.js.map +4 -4
- package/dist/mail.module.d.ts +20 -0
- package/dist/mail.service.d.ts +17 -0
- package/dist/transports/file.d.ts +18 -0
- package/dist/transports/index.d.ts +8 -0
- package/dist/transports/null.d.ts +10 -0
- package/dist/transports/smtp.d.ts +39 -0
- package/dist/types.d.ts +72 -0
- package/package.json +6 -11
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ This module is part of the NexusTS monorepo. Each module is published as its own
|
|
|
15
15
|
Most apps start with just the core:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
bun add @nexusts/core
|
|
18
|
+
bun add @nexusts/core
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
Then add this module only if you need it:
|
|
@@ -26,7 +26,7 @@ bun add @nexusts/mail
|
|
|
26
26
|
|
|
27
27
|
## Peer dependencies
|
|
28
28
|
|
|
29
|
-
None.
|
|
29
|
+
**None.** No external dependencies for the null / file backends. The SMTP backend works out of the box; no `nodemailer` needed.
|
|
30
30
|
|
|
31
31
|
## Usage
|
|
32
32
|
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry point for `nexusjs/mail`.
|
|
3
|
+
*/
|
|
4
|
+
export * from "./types.js";
|
|
5
|
+
export { NullTransport, FileTransport, SmtpTransport, } from "./transports/index.js";
|
|
6
|
+
export type { FileTransportOptions, SmtpTransportOptions, } from "./transports/index.js";
|
|
7
|
+
export { MailService } from "./mail.service.js";
|
|
8
|
+
export { MailModule } from "./mail.module.js";
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
2
|
var __legacyDecorateClassTS = function(decorators, target, key, desc) {
|
|
19
3
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
4
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
@@ -172,7 +156,7 @@ class SmtpTransport {
|
|
|
172
156
|
}
|
|
173
157
|
}
|
|
174
158
|
// packages/mail/src/mail.service.ts
|
|
175
|
-
import { Inject, Injectable } from "@nexusts/core
|
|
159
|
+
import { Inject, Injectable } from "@nexusts/core";
|
|
176
160
|
class MailService {
|
|
177
161
|
static TOKEN = Symbol.for("nexus:MailService");
|
|
178
162
|
transport;
|
|
@@ -211,7 +195,7 @@ MailService = __legacyDecorateClassTS([
|
|
|
211
195
|
], MailService);
|
|
212
196
|
// packages/mail/src/mail.module.ts
|
|
213
197
|
import"reflect-metadata";
|
|
214
|
-
import { Module } from "@nexusts/core
|
|
198
|
+
import { Module } from "@nexusts/core";
|
|
215
199
|
class MailModule {
|
|
216
200
|
static forRoot(config = {}) {
|
|
217
201
|
const cfg = {
|
|
@@ -254,5 +238,5 @@ export {
|
|
|
254
238
|
FileTransport
|
|
255
239
|
};
|
|
256
240
|
|
|
257
|
-
//# debugId=
|
|
241
|
+
//# debugId=3995FCC384FD6E1B64756E2164756E21
|
|
258
242
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
"/**\n * Null mail transport. Drops every message. Useful in tests.\n */\nimport type { MailMessage, MailSendResult, MailTransport } from \"../types.js\";\n\nexport class NullTransport implements MailTransport {\n\treadonly kind = \"null\";\n\t/** Captured messages for inspection in tests. */\n\tsent: MailMessage[] = [];\n\n\tasync send(msg: MailMessage): Promise<MailSendResult> {\n\t\tthis.sent.push(msg);\n\t\treturn {\n\t\t\tid: `null-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n\t\t\tsentAt: Date.now(),\n\t\t};\n\t}\n}\n",
|
|
7
7
|
"/**\n * File mail transport. Writes each outgoing message as a `.eml` file\n * under a directory. Useful for development and acceptance tests.\n *\n * new FileTransport({ dir: './tmp/mail', pretty: true });\n */\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { MailMessage, MailSendResult, MailTransport } from \"../types.js\";\n\nexport interface FileTransportOptions {\n\t/** Directory where `.eml` files are written. */\n\tdir: string;\n\t/** Format the .eml with proper headers (true) or just the body (false). Default: true. */\n\tincludeHeaders?: boolean;\n\t/** Pretty-print JSON content-type bodies. */\n\tpretty?: boolean;\n}\n\nexport class FileTransport implements MailTransport {\n\treadonly kind = \"file\";\n\tprivate opts: Required<FileTransportOptions>;\n\n\tconstructor(opts: FileTransportOptions) {\n\t\tthis.opts = {\n\t\t\tdir: opts.dir,\n\t\t\tincludeHeaders: opts.includeHeaders ?? true,\n\t\t\tpretty: opts.pretty ?? true,\n\t\t};\n\t}\n\n\tasync send(msg: MailMessage): Promise<MailSendResult> {\n\t\tawait mkdir(this.opts.dir, { recursive: true });\n\t\tconst id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n\t\tconst filename = `${id}.eml`;\n\t\tconst body = this.opts.includeHeaders ? this.toEml(msg) : this.toBody(msg);\n\t\tawait writeFile(join(this.opts.dir, filename), body, \"utf-8\");\n\t\treturn { id, sentAt: Date.now() };\n\t}\n\n\tprivate toEml(msg: MailMessage): string {\n\t\tconst headers: string[] = [];\n\t\tif (msg.from) headers.push(`From: ${this.formatAddr(msg.from)}`);\n\t\theaders.push(`To: ${this.formatAddr(msg.to)}`);\n\t\tif (msg.cc) headers.push(`Cc: ${this.formatAddr(msg.cc)}`);\n\t\tif (msg.replyTo) headers.push(`Reply-To: ${this.formatAddr(msg.replyTo)}`);\n\t\theaders.push(`Subject: ${msg.subject}`);\n\t\theaders.push(`Date: ${new Date().toUTCString()}`);\n\t\theaders.push(`MIME-Version: 1.0`);\n\t\tif (msg.html) {\n\t\t\theaders.push(`Content-Type: text/html; charset=utf-8`);\n\t\t} else {\n\t\t\theaders.push(`Content-Type: text/plain; charset=utf-8`);\n\t\t}\n\t\tconst body = msg.html ?? msg.text ?? \"\";\n\t\treturn `${headers.join(\"\\r\\n\")}\\r\\n\\r\\n${body}`;\n\t}\n\n\tprivate toBody(msg: MailMessage): string {\n\t\treturn msg.html ?? msg.text ?? \"\";\n\t}\n\n\tprivate formatAddr(a: MailMessage[\"to\"]): string {\n\t\tif (Array.isArray(a)) return a.map((x) => this.formatAddr(x)).join(\", \");\n\t\tif (typeof a === \"string\") return a;\n\t\treturn a.name ? `${a.name} <${a.address}>` : a.address;\n\t}\n}\n",
|
|
8
8
|
"/**\n * SMTP mail transport. Uses `nodemailer` as an optional peer dep.\n *\n * const transport = new SmtpTransport({\n * host: 'smtp.gmail.com',\n * port: 465,\n * secure: true,\n * auth: { user: '...', pass: '...' },\n * });\n * const mail = new MailService({ transport });\n */\nimport type { MailMessage, MailSendResult, MailTransport } from \"../types.js\";\n\nexport interface SmtpTransportOptions {\n\thost: string;\n\tport?: number;\n\tsecure?: boolean;\n\tauth?: { user: string; pass: string };\n\t/** Optional pool of pre-opened connections. */\n\tpool?: boolean;\n\t/** Maximum connections. */\n\tmaxConnections?: number;\n\t/** Sender override. */\n\tdefaultFrom?: string;\n\t/** `nodemailer` extra options. */\n\textras?: Record<string, any>;\n}\n\nexport class SmtpTransport implements MailTransport {\n\treadonly kind = \"smtp\";\n\tprivate opts: SmtpTransportOptions;\n\tprivate _transporter: any = null;\n\n\tconstructor(opts: SmtpTransportOptions) {\n\t\tthis.opts = opts;\n\t}\n\n\tprivate async transporter() {\n\t\tif (this._transporter) return this._transporter;\n\t\ttry {\n\t\t\tconst mod = await import(\"nodemailer\");\n\t\t\tthis._transporter = mod.default.createTransport({\n\t\t\t\thost: this.opts.host,\n\t\t\t\tport: this.opts.port,\n\t\t\t\tsecure: this.opts.secure,\n\t\t\t\tauth: this.opts.auth,\n\t\t\t\tpool: this.opts.pool,\n\t\t\t\tmaxConnections: this.opts.maxConnections,\n\t\t\t\t...this.opts.extras,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tthrow new Error(\n\t\t\t\t\"SmtpTransport requires nodemailer. Install it with: bun add nodemailer\",\n\t\t\t);\n\t\t}\n\t\treturn this._transporter;\n\t}\n\n\tasync send(msg: MailMessage): Promise<MailSendResult> {\n\t\tconst t = await this.transporter();\n\t\tconst from = this.formatAddr(msg.from ?? this.opts.defaultFrom);\n\t\tconst res = await t.sendMail({\n\t\t\tfrom,\n\t\t\tto: this.formatAddr(msg.to),\n\t\t\tcc: msg.cc ? this.formatAddr(msg.cc) : undefined,\n\t\t\tbcc: msg.bcc ? this.formatAddr(msg.bcc) : undefined,\n\t\t\treplyTo: msg.replyTo ? this.formatAddr(msg.replyTo) : undefined,\n\t\t\tsubject: msg.subject,\n\t\t\ttext: msg.text,\n\t\t\thtml: msg.html,\n\t\t\tattachments: msg.attachments?.map((a) => ({\n\t\t\t\tfilename: a.filename,\n\t\t\t\tcontent: a.content,\n\t\t\t\tcontentType: a.contentType,\n\t\t\t\tcid: a.cid,\n\t\t\t})),\n\t\t\theaders: msg.headers,\n\t\t\tpriority: msg.priority,\n\t\t});\n\t\treturn {\n\t\t\tid: res.messageId ?? `smtp-${Date.now()}`,\n\t\t\tsentAt: Date.now(),\n\t\t};\n\t}\n\n\tasync close(): Promise<void> {\n\t\tif (this._transporter) {\n\t\t\tawait this._transporter.close();\n\t\t\tthis._transporter = null;\n\t\t}\n\t}\n\n\tprivate formatAddr(a: MailMessage[\"to\"] | undefined): string {\n\t\tif (!a) return \"\";\n\t\tif (Array.isArray(a)) return a.map((x) => this.formatAddr(x)).join(\", \");\n\t\tif (typeof a === \"string\") return a;\n\t\treturn a.name ? `${a.name} <${a.address}>` : a.address;\n\t}\n}\n",
|
|
9
|
-
"/**\n * `MailService` — main entry point for outbound mail.\n *\n * const mail = new MailService({ transport: new NullTransport() });\n * await mail.send({ to: 'a@b.com', subject: 'hi', html: '<h1>hi</h1>' });\n *\n * mail.renderMjml('<mjml>...</mjml>', { name: 'Kim' });\n */\nimport { Inject, Injectable } from \"@nexusts/core
|
|
10
|
-
"/**\n * `MailModule` — drop-in mail.\n *\n * @Module({\n * imports: [\n * MailModule.forRoot({\n * transport: new SmtpTransport({ host: 'smtp.example.com' }),\n * defaultFrom: 'no-reply@example.com',\n * }),\n * ],\n * })\n * export class AppModule {}\n */\nimport \"reflect-metadata\";\nimport { Module } from \"@nexusts/core
|
|
9
|
+
"/**\n * `MailService` — main entry point for outbound mail.\n *\n * const mail = new MailService({ transport: new NullTransport() });\n * await mail.send({ to: 'a@b.com', subject: 'hi', html: '<h1>hi</h1>' });\n *\n * mail.renderMjml('<mjml>...</mjml>', { name: 'Kim' });\n */\nimport { Inject, Injectable } from \"@nexusts/core\";\nimport { NullTransport } from \"./transports/null.js\";\nimport type {\n\tMailConfig,\n\tMailMessage,\n\tMailSendResult,\n\tMailTransport,\n} from \"./types.js\";\n\n@Injectable()\nexport class MailService {\n\t/** DI token. */\n\tstatic readonly TOKEN = Symbol.for(\"nexus:MailService\");\n\n\ttransport: MailTransport;\n\tdefaultFrom?: MailConfig[\"defaultFrom\"];\n\n\tconstructor(@Inject(\"MAIL_CONFIG\") config: MailConfig = {}) {\n\t\tthis.transport = config.transport ?? new NullTransport();\n\t\tthis.defaultFrom = config.defaultFrom;\n\t}\n\n\t/** Send a single message. */\n\tasync send(msg: MailMessage): Promise<MailSendResult> {\n\t\tconst full = { ...msg, from: msg.from ?? this.defaultFrom };\n\t\treturn this.transport.send(full);\n\t}\n\n\t/** Send the same message to many recipients (one envelope per call). */\n\tasync sendBatch(msg: Omit<MailMessage, \"to\">, recipients: string[]): Promise<MailSendResult[]> {\n\t\tconst results: MailSendResult[] = [];\n\t\tfor (const to of recipients) {\n\t\t\tresults.push(await this.send({ ...msg, to }));\n\t\t}\n\t\treturn results;\n\t}\n\n\t/**\n\t * Render an MJML template. The optional `mjml` peer dep is loaded lazily.\n\t * Throws a clear error if not installed.\n\t */\n\tasync renderMjml(template: string, _vars?: Record<string, unknown>): Promise<string> {\n\t\ttry {\n\t\t\tconst mod = await import(\"mjml\");\n\t\t\tconst { html } = mod.mjml2html(template);\n\t\t\treturn html;\n\t\t} catch (err) {\n\t\t\tthrow new Error(\n\t\t\t\t\"renderMjml requires the 'mjml' package. Install it with: bun add mjml\",\n\t\t\t);\n\t\t}\n\t}\n}\n",
|
|
10
|
+
"/**\n * `MailModule` — drop-in mail.\n *\n * @Module({\n * imports: [\n * MailModule.forRoot({\n * transport: new SmtpTransport({ host: 'smtp.example.com' }),\n * defaultFrom: 'no-reply@example.com',\n * }),\n * ],\n * })\n * export class AppModule {}\n */\nimport \"reflect-metadata\";\nimport { Module } from \"@nexusts/core\";\nimport { MailService } from \"./mail.service.js\";\nimport { NullTransport } from \"./transports/null.js\";\nimport type { MailConfig } from \"./types.js\";\n\n@Module({\n\tproviders: [\n\t\tMailService,\n\t\t{ provide: MailService.TOKEN, useExisting: MailService },\n\t],\n\texports: [MailService, MailService.TOKEN],\n})\nexport class MailModule {\n\tstatic forRoot(config: MailConfig = {}) {\n\t\tconst cfg: MailConfig = {\n\t\t\ttransport: new NullTransport(),\n\t\t\t...config,\n\t\t};\n\t\t@Module({\n\t\t\tproviders: [\n\t\t\t\tMailService,\n\t\t\t\t{ provide: MailService.TOKEN, useExisting: MailService },\n\t\t\t\t{ provide: \"MAIL_CONFIG\", useValue: cfg },\n\t\t\t],\n\t\t\texports: [MailService, MailService.TOKEN],\n\t\t})\n\t\tclass ConfiguredMailModule {}\n\t\tObject.defineProperty(ConfiguredMailModule, \"name\", {\n\t\t\tvalue: \"ConfiguredMailModule\",\n\t\t});\n\t\treturn ConfiguredMailModule;\n\t}\n}\n"
|
|
11
11
|
],
|
|
12
|
-
"mappings": "
|
|
13
|
-
"debugId": "
|
|
12
|
+
"mappings": "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",
|
|
13
|
+
"debugId": "3995FCC384FD6E1B64756E2164756E21",
|
|
14
14
|
"names": []
|
|
15
15
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MailModule` — drop-in mail.
|
|
3
|
+
*
|
|
4
|
+
* @Module({
|
|
5
|
+
* imports: [
|
|
6
|
+
* MailModule.forRoot({
|
|
7
|
+
* transport: new SmtpTransport({ host: 'smtp.example.com' }),
|
|
8
|
+
* defaultFrom: 'no-reply@example.com',
|
|
9
|
+
* }),
|
|
10
|
+
* ],
|
|
11
|
+
* })
|
|
12
|
+
* export class AppModule {}
|
|
13
|
+
*/
|
|
14
|
+
import "reflect-metadata";
|
|
15
|
+
import type { MailConfig } from "./types.js";
|
|
16
|
+
export declare class MailModule {
|
|
17
|
+
static forRoot(config?: MailConfig): {
|
|
18
|
+
new (): {};
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { MailConfig, MailMessage, MailSendResult, MailTransport } from "./types.js";
|
|
2
|
+
export declare class MailService {
|
|
3
|
+
/** DI token. */
|
|
4
|
+
static readonly TOKEN: unique symbol;
|
|
5
|
+
transport: MailTransport;
|
|
6
|
+
defaultFrom?: MailConfig["defaultFrom"];
|
|
7
|
+
constructor(config?: MailConfig);
|
|
8
|
+
/** Send a single message. */
|
|
9
|
+
send(msg: MailMessage): Promise<MailSendResult>;
|
|
10
|
+
/** Send the same message to many recipients (one envelope per call). */
|
|
11
|
+
sendBatch(msg: Omit<MailMessage, "to">, recipients: string[]): Promise<MailSendResult[]>;
|
|
12
|
+
/**
|
|
13
|
+
* Render an MJML template. The optional `mjml` peer dep is loaded lazily.
|
|
14
|
+
* Throws a clear error if not installed.
|
|
15
|
+
*/
|
|
16
|
+
renderMjml(template: string, _vars?: Record<string, unknown>): Promise<string>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MailMessage, MailSendResult, MailTransport } from "../types.js";
|
|
2
|
+
export interface FileTransportOptions {
|
|
3
|
+
/** Directory where `.eml` files are written. */
|
|
4
|
+
dir: string;
|
|
5
|
+
/** Format the .eml with proper headers (true) or just the body (false). Default: true. */
|
|
6
|
+
includeHeaders?: boolean;
|
|
7
|
+
/** Pretty-print JSON content-type bodies. */
|
|
8
|
+
pretty?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare class FileTransport implements MailTransport {
|
|
11
|
+
readonly kind = "file";
|
|
12
|
+
private opts;
|
|
13
|
+
constructor(opts: FileTransportOptions);
|
|
14
|
+
send(msg: MailMessage): Promise<MailSendResult>;
|
|
15
|
+
private toEml;
|
|
16
|
+
private toBody;
|
|
17
|
+
private formatAddr;
|
|
18
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transports barrel.
|
|
3
|
+
*/
|
|
4
|
+
export { NullTransport } from "./null.js";
|
|
5
|
+
export { FileTransport } from "./file.js";
|
|
6
|
+
export type { FileTransportOptions } from "./file.js";
|
|
7
|
+
export { SmtpTransport } from "./smtp.js";
|
|
8
|
+
export type { SmtpTransportOptions } from "./smtp.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Null mail transport. Drops every message. Useful in tests.
|
|
3
|
+
*/
|
|
4
|
+
import type { MailMessage, MailSendResult, MailTransport } from "../types.js";
|
|
5
|
+
export declare class NullTransport implements MailTransport {
|
|
6
|
+
readonly kind = "null";
|
|
7
|
+
/** Captured messages for inspection in tests. */
|
|
8
|
+
sent: MailMessage[];
|
|
9
|
+
send(msg: MailMessage): Promise<MailSendResult>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMTP mail transport. Uses `nodemailer` as an optional peer dep.
|
|
3
|
+
*
|
|
4
|
+
* const transport = new SmtpTransport({
|
|
5
|
+
* host: 'smtp.gmail.com',
|
|
6
|
+
* port: 465,
|
|
7
|
+
* secure: true,
|
|
8
|
+
* auth: { user: '...', pass: '...' },
|
|
9
|
+
* });
|
|
10
|
+
* const mail = new MailService({ transport });
|
|
11
|
+
*/
|
|
12
|
+
import type { MailMessage, MailSendResult, MailTransport } from "../types.js";
|
|
13
|
+
export interface SmtpTransportOptions {
|
|
14
|
+
host: string;
|
|
15
|
+
port?: number;
|
|
16
|
+
secure?: boolean;
|
|
17
|
+
auth?: {
|
|
18
|
+
user: string;
|
|
19
|
+
pass: string;
|
|
20
|
+
};
|
|
21
|
+
/** Optional pool of pre-opened connections. */
|
|
22
|
+
pool?: boolean;
|
|
23
|
+
/** Maximum connections. */
|
|
24
|
+
maxConnections?: number;
|
|
25
|
+
/** Sender override. */
|
|
26
|
+
defaultFrom?: string;
|
|
27
|
+
/** `nodemailer` extra options. */
|
|
28
|
+
extras?: Record<string, any>;
|
|
29
|
+
}
|
|
30
|
+
export declare class SmtpTransport implements MailTransport {
|
|
31
|
+
readonly kind = "smtp";
|
|
32
|
+
private opts;
|
|
33
|
+
private _transporter;
|
|
34
|
+
constructor(opts: SmtpTransportOptions);
|
|
35
|
+
private transporter;
|
|
36
|
+
send(msg: MailMessage): Promise<MailSendResult>;
|
|
37
|
+
close(): Promise<void>;
|
|
38
|
+
private formatAddr;
|
|
39
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nexusjs/mail` — outbound email.
|
|
3
|
+
*
|
|
4
|
+
* const mail = new MailService({ transport: new SmtpTransport({ host: 'smtp.gmail.com' }) });
|
|
5
|
+
* await mail.send({
|
|
6
|
+
* from: 'no-reply@example.com',
|
|
7
|
+
* to: 'user@example.com',
|
|
8
|
+
* subject: 'Welcome',
|
|
9
|
+
* html: '<h1>Hi</h1>',
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* Transports:
|
|
13
|
+
* - `SmtpTransport` — SMTP via nodemailer (peer dep)
|
|
14
|
+
* - `FileTransport` — write .eml files to a directory (dev/test)
|
|
15
|
+
* - `NullTransport` — drop everything (tests)
|
|
16
|
+
*
|
|
17
|
+
* mail.renderMjml('template', { name: 'Kim' }) // compile MJML to HTML
|
|
18
|
+
*/
|
|
19
|
+
import "reflect-metadata";
|
|
20
|
+
/** A single recipient. */
|
|
21
|
+
export type MailAddress = string | {
|
|
22
|
+
name?: string;
|
|
23
|
+
address: string;
|
|
24
|
+
};
|
|
25
|
+
/** A mail message. */
|
|
26
|
+
export interface MailMessage {
|
|
27
|
+
from?: MailAddress;
|
|
28
|
+
to: MailAddress | MailAddress[];
|
|
29
|
+
cc?: MailAddress | MailAddress[];
|
|
30
|
+
bcc?: MailAddress | MailAddress[];
|
|
31
|
+
replyTo?: MailAddress;
|
|
32
|
+
subject: string;
|
|
33
|
+
text?: string;
|
|
34
|
+
html?: string;
|
|
35
|
+
/** Attachments. */
|
|
36
|
+
attachments?: MailAttachment[];
|
|
37
|
+
/** Custom headers. */
|
|
38
|
+
headers?: Record<string, string>;
|
|
39
|
+
/** Priority: 1 (high), 3 (normal), 5 (low). */
|
|
40
|
+
priority?: "high" | "normal" | "low";
|
|
41
|
+
}
|
|
42
|
+
export interface MailAttachment {
|
|
43
|
+
filename: string;
|
|
44
|
+
/** File content (Buffer / string). */
|
|
45
|
+
content: Buffer | string;
|
|
46
|
+
/** MIME type. Default: 'application/octet-stream'. */
|
|
47
|
+
contentType?: string;
|
|
48
|
+
/** Content-ID for inline images. */
|
|
49
|
+
cid?: string;
|
|
50
|
+
}
|
|
51
|
+
/** Result returned by a transport after sending. */
|
|
52
|
+
export interface MailSendResult {
|
|
53
|
+
/** Transport-specific ID (e.g. SMTP message-id). */
|
|
54
|
+
id: string;
|
|
55
|
+
/** When the message was sent (unix-ms). */
|
|
56
|
+
sentAt: number;
|
|
57
|
+
}
|
|
58
|
+
/** Transport that knows how to deliver a message. */
|
|
59
|
+
export interface MailTransport {
|
|
60
|
+
readonly kind: string;
|
|
61
|
+
send(msg: MailMessage): Promise<MailSendResult>;
|
|
62
|
+
close?(): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/** Top-level config. */
|
|
65
|
+
export interface MailConfig {
|
|
66
|
+
/** Transport backend. Default: NullTransport. */
|
|
67
|
+
transport?: MailTransport;
|
|
68
|
+
/** Default `from` address. */
|
|
69
|
+
defaultFrom?: MailAddress;
|
|
70
|
+
/** Whether to expose raw `nodemailer` (only if SmtpTransport is used). */
|
|
71
|
+
debug?: boolean;
|
|
72
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexusts/mail",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Outbound email (SMTP / File / Null transports)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,20 +12,15 @@
|
|
|
12
12
|
"import": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
-
"files": [
|
|
16
|
-
"dist",
|
|
17
|
-
"README.md"
|
|
18
|
-
],
|
|
15
|
+
"files": ["dist", "README.md"],
|
|
19
16
|
"scripts": {
|
|
20
17
|
"build": "bun run ../../build.ts"
|
|
21
18
|
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"nexusts",
|
|
24
|
-
"framework",
|
|
25
|
-
"bun"
|
|
26
|
-
],
|
|
19
|
+
"keywords": ["nexusts", "framework", "bun"],
|
|
27
20
|
"license": "MIT",
|
|
21
|
+
|
|
22
|
+
|
|
28
23
|
"dependencies": {
|
|
29
|
-
"@nexusts/core": "
|
|
24
|
+
"@nexusts/core": "file:../core"
|
|
30
25
|
}
|
|
31
26
|
}
|