ts-mailkit 0.2.0 → 0.3.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 +38 -9
- package/dist/core/client.d.ts +27 -23
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/types.d.ts +8 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.cjs +103 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +99 -59
- package/dist/index.js.map +1 -1
- package/dist/renderers/default/default-renderer.d.ts +9 -0
- package/dist/renderers/default/default-renderer.d.ts.map +1 -1
- package/dist/templates/dto/index.d.ts +8 -0
- package/dist/templates/dto/index.d.ts.map +1 -1
- package/dist/templates/factory.d.ts +7 -2
- package/dist/templates/factory.d.ts.map +1 -1
- package/dist/transports/zeptomail/types.d.ts +6 -1
- package/dist/transports/zeptomail/types.d.ts.map +1 -1
- package/dist/transports/zeptomail/zeptomail-sender.d.ts +10 -4
- package/dist/transports/zeptomail/zeptomail-sender.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Works seamlessly in **Node.js**, **Cloudflare Workers** (`workerd`), **Bun**, **
|
|
|
10
10
|
|
|
11
11
|
- **Type-Safe DTOs**: Strongly-typed Data Transfer Objects for transactional emails (verification, password reset, 2FA, magic links, newsletters).
|
|
12
12
|
- **Pluggable Transports (`IEmailSender`)**: Decoupled transport adapter interface with built-in senders:
|
|
13
|
-
- `
|
|
13
|
+
- `ZeptoMailHttpSender` (Zoho Mail transactional API via native `fetch`).
|
|
14
14
|
- `MemoryEmailSender` (In-memory mock transport for unit and integration testing).
|
|
15
15
|
- `ConsoleEmailSender` (Formatted terminal logger for local development).
|
|
16
16
|
- **Zero Runtime Dependencies**: Core uses standard web APIs (global `fetch`), ensuring zero heavy dependencies and complete edge compatibility.
|
|
@@ -18,7 +18,11 @@ Works seamlessly in **Node.js**, **Cloudflare Workers** (`workerd`), **Bun**, **
|
|
|
18
18
|
1. DTO schema and validation.
|
|
19
19
|
2. Template building and responsive HTML rendering.
|
|
20
20
|
3. Dispatch via the chosen transport adapter.
|
|
21
|
-
- **Multitenant & Dynamic Branding**: Configure global branding or pass a dynamic brand name resolver for multi-tenant applications.
|
|
21
|
+
- **Multitenant & Dynamic Branding**: Configure global branding, top-center logos, or pass a dynamic brand name resolver for multi-tenant applications.
|
|
22
|
+
- **Top-Center Brand Logo**: Display your brand or company logo top-center with automatic HTTP(S) URL validation.
|
|
23
|
+
- **Auto Plain-Text Fallbacks**: When sending custom or raw HTML, accessible plain-text equivalents are cleanly generated automatically if not explicitly provided.
|
|
24
|
+
- **RFC 5322 Address Parser**: Optional utility to safely parse `"Display Name <email@example.com>"` strings into structured address objects.
|
|
25
|
+
- **Template Preview**: Inspect [`demo-newsletter.html`](demo-newsletter.html) directly in the root folder to view the responsive default email template before installing.
|
|
22
26
|
- **Dual ESM & CommonJS**: Full support for `import` and `require` with first-class TypeScript declaration maps.
|
|
23
27
|
|
|
24
28
|
---
|
|
@@ -48,10 +52,10 @@ bun add ts-mailkit
|
|
|
48
52
|
### 1. Initialize Transport & Client
|
|
49
53
|
|
|
50
54
|
```ts
|
|
51
|
-
import { createMailKit,
|
|
55
|
+
import { createMailKit, ZeptoMailHttpSender, EmailTemplateFactory } from 'ts-mailkit';
|
|
52
56
|
|
|
53
57
|
// Configure the Zoho ZeptoMail HTTP transport
|
|
54
|
-
const transport = new
|
|
58
|
+
const transport = new ZeptoMailHttpSender({
|
|
55
59
|
apiToken: process.env.ZEPTO_MAIL_TOKEN!,
|
|
56
60
|
apiHost: 'api.zeptomail.com', // or 'api.zeptomail.eu', 'api.zeptomail.in'
|
|
57
61
|
from: { address: 'noreply@yourdomain.com', name: 'Acme App' },
|
|
@@ -137,6 +141,7 @@ You can instantiate `EmailTemplateFactory` with brand-level defaults:
|
|
|
137
141
|
```ts
|
|
138
142
|
const tenantFactory = new EmailTemplateFactory({
|
|
139
143
|
brandName: 'St. Patrick High School',
|
|
144
|
+
logoUrl: 'https://school.edu/assets/logo.png',
|
|
140
145
|
securityMessage: 'If you did not make this request, contact our school IT administration immediately.',
|
|
141
146
|
footer: (brand) => `© ${new Date().getFullYear()} ${brand}. Authorized educational portal.`,
|
|
142
147
|
});
|
|
@@ -198,14 +203,14 @@ describe('User Registration Email', () => {
|
|
|
198
203
|
|
|
199
204
|
### 4. Sending Raw Emails (No Template DTO)
|
|
200
205
|
|
|
201
|
-
For custom HTML or plain-text messages
|
|
206
|
+
For custom HTML or plain-text messages. When `text` is omitted, an accessible plain-text fallback is automatically extracted from the `html`:
|
|
202
207
|
|
|
203
208
|
```ts
|
|
204
209
|
await mailer.sendRaw({
|
|
205
210
|
to: [{ address: 'support@example.com', name: 'Support Team' }],
|
|
206
211
|
subject: 'Urgent System Alert',
|
|
207
212
|
html: '<h1>System Alert</h1><p>Database failover completed successfully.</p>',
|
|
208
|
-
text
|
|
213
|
+
// text is optional — auto-converted from html if omitted
|
|
209
214
|
attachments: [
|
|
210
215
|
{
|
|
211
216
|
filename: 'report.txt',
|
|
@@ -216,7 +221,21 @@ await mailer.sendRaw({
|
|
|
216
221
|
});
|
|
217
222
|
```
|
|
218
223
|
|
|
219
|
-
### 5.
|
|
224
|
+
### 5. Parsing RFC 5322 Email Addresses
|
|
225
|
+
|
|
226
|
+
If your application receives combined address strings like `"Jane Doe <jane@example.com>"`, use the standalone, tree-shakeable `parseEmailAddress` helper:
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
import { parseEmailAddress } from 'ts-mailkit';
|
|
230
|
+
|
|
231
|
+
const recipient = parseEmailAddress('Jane Doe <jane@example.com>');
|
|
232
|
+
// => { address: 'jane@example.com', name: 'Jane Doe' }
|
|
233
|
+
|
|
234
|
+
const simple = parseEmailAddress('jane@example.com');
|
|
235
|
+
// => { address: 'jane@example.com' }
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### 6. Pluggable Transports (`IEmailSender`)
|
|
220
239
|
|
|
221
240
|
You can implement custom transports (e.g. SMTP, Resend, SendGrid, Postmark) by satisfying the `IEmailSender` interface:
|
|
222
241
|
|
|
@@ -238,6 +257,14 @@ export class CustomSmtpSender implements IEmailSender {
|
|
|
238
257
|
|
|
239
258
|
---
|
|
240
259
|
|
|
260
|
+
## Template Preview
|
|
261
|
+
|
|
262
|
+
You can inspect what the default responsive email template looks like without writing code or installing the library:
|
|
263
|
+
|
|
264
|
+
- 📄 **[demo-newsletter.html](demo-newsletter.html)** — Standalone, fully pre-rendered HTML newsletter showcasing top-center brand logo, hero banner, typography, call-to-action button, and footer. Generated automatically during the test suite.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
241
268
|
## Development & Testing
|
|
242
269
|
|
|
243
270
|
```bash
|
|
@@ -261,12 +288,14 @@ pnpm run prepublishOnly
|
|
|
261
288
|
|
|
262
289
|
## Deprecated API (Scheduled for Removal in v1.0.0)
|
|
263
290
|
|
|
264
|
-
The following legacy migration bridges are marked `@deprecated` and scheduled for removal in `v1.0.0`:
|
|
291
|
+
The following legacy migration bridges and aliases are marked `@deprecated` and scheduled for removal in `v1.0.0`:
|
|
265
292
|
|
|
266
293
|
| Deprecated | Replacement | Notes |
|
|
267
294
|
| :--- | :--- | :--- |
|
|
268
|
-
| `
|
|
295
|
+
| `ZeptoMailSender` | `ZeptoMailHttpSender` | Renamed to explicitly signify HTTP transport adapter. |
|
|
296
|
+
| `ZeptoMailConfig` | `ZeptoMailHttpConfig` | Configuration interface rename. |
|
|
269
297
|
| `sender.sendEmail(...)` | `sender.send({ to, subject, html, text, ... })` | Standardized on `SendMailOptions`. |
|
|
298
|
+
| `mailer.send(to, template, toName)` | `mailer.send({ to, template, ... })` | Use the type-safe options object. |
|
|
270
299
|
| `mailer.sendSimpleMessage(...)` | `mailer.sendRaw({ to, subject, text, html })` | Direct raw email dispatch. |
|
|
271
300
|
| `mailer.buildPlainTextMessage(template)` | `mailer.render(template)` or `buildPlainText(dto)` | Standalone or client renderer methods. |
|
|
272
301
|
| `EmailService` | `MailKit` | Main client class. |
|
package/dist/core/client.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export interface SendTemplateOptions {
|
|
|
54
54
|
}
|
|
55
55
|
export interface MailKitOptions {
|
|
56
56
|
/**
|
|
57
|
-
* The transport adapter used to dispatch emails (e.g.
|
|
57
|
+
* The transport adapter used to dispatch emails (e.g. ZeptoMailHttpSender, MemoryEmailSender).
|
|
58
58
|
*/
|
|
59
59
|
transport: IEmailSender;
|
|
60
60
|
/**
|
|
@@ -94,44 +94,48 @@ export declare class MailKit {
|
|
|
94
94
|
*/
|
|
95
95
|
render(template: EmailTemplateDto): Promise<RenderedEmail>;
|
|
96
96
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
97
|
+
* Legacy positional send signature for backwards compatibility with 0.1.x:
|
|
98
|
+
* `send(to: string, template: EmailTemplateDto, toName?: string): Promise<SendResult>`
|
|
99
|
+
*
|
|
100
|
+
* @deprecated Use `send({ to, template, ... })` instead. This overload will be removed in v1.0.0.
|
|
99
101
|
*/
|
|
100
|
-
|
|
102
|
+
send(to: string, template: EmailTemplateDto, toName?: string): Promise<SendResult>;
|
|
101
103
|
/**
|
|
102
104
|
* Sends an email using a strongly-typed template DTO.
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
105
|
+
*
|
|
106
|
+
* Example:
|
|
107
|
+
* ```ts
|
|
108
|
+
* await mailer.send({
|
|
109
|
+
* to: 'user@example.com',
|
|
110
|
+
* template: myDto,
|
|
111
|
+
* });
|
|
112
|
+
* ```
|
|
107
113
|
*/
|
|
108
114
|
send(options: SendTemplateOptions): Promise<SendResult>;
|
|
109
|
-
/**
|
|
110
|
-
* @deprecated Use the options object signature `mailer.send({ to, template, ... })` instead. Positional signature will be removed in v1.0.0.
|
|
111
|
-
*/
|
|
112
|
-
send(to: string, template: EmailTemplateDto, toName?: string): Promise<SendResult>;
|
|
113
115
|
/**
|
|
114
116
|
* Dispatches a raw, pre-rendered email directly through the transport.
|
|
117
|
+
* If `options.text` is omitted, plain text is automatically derived from `options.html`.
|
|
115
118
|
*/
|
|
116
119
|
sendRaw(options: SendMailOptions): Promise<SendResult>;
|
|
117
120
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* @deprecated Use `mailer.sendRaw({ to, subject, text, html })` instead. This method will be removed in v1.0.0.
|
|
121
|
+
* Helper method matching legacy 0.1.x `sendSimpleMessage(to, subject, text, fromName?)`.
|
|
122
|
+
* @deprecated Use `sendRaw({ to, subject, text, ... })` instead. This method will be removed in v1.0.0.
|
|
121
123
|
*/
|
|
122
|
-
sendSimpleMessage(to: string, subject: string, text: string,
|
|
124
|
+
sendSimpleMessage(to: string, subject: string, text: string, fromName?: string): Promise<SendResult>;
|
|
125
|
+
/**
|
|
126
|
+
* Legacy helper method to construct plain text from a template.
|
|
127
|
+
* @deprecated Use `render(template)` or `buildPlainText(dto)` instead. This method will be removed in v1.0.0.
|
|
128
|
+
*/
|
|
129
|
+
buildPlainTextMessage(template: EmailTemplateDto): string;
|
|
123
130
|
}
|
|
124
131
|
/**
|
|
125
|
-
*
|
|
126
|
-
* @deprecated Use `MailKit` instead. This alias will be removed in v1.0.0.
|
|
132
|
+
* Convenience factory to create a MailKit client instance.
|
|
127
133
|
*/
|
|
128
|
-
export declare
|
|
134
|
+
export declare function createMailKit(options: MailKitOptions): MailKit;
|
|
129
135
|
/**
|
|
136
|
+
* Backward-compatibility alias for `MailKit`.
|
|
130
137
|
* @deprecated Use `MailKit` instead. This alias will be removed in v1.0.0.
|
|
131
138
|
*/
|
|
139
|
+
export declare const EmailService: typeof MailKit;
|
|
132
140
|
export type EmailService = MailKit;
|
|
133
|
-
/**
|
|
134
|
-
* Convenience factory to create a MailKit client instance.
|
|
135
|
-
*/
|
|
136
|
-
export declare function createMailKit(options: MailKitOptions): MailKit;
|
|
137
141
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"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"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -14,6 +14,14 @@ export type Recipient = string | EmailAddress | {
|
|
|
14
14
|
email: string;
|
|
15
15
|
name?: string;
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Parses an RFC 5322 formatted address string into an EmailAddress.
|
|
19
|
+
* Supports formats such as:
|
|
20
|
+
* - "user@example.com" -> { address: "user@example.com" }
|
|
21
|
+
* - "Sender Name <sender@example.com>" -> { name: "Sender Name", address: "sender@example.com" }
|
|
22
|
+
* - "\"Sender Name\" <sender@example.com>" -> { name: "Sender Name", address: "sender@example.com" }
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseEmailAddress(input: string): EmailAddress;
|
|
17
25
|
/**
|
|
18
26
|
* Normalizes a Recipient value into a standardized EmailAddress.
|
|
19
27
|
*/
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,YAAY,GACZ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,YAAY,CAcrE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,GACnC,YAAY,EAAE,CAIhB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC7B,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,YAAY,GACZ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAa7D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,YAAY,CAcrE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,GACnC,YAAY,EAAE,CAIhB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC7B,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
|
package/dist/index.cjs
CHANGED
|
@@ -30,18 +30,35 @@ __export(index_exports, {
|
|
|
30
30
|
MemoryEmailSender: () => MemoryEmailSender,
|
|
31
31
|
TemplateError: () => TemplateError,
|
|
32
32
|
TransportError: () => TransportError,
|
|
33
|
+
ZeptoMailHttpSender: () => ZeptoMailHttpSender,
|
|
33
34
|
ZeptoMailSender: () => ZeptoMailSender,
|
|
34
35
|
buildHtml: () => buildHtml,
|
|
35
36
|
buildPlainText: () => buildPlainText,
|
|
36
37
|
createMailKit: () => createMailKit,
|
|
37
38
|
decodeHtmlEntities: () => decodeHtmlEntities,
|
|
38
39
|
htmlToPlainText: () => htmlToPlainText,
|
|
40
|
+
isValidHttpUrl: () => isValidHttpUrl,
|
|
39
41
|
normalizeRecipient: () => normalizeRecipient,
|
|
40
|
-
normalizeRecipients: () => normalizeRecipients
|
|
42
|
+
normalizeRecipients: () => normalizeRecipients,
|
|
43
|
+
parseEmailAddress: () => parseEmailAddress
|
|
41
44
|
});
|
|
42
45
|
module.exports = __toCommonJS(index_exports);
|
|
43
46
|
|
|
44
47
|
// src/core/types.ts
|
|
48
|
+
function parseEmailAddress(input) {
|
|
49
|
+
if (!input || typeof input !== "string") {
|
|
50
|
+
return { address: "" };
|
|
51
|
+
}
|
|
52
|
+
const trimmed = input.trim();
|
|
53
|
+
const match = trimmed.match(/^(?:["']?([^"']+)["']?\s+)?<?([^\s<>@]+@[^\s<>@]+)>?$/);
|
|
54
|
+
if (!match) {
|
|
55
|
+
return { address: trimmed };
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
address: match[2].trim(),
|
|
59
|
+
name: match[1]?.trim() || void 0
|
|
60
|
+
};
|
|
61
|
+
}
|
|
45
62
|
function normalizeRecipient(recipient) {
|
|
46
63
|
if (typeof recipient === "string") {
|
|
47
64
|
return { address: recipient.trim() };
|
|
@@ -113,6 +130,15 @@ function htmlToPlainText(html) {
|
|
|
113
130
|
}
|
|
114
131
|
|
|
115
132
|
// src/renderers/default/default-renderer.ts
|
|
133
|
+
function isValidHttpUrl(urlString) {
|
|
134
|
+
if (!urlString || typeof urlString !== "string") return false;
|
|
135
|
+
try {
|
|
136
|
+
const url = new URL(urlString.trim());
|
|
137
|
+
return (url.protocol === "http:" || url.protocol === "https:") && url.hostname.length > 0;
|
|
138
|
+
} catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
116
142
|
function buildPlainText(dto) {
|
|
117
143
|
if (dto.noHtmlMessage) {
|
|
118
144
|
return dto.noHtmlMessage;
|
|
@@ -155,6 +181,15 @@ function buildHtml(dto, options = {}) {
|
|
|
155
181
|
`<body style="margin:0;padding:24px 16px;background-color:#f9fafb;font-family:${fontFamily};color:#1f2937;line-height:1.6;">`,
|
|
156
182
|
`<div style="max-width:${maxWidth};margin:0 auto;background-color:#ffffff;padding:32px 28px;border-radius:8px;box-shadow:0 1px 3px rgba(0,0,0,0.1);border:1px solid #f3f4f6;">`
|
|
157
183
|
];
|
|
184
|
+
const logoCandidate = dto.logoUrl ?? options.logoUrl;
|
|
185
|
+
if (logoCandidate && isValidHttpUrl(logoCandidate)) {
|
|
186
|
+
const validLogo = logoCandidate.trim();
|
|
187
|
+
parts.push(
|
|
188
|
+
`<div style="margin-bottom:24px;text-align:center;">`,
|
|
189
|
+
` <img src="${validLogo}" alt="${dto.fromName || "Logo"}" style="max-height:48px;max-width:200px;height:auto;width:auto;display:inline-block;border:0;outline:none;text-decoration:none;" />`,
|
|
190
|
+
`</div>`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
158
193
|
if (dto.imageUrl) {
|
|
159
194
|
parts.push(
|
|
160
195
|
`<div style="margin-bottom:24px;text-align:center;">`,
|
|
@@ -239,30 +274,15 @@ var MailKit = class {
|
|
|
239
274
|
async render(template) {
|
|
240
275
|
return await this.renderer.render(template);
|
|
241
276
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
let
|
|
251
|
-
if (typeof optionsOrTo === "string") {
|
|
252
|
-
if (!maybeTemplate) {
|
|
253
|
-
throw new ConfigurationError("MailKit.send: Missing required template DTO argument.");
|
|
254
|
-
}
|
|
255
|
-
opts = {
|
|
256
|
-
to: optionsOrTo,
|
|
257
|
-
template: maybeTemplate,
|
|
258
|
-
toName: maybeToName
|
|
259
|
-
};
|
|
260
|
-
} else {
|
|
261
|
-
opts = optionsOrTo;
|
|
262
|
-
}
|
|
263
|
-
const template = opts.template;
|
|
264
|
-
const recipientName = opts.toName ?? template.userName;
|
|
265
|
-
let resolvedFromName = opts.fromName ?? template.fromName;
|
|
277
|
+
async send(toOrOptions, maybeTemplate, maybeToName) {
|
|
278
|
+
const options = typeof toOrOptions === "string" ? {
|
|
279
|
+
to: toOrOptions,
|
|
280
|
+
template: maybeTemplate,
|
|
281
|
+
toName: maybeToName
|
|
282
|
+
} : toOrOptions;
|
|
283
|
+
const template = options.template;
|
|
284
|
+
const recipientName = options.toName ?? template.userName;
|
|
285
|
+
let resolvedFromName = options.fromName ?? template.fromName;
|
|
266
286
|
if (!resolvedFromName && this.brandNameResolver) {
|
|
267
287
|
resolvedFromName = await this.brandNameResolver();
|
|
268
288
|
}
|
|
@@ -272,12 +292,12 @@ var MailKit = class {
|
|
|
272
292
|
const rendered = await this.renderer.render(template);
|
|
273
293
|
const plaintextBody = template.noHtmlMessage ?? rendered.text;
|
|
274
294
|
let toRecipients;
|
|
275
|
-
if (typeof
|
|
276
|
-
toRecipients = { address:
|
|
295
|
+
if (typeof options.to === "string" && recipientName) {
|
|
296
|
+
toRecipients = { address: options.to, name: recipientName };
|
|
277
297
|
} else {
|
|
278
|
-
toRecipients =
|
|
298
|
+
toRecipients = options.to;
|
|
279
299
|
}
|
|
280
|
-
let from =
|
|
300
|
+
let from = options.from ?? this.defaultFrom;
|
|
281
301
|
if (resolvedFromName && from) {
|
|
282
302
|
const normalizedFrom = normalizeRecipient(from);
|
|
283
303
|
from = { address: normalizedFrom.address, name: resolvedFromName };
|
|
@@ -288,47 +308,56 @@ var MailKit = class {
|
|
|
288
308
|
subject: template.subject,
|
|
289
309
|
html: rendered.html,
|
|
290
310
|
text: plaintextBody,
|
|
291
|
-
cc:
|
|
292
|
-
bcc:
|
|
293
|
-
replyTo:
|
|
294
|
-
attachments:
|
|
295
|
-
headers:
|
|
296
|
-
tags:
|
|
297
|
-
metadata:
|
|
311
|
+
cc: options.cc,
|
|
312
|
+
bcc: options.bcc,
|
|
313
|
+
replyTo: options.replyTo,
|
|
314
|
+
attachments: options.attachments,
|
|
315
|
+
headers: options.headers,
|
|
316
|
+
tags: options.tags,
|
|
317
|
+
metadata: options.metadata
|
|
298
318
|
});
|
|
299
319
|
}
|
|
300
320
|
/**
|
|
301
321
|
* Dispatches a raw, pre-rendered email directly through the transport.
|
|
322
|
+
* If `options.text` is omitted, plain text is automatically derived from `options.html`.
|
|
302
323
|
*/
|
|
303
324
|
async sendRaw(options) {
|
|
304
325
|
const from = options.from ?? this.defaultFrom;
|
|
326
|
+
const text = options.text ?? (options.html ? htmlToPlainText(options.html) : void 0);
|
|
305
327
|
return await this.transport.send({
|
|
306
328
|
...options,
|
|
307
|
-
from
|
|
329
|
+
from,
|
|
330
|
+
text
|
|
308
331
|
});
|
|
309
332
|
}
|
|
310
333
|
/**
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
* @deprecated Use `mailer.sendRaw({ to, subject, text, html })` instead. This method will be removed in v1.0.0.
|
|
334
|
+
* Helper method matching legacy 0.1.x `sendSimpleMessage(to, subject, text, fromName?)`.
|
|
335
|
+
* @deprecated Use `sendRaw({ to, subject, text, ... })` instead. This method will be removed in v1.0.0.
|
|
314
336
|
*/
|
|
315
|
-
async sendSimpleMessage(to, subject, text,
|
|
316
|
-
const html = `<pre style="font-family:monospace;white-space:pre-wrap;">${text}</pre>`;
|
|
337
|
+
async sendSimpleMessage(to, subject, text, fromName) {
|
|
317
338
|
return await this.sendRaw({
|
|
318
|
-
to
|
|
339
|
+
to,
|
|
319
340
|
subject,
|
|
320
|
-
|
|
321
|
-
text
|
|
341
|
+
text,
|
|
342
|
+
html: `<pre style="font-family:monospace;white-space:pre-wrap;">${text}</pre>`,
|
|
343
|
+
from: fromName && this.defaultFrom ? { address: normalizeRecipient(this.defaultFrom).address, name: fromName } : this.defaultFrom
|
|
322
344
|
});
|
|
323
345
|
}
|
|
346
|
+
/**
|
|
347
|
+
* Legacy helper method to construct plain text from a template.
|
|
348
|
+
* @deprecated Use `render(template)` or `buildPlainText(dto)` instead. This method will be removed in v1.0.0.
|
|
349
|
+
*/
|
|
350
|
+
buildPlainTextMessage(template) {
|
|
351
|
+
return template.noHtmlMessage ?? buildPlainText(template);
|
|
352
|
+
}
|
|
324
353
|
};
|
|
325
|
-
var EmailService = MailKit;
|
|
326
354
|
function createMailKit(options) {
|
|
327
355
|
return new MailKit(options);
|
|
328
356
|
}
|
|
357
|
+
var EmailService = MailKit;
|
|
329
358
|
|
|
330
359
|
// src/transports/zeptomail/zeptomail-sender.ts
|
|
331
|
-
var
|
|
360
|
+
var ZeptoMailHttpSender = class {
|
|
332
361
|
name = "zeptomail";
|
|
333
362
|
apiUrl;
|
|
334
363
|
authHeader;
|
|
@@ -336,10 +365,10 @@ var ZeptoMailSender = class {
|
|
|
336
365
|
fetchImpl;
|
|
337
366
|
constructor(config) {
|
|
338
367
|
if (!config.apiToken || typeof config.apiToken !== "string") {
|
|
339
|
-
throw new ConfigurationError("
|
|
368
|
+
throw new ConfigurationError("ZeptoMailHttpSender: Missing or invalid apiToken.");
|
|
340
369
|
}
|
|
341
370
|
if (!config.from) {
|
|
342
|
-
throw new ConfigurationError("
|
|
371
|
+
throw new ConfigurationError("ZeptoMailHttpSender: Missing required default from address.");
|
|
343
372
|
}
|
|
344
373
|
const host = (config.apiHost || "api.zeptomail.com").replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
345
374
|
this.apiUrl = `https://${host}/v1.1/email`;
|
|
@@ -347,14 +376,15 @@ var ZeptoMailSender = class {
|
|
|
347
376
|
this.authHeader = token.startsWith("Zoho-") ? token : `Zoho-enczapikey ${token}`;
|
|
348
377
|
this.defaultFrom = normalizeRecipient(config.from);
|
|
349
378
|
if (!this.defaultFrom.address) {
|
|
350
|
-
throw new ConfigurationError("
|
|
379
|
+
throw new ConfigurationError("ZeptoMailHttpSender: Configured from address must not be empty.");
|
|
351
380
|
}
|
|
352
|
-
|
|
353
|
-
if (typeof
|
|
381
|
+
const fetchImpl = config.fetch ?? globalThis.fetch;
|
|
382
|
+
if (typeof fetchImpl !== "function") {
|
|
354
383
|
throw new ConfigurationError(
|
|
355
|
-
"
|
|
384
|
+
"ZeptoMailHttpSender: No global fetch implementation found. Pass a custom fetch to ZeptoMailHttpConfig if running on Node < 18."
|
|
356
385
|
);
|
|
357
386
|
}
|
|
387
|
+
this.fetchImpl = fetchImpl.bind(globalThis);
|
|
358
388
|
}
|
|
359
389
|
/**
|
|
360
390
|
* Dispatches an email using Zoho ZeptoMail API v1.1.
|
|
@@ -362,7 +392,7 @@ var ZeptoMailSender = class {
|
|
|
362
392
|
async send(options) {
|
|
363
393
|
const toRecipients = normalizeRecipients(options.to);
|
|
364
394
|
if (toRecipients.length === 0) {
|
|
365
|
-
throw new TransportError("
|
|
395
|
+
throw new TransportError("ZeptoMailHttpSender: At least one recipient (to) must be specified.", {
|
|
366
396
|
transportName: this.name
|
|
367
397
|
});
|
|
368
398
|
}
|
|
@@ -444,7 +474,7 @@ var ZeptoMailSender = class {
|
|
|
444
474
|
body: JSON.stringify(payload)
|
|
445
475
|
});
|
|
446
476
|
} catch (err) {
|
|
447
|
-
throw new TransportError(`
|
|
477
|
+
throw new TransportError(`ZeptoMailHttpSender: Network request failed: ${err instanceof Error ? err.message : String(err)}`, {
|
|
448
478
|
transportName: this.name,
|
|
449
479
|
cause: err
|
|
450
480
|
});
|
|
@@ -458,7 +488,7 @@ var ZeptoMailSender = class {
|
|
|
458
488
|
}
|
|
459
489
|
if (!response.ok) {
|
|
460
490
|
const errorMessage = responseData?.error?.message || responseData?.message || `HTTP ${response.status}: ${responseText || response.statusText}`;
|
|
461
|
-
throw new TransportError(`
|
|
491
|
+
throw new TransportError(`ZeptoMailHttpSender: Failed to send email - ${errorMessage}`, {
|
|
462
492
|
transportName: this.name,
|
|
463
493
|
statusCode: response.status,
|
|
464
494
|
responseBody: responseText
|
|
@@ -486,6 +516,7 @@ var ZeptoMailSender = class {
|
|
|
486
516
|
});
|
|
487
517
|
}
|
|
488
518
|
};
|
|
519
|
+
var ZeptoMailSender = ZeptoMailHttpSender;
|
|
489
520
|
|
|
490
521
|
// src/transports/memory/memory-sender.ts
|
|
491
522
|
var MemoryEmailSender = class {
|
|
@@ -584,9 +615,11 @@ var EmailTemplateFactory = class _EmailTemplateFactory {
|
|
|
584
615
|
defaultBrandName;
|
|
585
616
|
defaultSecurityMessage;
|
|
586
617
|
footerResolver;
|
|
618
|
+
defaultLogoUrl;
|
|
587
619
|
constructor(config = {}) {
|
|
588
620
|
this.defaultBrandName = config.brandName || "Application";
|
|
589
621
|
this.defaultSecurityMessage = config.securityMessage || DEFAULT_SECURITY_MESSAGE;
|
|
622
|
+
this.defaultLogoUrl = config.logoUrl;
|
|
590
623
|
if (typeof config.footer === "function") {
|
|
591
624
|
this.footerResolver = config.footer;
|
|
592
625
|
} else if (typeof config.footer === "string") {
|
|
@@ -612,6 +645,7 @@ var EmailTemplateFactory = class _EmailTemplateFactory {
|
|
|
612
645
|
subject: "Verify Your Email Address",
|
|
613
646
|
header: `Welcome to ${brand}!`,
|
|
614
647
|
body,
|
|
648
|
+
logoUrl: this.defaultLogoUrl,
|
|
615
649
|
otpCode: otp,
|
|
616
650
|
actionUrl: verificationUrl,
|
|
617
651
|
actionText: "Verify Email",
|
|
@@ -640,6 +674,7 @@ Your OTP code is: ${otp}` : "";
|
|
|
640
674
|
subject: "Password Reset Request",
|
|
641
675
|
header: "Reset Your Password",
|
|
642
676
|
body,
|
|
677
|
+
logoUrl: this.defaultLogoUrl,
|
|
643
678
|
otpCode: otp || void 0,
|
|
644
679
|
actionUrl: resetUrl,
|
|
645
680
|
actionText: "Reset Password",
|
|
@@ -662,6 +697,7 @@ ${resetUrl}`
|
|
|
662
697
|
subject,
|
|
663
698
|
header,
|
|
664
699
|
body,
|
|
700
|
+
logoUrl: this.defaultLogoUrl,
|
|
665
701
|
footer: this.buildFooter(brand),
|
|
666
702
|
fromName: brand,
|
|
667
703
|
noHtmlMessage: htmlToPlainText(body)
|
|
@@ -670,7 +706,7 @@ ${resetUrl}`
|
|
|
670
706
|
/**
|
|
671
707
|
* Newsletter / announcement email with an optional hero image and CTA button.
|
|
672
708
|
*/
|
|
673
|
-
createNewsLetter(subject, header, body, imageUrl, actionUrl, actionText, brandName) {
|
|
709
|
+
createNewsLetter(subject, header, body, imageUrl, actionUrl, actionText, brandName, logoUrl) {
|
|
674
710
|
const brand = this.resolveBrand(brandName);
|
|
675
711
|
let noHtmlMessage = htmlToPlainText(body);
|
|
676
712
|
if (actionUrl) {
|
|
@@ -682,6 +718,7 @@ ${actionText || "Learn more"}: ${actionUrl}`;
|
|
|
682
718
|
subject,
|
|
683
719
|
header,
|
|
684
720
|
body,
|
|
721
|
+
logoUrl: logoUrl || this.defaultLogoUrl,
|
|
685
722
|
imageUrl,
|
|
686
723
|
actionUrl,
|
|
687
724
|
actionText,
|
|
@@ -704,6 +741,7 @@ ${magicLink}` : "";
|
|
|
704
741
|
subject: "Your Login Verification Code",
|
|
705
742
|
header: "Two-Factor Authentication",
|
|
706
743
|
body,
|
|
744
|
+
logoUrl: this.defaultLogoUrl,
|
|
707
745
|
otpCode: otp,
|
|
708
746
|
actionUrl: magicLink || void 0,
|
|
709
747
|
actionText: magicLink ? "Verify Login" : void 0,
|
|
@@ -726,6 +764,7 @@ Your verification code is: ${otp}` + plainLink
|
|
|
726
764
|
subject: "Your Magic Link",
|
|
727
765
|
header: `Sign In to ${brand}`,
|
|
728
766
|
body,
|
|
767
|
+
logoUrl: this.defaultLogoUrl,
|
|
729
768
|
actionUrl: magicLink,
|
|
730
769
|
actionText: "Sign In",
|
|
731
770
|
extraMessage: this.defaultSecurityMessage,
|
|
@@ -755,7 +794,7 @@ ${magicLink}`
|
|
|
755
794
|
static createSimpleMessage(subject, header, body, brandName) {
|
|
756
795
|
return this.defaultInstance.createSimpleMessage(subject, header, body, brandName);
|
|
757
796
|
}
|
|
758
|
-
static createNewsLetter(subject, header, body, imageUrl, actionUrl, actionText, brandName) {
|
|
797
|
+
static createNewsLetter(subject, header, body, imageUrl, actionUrl, actionText, brandName, logoUrl) {
|
|
759
798
|
return this.defaultInstance.createNewsLetter(
|
|
760
799
|
subject,
|
|
761
800
|
header,
|
|
@@ -763,7 +802,8 @@ ${magicLink}`
|
|
|
763
802
|
imageUrl,
|
|
764
803
|
actionUrl,
|
|
765
804
|
actionText,
|
|
766
|
-
brandName
|
|
805
|
+
brandName,
|
|
806
|
+
logoUrl
|
|
767
807
|
);
|
|
768
808
|
}
|
|
769
809
|
static create2FAEmail(username, otp, magicLink, brandName) {
|
|
@@ -785,13 +825,16 @@ ${magicLink}`
|
|
|
785
825
|
MemoryEmailSender,
|
|
786
826
|
TemplateError,
|
|
787
827
|
TransportError,
|
|
828
|
+
ZeptoMailHttpSender,
|
|
788
829
|
ZeptoMailSender,
|
|
789
830
|
buildHtml,
|
|
790
831
|
buildPlainText,
|
|
791
832
|
createMailKit,
|
|
792
833
|
decodeHtmlEntities,
|
|
793
834
|
htmlToPlainText,
|
|
835
|
+
isValidHttpUrl,
|
|
794
836
|
normalizeRecipient,
|
|
795
|
-
normalizeRecipients
|
|
837
|
+
normalizeRecipients,
|
|
838
|
+
parseEmailAddress
|
|
796
839
|
});
|
|
797
840
|
//# sourceMappingURL=index.cjs.map
|