@breadstone/archipel-platform-mailing 0.0.23 → 0.0.25
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 +62 -47
- package/package.json +21 -7
- package/src/{terminus → health}/MailHealthIndicator.d.ts +1 -1
- package/src/{terminus → health}/MailHealthIndicator.js +3 -3
- package/src/health/index.d.ts +1 -0
- package/src/health/index.js +6 -0
- package/src/index.d.ts +2 -1
- package/src/index.js +1 -1
- package/src/services/MailVerificationService.d.ts +10 -21
- package/src/services/MailVerificationService.js +14 -64
- package/src/services/SmtpConnectionVerifier.d.ts +30 -0
- package/src/services/SmtpConnectionVerifier.js +78 -0
- package/src/tokens/MailModule.d.ts +31 -0
- package/src/tokens/MailModule.js +82 -79
package/README.md
CHANGED
|
@@ -2,7 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
Multi-strategy email delivery for NestJS with support for SMTP, Postmark, Resend, SendGrid, and Mailgun.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multi-provider** — Switch between SMTP, Postmark, Resend, SendGrid, or Mailgun via config
|
|
8
|
+
- **Subpath imports** — Each provider lives in its own subpath — install only the SDK you need
|
|
9
|
+
- **Template engines** — File-based or blob-based template fetching with variable substitution
|
|
10
|
+
- **Health checks** — `MailHealthIndicator` for readiness probes (separate `/health` subpath)
|
|
11
|
+
- **SMTP connection verification** — `SmtpConnectionVerifier` for verifying SMTP server reachability and sending test emails
|
|
12
|
+
- **Attachment support** — Send file attachments with MIME-type validation and size limits (25 MB max)
|
|
13
|
+
- **Header injection prevention** — Subject lines are automatically sanitized against SMTP header injection
|
|
14
|
+
|
|
15
|
+
> **Deprecation notice:** `MailVerificationService` is deprecated. Use `SmtpConnectionVerifier` instead — it provides `verifyConnection()` and `sendTestEmail()` methods.
|
|
16
|
+
|
|
17
|
+
## ⚠️ Environment Variables
|
|
6
18
|
|
|
7
19
|
### Core mailing configuration
|
|
8
20
|
|
|
@@ -37,18 +49,6 @@ Multi-strategy email delivery for NestJS with support for SMTP, Postmark, Resend
|
|
|
37
49
|
| `MAIL_USER` | no | `''` | Health-check mail user |
|
|
38
50
|
| `MAIL_PORT` | no | `0` | Health-check mail port |
|
|
39
51
|
|
|
40
|
-
## Import Options
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
import { MailModule, MailService } from '@breadstone/archipel-platform-mailing';
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Provider-specific import:
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
import { PostmarkDeliveryStrategy, POSTMARK_CONFIG_ENTRIES } from '@breadstone/archipel-platform-mailing/postmark';
|
|
50
|
-
```
|
|
51
|
-
|
|
52
52
|
## Quick Start
|
|
53
53
|
|
|
54
54
|
```typescript
|
|
@@ -63,50 +63,65 @@ export class AppModule {}
|
|
|
63
63
|
|
|
64
64
|
Set `MAIL_DELIVERY_STRATEGY` to one of: `smtp`, `postmark`, `resend`, `sendgrid`, `mailgun`, `log`.
|
|
65
65
|
|
|
66
|
-
##
|
|
66
|
+
## Supported Providers
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
-
|
|
73
|
-
|
|
74
|
-
- **Header injection prevention**: Subject lines are automatically sanitized against SMTP header injection
|
|
68
|
+
| Subpath | Class | SDK |
|
|
69
|
+
| ------------------------------------------------ | -------------------------- | ---------------- |
|
|
70
|
+
| `@breadstone/archipel-platform-mailing/postmark` | `PostmarkDeliveryStrategy` | `postmark` |
|
|
71
|
+
| `@breadstone/archipel-platform-mailing/resend` | `ResendDeliveryStrategy` | `resend` |
|
|
72
|
+
| `@breadstone/archipel-platform-mailing/sendgrid` | `SendGridDeliveryStrategy` | `@sendgrid/mail` |
|
|
73
|
+
| `@breadstone/archipel-platform-mailing/mailgun` | `MailgunDeliveryStrategy` | `mailgun.js` |
|
|
75
74
|
|
|
76
|
-
|
|
75
|
+
SMTP and Log strategies are built-in (no external SDK required).
|
|
77
76
|
|
|
78
|
-
|
|
77
|
+
## Import Options
|
|
79
78
|
|
|
80
79
|
```typescript
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
80
|
+
// Main import (module, service)
|
|
81
|
+
import { MailModule, MailService } from '@breadstone/archipel-platform-mailing';
|
|
82
|
+
|
|
83
|
+
// Built-in strategies
|
|
84
|
+
import { SmtpDeliveryStrategy } from '@breadstone/archipel-platform-mailing/smtp';
|
|
85
|
+
import { LogDeliveryStrategy } from '@breadstone/archipel-platform-mailing/log';
|
|
86
|
+
|
|
87
|
+
// Provider-specific (tree-shakable sub-exports)
|
|
88
|
+
import { PostmarkDeliveryStrategy, POSTMARK_CONFIG_ENTRIES } from '@breadstone/archipel-platform-mailing/postmark';
|
|
89
|
+
import { ResendDeliveryStrategy } from '@breadstone/archipel-platform-mailing/resend';
|
|
90
|
+
import { SendGridDeliveryStrategy } from '@breadstone/archipel-platform-mailing/sendgrid';
|
|
91
|
+
import { MailgunDeliveryStrategy } from '@breadstone/archipel-platform-mailing/mailgun';
|
|
92
|
+
|
|
93
|
+
// Health indicator (optional)
|
|
94
|
+
import { MailHealthIndicator } from '@breadstone/archipel-platform-mailing/health';
|
|
92
95
|
```
|
|
93
96
|
|
|
94
|
-
|
|
95
|
-
| ---------- | --------- | ----------------------------------------------- |
|
|
96
|
-
| `code` | `string` | Always `'MAIL_DELIVERY'` |
|
|
97
|
-
| `provider` | `string` | Provider that failed (`smtp`, `postmark`, etc.) |
|
|
98
|
-
| `cause` | `unknown` | Original error from the provider SDK |
|
|
97
|
+
## Error Handling
|
|
99
98
|
|
|
100
|
-
|
|
99
|
+
| Error Class | Code | When Thrown |
|
|
100
|
+
| ------------------- | --------------- | ----------------------------------- |
|
|
101
|
+
| `MailDeliveryError` | `MAIL_DELIVERY` | Provider SDK failure during sending |
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
| ------------------------------------------------ | -------------------------- | ---------------- |
|
|
104
|
-
| `@breadstone/archipel-platform-mailing/postmark` | `PostmarkDeliveryStrategy` | `postmark` |
|
|
105
|
-
| `@breadstone/archipel-platform-mailing/resend` | `ResendDeliveryStrategy` | `resend` |
|
|
106
|
-
| `@breadstone/archipel-platform-mailing/sendgrid` | `SendGridDeliveryStrategy` | `@sendgrid/mail` |
|
|
107
|
-
| `@breadstone/archipel-platform-mailing/mailgun` | `MailgunDeliveryStrategy` | `mailgun.js` |
|
|
103
|
+
## Lifecycle
|
|
108
104
|
|
|
109
|
-
|
|
105
|
+
- **Startup (`OnModuleInit`):** `MailTemplateEngine` preloads and compiles templates.
|
|
106
|
+
- **Shutdown (`OnModuleDestroy`):** `MailEventSubscriber` unsubscribes from event streams.
|
|
107
|
+
|
|
108
|
+
## Peer Dependencies
|
|
109
|
+
|
|
110
|
+
| Package | Required | Notes |
|
|
111
|
+
| --------------------------------------------- | -------- | ------------------------------ |
|
|
112
|
+
| `@breadstone/archipel-platform-configuration` | Yes | Typed config key support |
|
|
113
|
+
| `@nestjs/common` | Yes | NestJS core |
|
|
114
|
+
| `nodemailer` | No | Required for SMTP strategy |
|
|
115
|
+
| `postmark` | No | Required for Postmark provider |
|
|
116
|
+
| `resend` | No | Required for Resend provider |
|
|
117
|
+
| `@sendgrid/mail` | No | Required for SendGrid provider |
|
|
118
|
+
| `mailgun.js` | No | Required for Mailgun provider |
|
|
119
|
+
| `@breadstone/archipel-platform-health` | No | Required for health indicator |
|
|
120
|
+
| `@nestjs/terminus` | No | Required for health indicator |
|
|
121
|
+
|
|
122
|
+
## Documentation
|
|
123
|
+
|
|
124
|
+
📖 **Package Docs:** [`.docs/packages/platform-mailing/index.md`](../../.docs/packages/platform-mailing/index.md)
|
|
110
125
|
|
|
111
126
|
## Development
|
|
112
127
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@breadstone/archipel-platform-mailing",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.25",
|
|
4
4
|
"description": "Email delivery with strategy-based transport and template engines for NestJS applications.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
],
|
|
25
25
|
"sendgrid": [
|
|
26
26
|
"./src/sendgrid/index.d.ts"
|
|
27
|
+
],
|
|
28
|
+
"health": [
|
|
29
|
+
"./src/health/index.d.ts"
|
|
27
30
|
]
|
|
28
31
|
}
|
|
29
32
|
},
|
|
@@ -56,12 +59,17 @@
|
|
|
56
59
|
"types": "./src/sendgrid/index.d.ts",
|
|
57
60
|
"default": "./src/sendgrid/index.js"
|
|
58
61
|
},
|
|
62
|
+
"./health": {
|
|
63
|
+
"types": "./src/health/index.d.ts",
|
|
64
|
+
"default": "./src/health/index.js"
|
|
65
|
+
},
|
|
59
66
|
"./package.json": "./package.json",
|
|
60
67
|
"./smtp/index": "./src/smtp/index.js",
|
|
61
68
|
"./postmark/index": "./src/postmark/index.js",
|
|
62
69
|
"./resend/index": "./src/resend/index.js",
|
|
63
70
|
"./sendgrid/index": "./src/sendgrid/index.js",
|
|
64
|
-
"./mailgun/index": "./src/mailgun/index.js"
|
|
71
|
+
"./mailgun/index": "./src/mailgun/index.js",
|
|
72
|
+
"./health/index": "./src/health/index.js"
|
|
65
73
|
},
|
|
66
74
|
"license": "MIT",
|
|
67
75
|
"repository": {
|
|
@@ -91,14 +99,14 @@
|
|
|
91
99
|
"README.md"
|
|
92
100
|
],
|
|
93
101
|
"dependencies": {
|
|
94
|
-
"@breadstone/archipel-platform-blob-storage": "0.0.
|
|
95
|
-
"@breadstone/archipel-platform-configuration": "0.0.
|
|
96
|
-
"@breadstone/archipel-platform-core": "0.0.
|
|
97
|
-
"@breadstone/archipel-platform-
|
|
98
|
-
"@breadstone/archipel-platform-resources": "0.0.23",
|
|
102
|
+
"@breadstone/archipel-platform-blob-storage": "0.0.25",
|
|
103
|
+
"@breadstone/archipel-platform-configuration": "0.0.25",
|
|
104
|
+
"@breadstone/archipel-platform-core": "0.0.25",
|
|
105
|
+
"@breadstone/archipel-platform-resources": "0.0.25",
|
|
99
106
|
"tslib": "2.8.1"
|
|
100
107
|
},
|
|
101
108
|
"peerDependencies": {
|
|
109
|
+
"@breadstone/archipel-platform-health": ">=0.0.1",
|
|
102
110
|
"@nestjs/common": ">=11.0.0",
|
|
103
111
|
"@nestjs/terminus": ">=11.0.0",
|
|
104
112
|
"@sendgrid/mail": ">=8.0.0",
|
|
@@ -110,6 +118,12 @@
|
|
|
110
118
|
"rxjs": ">=7.0.0"
|
|
111
119
|
},
|
|
112
120
|
"peerDependenciesMeta": {
|
|
121
|
+
"@breadstone/archipel-platform-health": {
|
|
122
|
+
"optional": true
|
|
123
|
+
},
|
|
124
|
+
"@nestjs/terminus": {
|
|
125
|
+
"optional": true
|
|
126
|
+
},
|
|
113
127
|
"@sendgrid/mail": {
|
|
114
128
|
"optional": true
|
|
115
129
|
},
|
|
@@ -22,11 +22,11 @@ let MailHealthIndicator = class MailHealthIndicator {
|
|
|
22
22
|
*/
|
|
23
23
|
constructor(configService) {
|
|
24
24
|
// #endregion
|
|
25
|
-
|
|
25
|
+
// #region Properties
|
|
26
26
|
this.key = 'mail';
|
|
27
27
|
this._configService = configService;
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
// #endregion
|
|
30
30
|
// #region Methods
|
|
31
31
|
/**
|
|
32
32
|
* Checks if the mail configuration is valid.
|
|
@@ -40,7 +40,7 @@ let MailHealthIndicator = class MailHealthIndicator {
|
|
|
40
40
|
const mailPort = this._configService.tryGet(env_1.MAIL_PORT.key, 0);
|
|
41
41
|
const isHealthy = mailHost !== '' && mailUser !== '' && mailPort > 0;
|
|
42
42
|
return {
|
|
43
|
-
|
|
43
|
+
mail: {
|
|
44
44
|
status: isHealthy ? 'up' : 'down',
|
|
45
45
|
...(isHealthy ? {} : { message: 'Mail configuration is invalid' }),
|
|
46
46
|
},
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MailHealthIndicator } from './MailHealthIndicator';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MailHealthIndicator = void 0;
|
|
4
|
+
var MailHealthIndicator_1 = require("./MailHealthIndicator");
|
|
5
|
+
Object.defineProperty(exports, "MailHealthIndicator", { enumerable: true, get: function () { return MailHealthIndicator_1.MailHealthIndicator; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.d.ts
CHANGED
|
@@ -5,8 +5,9 @@ export * from './MailTokens';
|
|
|
5
5
|
export * from './models/IMailAttachment';
|
|
6
6
|
export * from './services/MailService';
|
|
7
7
|
export * from './services/MailVerificationService';
|
|
8
|
+
export * from './services/SmtpConnectionVerifier';
|
|
8
9
|
export * from './services/strategies/abstracts/DeliveryStrategyBase';
|
|
9
10
|
export * from './templating/MailTemplateEngine';
|
|
10
11
|
export * from './templating/strategies/abstracts/TemplateFetchStrategyBase';
|
|
11
|
-
export * from './terminus/MailHealthIndicator';
|
|
12
12
|
export * from './tokens/MailModule';
|
|
13
|
+
export type { IMailModuleOptions } from './tokens/MailModule';
|
package/src/index.js
CHANGED
|
@@ -8,9 +8,9 @@ tslib_1.__exportStar(require("./MailTokens"), exports);
|
|
|
8
8
|
tslib_1.__exportStar(require("./models/IMailAttachment"), exports);
|
|
9
9
|
tslib_1.__exportStar(require("./services/MailService"), exports);
|
|
10
10
|
tslib_1.__exportStar(require("./services/MailVerificationService"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./services/SmtpConnectionVerifier"), exports);
|
|
11
12
|
tslib_1.__exportStar(require("./services/strategies/abstracts/DeliveryStrategyBase"), exports);
|
|
12
13
|
tslib_1.__exportStar(require("./templating/MailTemplateEngine"), exports);
|
|
13
14
|
tslib_1.__exportStar(require("./templating/strategies/abstracts/TemplateFetchStrategyBase"), exports);
|
|
14
|
-
tslib_1.__exportStar(require("./terminus/MailHealthIndicator"), exports);
|
|
15
15
|
tslib_1.__exportStar(require("./tokens/MailModule"), exports);
|
|
16
16
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,30 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SmtpConnectionVerifier } from './SmtpConnectionVerifier';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* @deprecated Use {@link SmtpConnectionVerifier} instead. This class will be
|
|
4
|
+
* removed in a future major release.
|
|
5
5
|
*
|
|
6
6
|
* @public
|
|
7
|
-
* @deprecated Renamed to `SmtpConnectionVerifier` in a future release to better
|
|
8
|
-
* reflect its actual purpose. Prefer wrapping this in a health-check rather
|
|
9
|
-
* than calling it directly.
|
|
10
7
|
*/
|
|
11
|
-
export declare class MailVerificationService {
|
|
12
|
-
private readonly _logger;
|
|
13
|
-
private readonly _transporter;
|
|
8
|
+
export declare class MailVerificationService extends SmtpConnectionVerifier {
|
|
14
9
|
/**
|
|
15
|
-
*
|
|
10
|
+
* Verifies SMTP server connectivity.
|
|
11
|
+
*
|
|
12
|
+
* @deprecated Use {@link SmtpConnectionVerifier.verifyConnection} instead.
|
|
13
|
+
* The `email` parameter was never used.
|
|
16
14
|
*
|
|
17
15
|
* @public
|
|
16
|
+
* @param _email - Unused. Kept for backward compatibility.
|
|
18
17
|
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Verifies if the email address is valid and reachable.
|
|
22
|
-
* @param email - The email address to verify
|
|
23
|
-
* @returns Promise<boolean> - Resolves true if email exists, false otherwise
|
|
24
|
-
*/
|
|
25
|
-
verifyEmail(email: string): Promise<boolean>;
|
|
26
|
-
/**
|
|
27
|
-
* Send an email for testing purposes or verification
|
|
28
|
-
*/
|
|
29
|
-
sendTestEmail(from: string, to: string, subject: string, text: string): Promise<void>;
|
|
18
|
+
verifyEmail(_email: string): Promise<boolean>;
|
|
30
19
|
}
|
|
@@ -1,84 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// #region Imports
|
|
3
|
-
var MailVerificationService_1;
|
|
4
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
4
|
exports.MailVerificationService = void 0;
|
|
6
5
|
const tslib_1 = require("tslib");
|
|
7
|
-
const archipel_platform_configuration_1 = require("@breadstone/archipel-platform-configuration");
|
|
8
6
|
const common_1 = require("@nestjs/common");
|
|
9
|
-
const
|
|
10
|
-
const env_1 = require("../env");
|
|
7
|
+
const SmtpConnectionVerifier_1 = require("./SmtpConnectionVerifier");
|
|
11
8
|
// #endregion
|
|
12
9
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
10
|
+
* @deprecated Use {@link SmtpConnectionVerifier} instead. This class will be
|
|
11
|
+
* removed in a future major release.
|
|
15
12
|
*
|
|
16
13
|
* @public
|
|
17
|
-
* @deprecated Renamed to `SmtpConnectionVerifier` in a future release to better
|
|
18
|
-
* reflect its actual purpose. Prefer wrapping this in a health-check rather
|
|
19
|
-
* than calling it directly.
|
|
20
14
|
*/
|
|
21
|
-
let MailVerificationService =
|
|
22
|
-
// #
|
|
23
|
-
// #region Ctor
|
|
15
|
+
let MailVerificationService = class MailVerificationService extends SmtpConnectionVerifier_1.SmtpConnectionVerifier {
|
|
16
|
+
// #region Methods
|
|
24
17
|
/**
|
|
25
|
-
*
|
|
18
|
+
* Verifies SMTP server connectivity.
|
|
19
|
+
*
|
|
20
|
+
* @deprecated Use {@link SmtpConnectionVerifier.verifyConnection} instead.
|
|
21
|
+
* The `email` parameter was never used.
|
|
26
22
|
*
|
|
27
23
|
* @public
|
|
24
|
+
* @param _email - Unused. Kept for backward compatibility.
|
|
28
25
|
*/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this._logger = new common_1.Logger(MailVerificationService_1.name);
|
|
32
|
-
this._transporter = nodemailer.createTransport({
|
|
33
|
-
host: configService.tryGet(env_1.MAIL_SMTP_HOST.key, 'localhost'),
|
|
34
|
-
port: 465,
|
|
35
|
-
secure: true,
|
|
36
|
-
auth: {
|
|
37
|
-
user: configService.tryGet(env_1.MAIL_SMTP_USER.key, ''),
|
|
38
|
-
pass: configService.tryGet(env_1.MAIL_SMTP_PASSWORD.key, ''),
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
// #endregion
|
|
43
|
-
/**
|
|
44
|
-
* Verifies if the email address is valid and reachable.
|
|
45
|
-
* @param email - The email address to verify
|
|
46
|
-
* @returns Promise<boolean> - Resolves true if email exists, false otherwise
|
|
47
|
-
*/
|
|
48
|
-
async verifyEmail(email) {
|
|
49
|
-
return new Promise((resolve, reject) => {
|
|
50
|
-
this._transporter.verify((error, success) => {
|
|
51
|
-
if (error) {
|
|
52
|
-
this._logger.error('SMTP verification error:', error);
|
|
53
|
-
resolve(false);
|
|
54
|
-
return; // Couldn't connect or verify
|
|
55
|
-
}
|
|
56
|
-
// Here we perform a simple check if the server is reachable
|
|
57
|
-
if (success) {
|
|
58
|
-
// Nodemailer does not explicitly verify an email exists but confirms server readiness.
|
|
59
|
-
resolve(true);
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
resolve(false);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Send an email for testing purposes or verification
|
|
69
|
-
*/
|
|
70
|
-
async sendTestEmail(from, to, subject, text) {
|
|
71
|
-
await this._transporter.sendMail({
|
|
72
|
-
from,
|
|
73
|
-
to,
|
|
74
|
-
subject,
|
|
75
|
-
text,
|
|
76
|
-
});
|
|
26
|
+
async verifyEmail(_email) {
|
|
27
|
+
return this.verifyConnection();
|
|
77
28
|
}
|
|
78
29
|
};
|
|
79
30
|
exports.MailVerificationService = MailVerificationService;
|
|
80
|
-
exports.MailVerificationService = MailVerificationService =
|
|
81
|
-
(0, common_1.Injectable)()
|
|
82
|
-
tslib_1.__metadata("design:paramtypes", [archipel_platform_configuration_1.ConfigService])
|
|
31
|
+
exports.MailVerificationService = MailVerificationService = tslib_1.__decorate([
|
|
32
|
+
(0, common_1.Injectable)()
|
|
83
33
|
], MailVerificationService);
|
|
84
34
|
//# sourceMappingURL=MailVerificationService.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ConfigService } from '@breadstone/archipel-platform-configuration';
|
|
2
|
+
/**
|
|
3
|
+
* Verifies SMTP server connectivity. Does **not** validate individual email
|
|
4
|
+
* addresses — only checks whether the configured SMTP transport is reachable.
|
|
5
|
+
*
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export declare class SmtpConnectionVerifier {
|
|
9
|
+
private readonly _logger;
|
|
10
|
+
private readonly _transporter;
|
|
11
|
+
/**
|
|
12
|
+
* Constructs a new instance of the {@link SmtpConnectionVerifier} class.
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
constructor(configService: ConfigService);
|
|
17
|
+
/**
|
|
18
|
+
* Verifies that the configured SMTP server is reachable.
|
|
19
|
+
*
|
|
20
|
+
* @public
|
|
21
|
+
* @returns `true` if the SMTP server is reachable, `false` otherwise.
|
|
22
|
+
*/
|
|
23
|
+
verifyConnection(): Promise<boolean>;
|
|
24
|
+
/**
|
|
25
|
+
* Send an email for testing purposes.
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
sendTestEmail(from: string, to: string, subject: string, text: string): Promise<void>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// #region Imports
|
|
3
|
+
var SmtpConnectionVerifier_1;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.SmtpConnectionVerifier = void 0;
|
|
6
|
+
const tslib_1 = require("tslib");
|
|
7
|
+
const archipel_platform_configuration_1 = require("@breadstone/archipel-platform-configuration");
|
|
8
|
+
const common_1 = require("@nestjs/common");
|
|
9
|
+
const nodemailer = tslib_1.__importStar(require("nodemailer"));
|
|
10
|
+
const env_1 = require("../env");
|
|
11
|
+
// #endregion
|
|
12
|
+
/**
|
|
13
|
+
* Verifies SMTP server connectivity. Does **not** validate individual email
|
|
14
|
+
* addresses — only checks whether the configured SMTP transport is reachable.
|
|
15
|
+
*
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
let SmtpConnectionVerifier = SmtpConnectionVerifier_1 = class SmtpConnectionVerifier {
|
|
19
|
+
// #endregion
|
|
20
|
+
// #region Ctor
|
|
21
|
+
/**
|
|
22
|
+
* Constructs a new instance of the {@link SmtpConnectionVerifier} class.
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
constructor(configService) {
|
|
27
|
+
// #region Fields
|
|
28
|
+
this._logger = new common_1.Logger(SmtpConnectionVerifier_1.name);
|
|
29
|
+
this._transporter = nodemailer.createTransport({
|
|
30
|
+
host: configService.tryGet(env_1.MAIL_SMTP_HOST.key, 'localhost'),
|
|
31
|
+
port: 465,
|
|
32
|
+
secure: true,
|
|
33
|
+
auth: {
|
|
34
|
+
user: configService.tryGet(env_1.MAIL_SMTP_USER.key, ''),
|
|
35
|
+
pass: configService.tryGet(env_1.MAIL_SMTP_PASSWORD.key, ''),
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// #endregion
|
|
40
|
+
// #region Methods
|
|
41
|
+
/**
|
|
42
|
+
* Verifies that the configured SMTP server is reachable.
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
* @returns `true` if the SMTP server is reachable, `false` otherwise.
|
|
46
|
+
*/
|
|
47
|
+
async verifyConnection() {
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
this._transporter.verify((error, success) => {
|
|
50
|
+
if (error) {
|
|
51
|
+
this._logger.error('SMTP verification error:', error);
|
|
52
|
+
resolve(false);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
resolve(!!success);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Send an email for testing purposes.
|
|
61
|
+
*
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
64
|
+
async sendTestEmail(from, to, subject, text) {
|
|
65
|
+
await this._transporter.sendMail({
|
|
66
|
+
from,
|
|
67
|
+
to,
|
|
68
|
+
subject,
|
|
69
|
+
text,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
exports.SmtpConnectionVerifier = SmtpConnectionVerifier;
|
|
74
|
+
exports.SmtpConnectionVerifier = SmtpConnectionVerifier = SmtpConnectionVerifier_1 = tslib_1.__decorate([
|
|
75
|
+
(0, common_1.Injectable)(),
|
|
76
|
+
tslib_1.__metadata("design:paramtypes", [archipel_platform_configuration_1.ConfigService])
|
|
77
|
+
], SmtpConnectionVerifier);
|
|
78
|
+
//# sourceMappingURL=SmtpConnectionVerifier.js.map
|
|
@@ -1,7 +1,38 @@
|
|
|
1
|
+
import type { IConfigRegistryEntry } from '@breadstone/archipel-platform-configuration';
|
|
2
|
+
import { type DynamicModule } from '@nestjs/common';
|
|
3
|
+
/**
|
|
4
|
+
* Options for configuring the {@link MailModule}.
|
|
5
|
+
*
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export interface IMailModuleOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Whether to register the module globally.
|
|
11
|
+
* Defaults to `true`.
|
|
12
|
+
*/
|
|
13
|
+
readonly isGlobal?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Additional or overriding configuration entries.
|
|
16
|
+
* Merged with the platform default entries.
|
|
17
|
+
*/
|
|
18
|
+
readonly configEntries?: ReadonlyArray<Omit<IConfigRegistryEntry, 'module'>>;
|
|
19
|
+
}
|
|
1
20
|
/**
|
|
2
21
|
* Represents the mail module.
|
|
3
22
|
*
|
|
23
|
+
* Delivery and template strategies are resolved at runtime based on
|
|
24
|
+
* configuration keys `MAIL_DELIVERY_STRATEGY` and `MAIL_TEMPLATE_STRATEGY`.
|
|
25
|
+
*
|
|
4
26
|
* @public
|
|
5
27
|
*/
|
|
6
28
|
export declare class MailModule {
|
|
29
|
+
/**
|
|
30
|
+
* Registers the mail module with optional configuration.
|
|
31
|
+
*
|
|
32
|
+
* @param options - Module registration options.
|
|
33
|
+
* @returns A configured `DynamicModule`.
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
static register(options?: IMailModuleOptions): DynamicModule;
|
|
7
38
|
}
|
package/src/tokens/MailModule.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// #region Imports
|
|
3
|
+
var MailModule_1;
|
|
3
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
5
|
exports.MailModule = void 0;
|
|
5
6
|
const tslib_1 = require("tslib");
|
|
6
7
|
const archipel_platform_blob_storage_1 = require("@breadstone/archipel-platform-blob-storage");
|
|
7
8
|
const archipel_platform_configuration_1 = require("@breadstone/archipel-platform-configuration");
|
|
8
9
|
const archipel_platform_core_1 = require("@breadstone/archipel-platform-core");
|
|
9
|
-
const archipel_platform_health_1 = require("@breadstone/archipel-platform-health");
|
|
10
10
|
const archipel_platform_resources_1 = require("@breadstone/archipel-platform-resources");
|
|
11
11
|
const common_1 = require("@nestjs/common");
|
|
12
12
|
const env_1 = require("../env");
|
|
@@ -14,91 +14,94 @@ const MailEventSubscriber_1 = require("../events/listeners/MailEventSubscriber")
|
|
|
14
14
|
const MailTokens_1 = require("../MailTokens");
|
|
15
15
|
const MailService_1 = require("../services/MailService");
|
|
16
16
|
const MailVerificationService_1 = require("../services/MailVerificationService");
|
|
17
|
+
const SmtpConnectionVerifier_1 = require("../services/SmtpConnectionVerifier");
|
|
17
18
|
const MailTemplateEngine_1 = require("../templating/MailTemplateEngine");
|
|
18
|
-
const MailHealthIndicator_1 = require("../terminus/MailHealthIndicator");
|
|
19
|
-
// #endregion
|
|
20
19
|
/**
|
|
21
20
|
* Represents the mail module.
|
|
22
21
|
*
|
|
22
|
+
* Delivery and template strategies are resolved at runtime based on
|
|
23
|
+
* configuration keys `MAIL_DELIVERY_STRATEGY` and `MAIL_TEMPLATE_STRATEGY`.
|
|
24
|
+
*
|
|
23
25
|
* @public
|
|
24
26
|
*/
|
|
25
|
-
let MailModule = class MailModule {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
27
|
+
let MailModule = MailModule_1 = class MailModule {
|
|
28
|
+
/**
|
|
29
|
+
* Registers the mail module with optional configuration.
|
|
30
|
+
*
|
|
31
|
+
* @param options - Module registration options.
|
|
32
|
+
* @returns A configured `DynamicModule`.
|
|
33
|
+
*
|
|
34
|
+
* @public
|
|
35
|
+
*/
|
|
36
|
+
static register(options) {
|
|
37
|
+
const isGlobal = options?.isGlobal ?? true;
|
|
38
|
+
const configEntries = options?.configEntries ?? env_1.PLATFORM_MAILING_CONFIG_ENTRIES;
|
|
39
|
+
return {
|
|
40
|
+
module: MailModule_1,
|
|
41
|
+
global: isGlobal,
|
|
42
|
+
imports: [archipel_platform_configuration_1.ConfigModule.register('platform-mailing', configEntries), archipel_platform_blob_storage_1.BlobModule, archipel_platform_core_1.EventModule],
|
|
43
|
+
providers: [
|
|
44
|
+
{
|
|
45
|
+
provide: MailTokens_1.MAIL_TEMPLATE_FETCH_STRATEGY_TOKEN,
|
|
46
|
+
useFactory: async (configService, blobService, resourceManager) => {
|
|
47
|
+
const templateStrategy = configService.get(env_1.MAIL_TEMPLATE_STRATEGY.key);
|
|
48
|
+
if (templateStrategy === 'file') {
|
|
49
|
+
const { FileTemplateFetchStrategy } = await Promise.resolve().then(() => tslib_1.__importStar(require('../templating/strategies/FileTemplateFetchStrategy')));
|
|
50
|
+
return new FileTemplateFetchStrategy(resourceManager);
|
|
51
|
+
}
|
|
52
|
+
if (templateStrategy === 'blob') {
|
|
53
|
+
const { BlobTemplateFetchStrategy } = await Promise.resolve().then(() => tslib_1.__importStar(require('../templating/strategies/BlobTemplateFetchStrategy')));
|
|
54
|
+
return new BlobTemplateFetchStrategy(blobService);
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`Unknown template strategy: ${templateStrategy}`);
|
|
57
|
+
},
|
|
58
|
+
inject: [archipel_platform_configuration_1.ConfigService, archipel_platform_blob_storage_1.BlobService, archipel_platform_resources_1.ResourceManager],
|
|
51
59
|
},
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
60
|
+
{
|
|
61
|
+
provide: MailTokens_1.MAIL_DELIVERY_STRATEGY_TOKEN,
|
|
62
|
+
useFactory: async (configService) => {
|
|
63
|
+
const deliveryStrategy = configService.get(env_1.MAIL_DELIVERY_STRATEGY.key);
|
|
64
|
+
if (deliveryStrategy === 'log') {
|
|
65
|
+
const { LogDeliveryStrategy } = await Promise.resolve().then(() => tslib_1.__importStar(require('../services/strategies/LogDeliveryStrategy')));
|
|
66
|
+
return new LogDeliveryStrategy();
|
|
67
|
+
}
|
|
68
|
+
if (deliveryStrategy === 'smtp') {
|
|
69
|
+
const { SmtpDeliveryStrategy } = await Promise.resolve().then(() => tslib_1.__importStar(require('../services/strategies/SmtpDeliveryStrategy')));
|
|
70
|
+
return new SmtpDeliveryStrategy(configService);
|
|
71
|
+
}
|
|
72
|
+
if (deliveryStrategy === 'postmark') {
|
|
73
|
+
const { PostmarkDeliveryStrategy } = await Promise.resolve().then(() => tslib_1.__importStar(require('../services/strategies/PostmarkDeliveryStrategy')));
|
|
74
|
+
return new PostmarkDeliveryStrategy(configService);
|
|
75
|
+
}
|
|
76
|
+
if (deliveryStrategy === 'resend') {
|
|
77
|
+
const { ResendDeliveryStrategy } = await Promise.resolve().then(() => tslib_1.__importStar(require('../services/strategies/ResendDeliveryStrategy')));
|
|
78
|
+
return new ResendDeliveryStrategy(configService);
|
|
79
|
+
}
|
|
80
|
+
if (deliveryStrategy === 'sendgrid') {
|
|
81
|
+
const { SendGridDeliveryStrategy } = await Promise.resolve().then(() => tslib_1.__importStar(require('../services/strategies/SendGridDeliveryStrategy')));
|
|
82
|
+
return new SendGridDeliveryStrategy(configService);
|
|
83
|
+
}
|
|
84
|
+
if (deliveryStrategy === 'mailgun') {
|
|
85
|
+
const { MailgunDeliveryStrategy } = await Promise.resolve().then(() => tslib_1.__importStar(require('../services/strategies/MailgunDeliveryStrategy')));
|
|
86
|
+
return new MailgunDeliveryStrategy(configService);
|
|
87
|
+
}
|
|
88
|
+
throw new Error(`Unknown delivery strategy: ${deliveryStrategy}`);
|
|
89
|
+
},
|
|
90
|
+
inject: [archipel_platform_configuration_1.ConfigService],
|
|
83
91
|
},
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
inject: [archipel_platform_health_1.HealthOrchestrator, MailHealthIndicator_1.MailHealthIndicator],
|
|
99
|
-
},
|
|
100
|
-
],
|
|
101
|
-
exports: [MailService_1.MailService, MailVerificationService_1.MailVerificationService, MailHealthIndicator_1.MailHealthIndicator],
|
|
102
|
-
})
|
|
92
|
+
archipel_platform_core_1.ContentTemplateEngine,
|
|
93
|
+
MailService_1.MailService,
|
|
94
|
+
MailTemplateEngine_1.MailTemplateEngine,
|
|
95
|
+
MailVerificationService_1.MailVerificationService,
|
|
96
|
+
SmtpConnectionVerifier_1.SmtpConnectionVerifier,
|
|
97
|
+
MailEventSubscriber_1.MailEventSubscriber,
|
|
98
|
+
],
|
|
99
|
+
exports: [MailService_1.MailService, MailVerificationService_1.MailVerificationService, SmtpConnectionVerifier_1.SmtpConnectionVerifier],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
exports.MailModule = MailModule;
|
|
104
|
+
exports.MailModule = MailModule = MailModule_1 = tslib_1.__decorate([
|
|
105
|
+
(0, common_1.Module)({})
|
|
103
106
|
], MailModule);
|
|
104
107
|
//# sourceMappingURL=MailModule.js.map
|