@venizia/ignis-docs 0.2.0 → 0.2.1-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 +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +22 -11
- package/content/best-practices/architecture-decisions.md +29 -16
- package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
- package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
- package/content/best-practices/code-style-standards/control-flow.md +33 -1
- package/content/best-practices/code-style-standards/documentation.md +28 -8
- package/content/best-practices/code-style-standards/function-patterns.md +15 -4
- package/content/best-practices/code-style-standards/index.md +7 -2
- package/content/best-practices/code-style-standards/naming-conventions.md +26 -2
- package/content/best-practices/code-style-standards/route-definitions.md +9 -5
- package/content/best-practices/code-style-standards/tooling.md +14 -1
- package/content/best-practices/code-style-standards/type-safety.md +39 -6
- package/content/best-practices/common-pitfalls.md +59 -35
- package/content/best-practices/contribution-workflow.md +6 -2
- package/content/best-practices/data-modeling.md +78 -62
- package/content/best-practices/deployment-strategies.md +56 -19
- package/content/best-practices/error-handling.md +182 -93
- package/content/best-practices/index.md +6 -0
- package/content/best-practices/performance-optimization.md +26 -13
- package/content/best-practices/security-guidelines.md +35 -9
- package/content/best-practices/testing-strategies.md +7 -2
- package/content/best-practices/troubleshooting-tips.md +27 -17
- package/content/extensions/components/api-reference.md +107 -322
- package/content/extensions/components/authentication/api.md +454 -603
- package/content/extensions/components/authentication/errors.md +121 -498
- package/content/extensions/components/authentication/index.md +88 -801
- package/content/extensions/components/authentication/usage.md +207 -956
- package/content/extensions/components/authorization/api.md +736 -656
- package/content/extensions/components/authorization/errors.md +168 -206
- package/content/extensions/components/authorization/index.md +82 -797
- package/content/extensions/components/authorization/usage.md +194 -527
- package/content/extensions/components/health-check.md +71 -243
- package/content/extensions/components/mail/api.md +504 -287
- package/content/extensions/components/mail/errors.md +73 -61
- package/content/extensions/components/mail/index.md +96 -467
- package/content/extensions/components/mail/usage.md +130 -172
- package/content/extensions/components/request-tracker.md +66 -173
- package/content/extensions/components/socket-io/api.md +195 -13
- package/content/extensions/components/socket-io/errors.md +3 -3
- package/content/extensions/components/socket-io/index.md +50 -337
- package/content/extensions/components/socket-io/usage.md +143 -26
- package/content/extensions/components/static-asset/api.md +410 -142
- package/content/extensions/components/static-asset/errors.md +110 -53
- package/content/extensions/components/static-asset/index.md +79 -608
- package/content/extensions/components/static-asset/usage.md +180 -300
- package/content/extensions/components/websocket/api.md +275 -399
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +74 -407
- package/content/extensions/components/websocket/usage.md +110 -341
- package/content/extensions/helpers/cron/index.md +51 -160
- package/content/extensions/helpers/crypto/index.md +62 -483
- package/content/extensions/helpers/crypto/reference.md +456 -0
- package/content/extensions/helpers/env/index.md +60 -178
- package/content/extensions/helpers/error/index.md +221 -207
- package/content/extensions/helpers/inversion/index.md +65 -556
- package/content/extensions/helpers/inversion/reference.md +522 -0
- package/content/extensions/helpers/kafka/admin.md +20 -1
- package/content/extensions/helpers/kafka/compile-binary.md +41 -35
- package/content/extensions/helpers/kafka/consumer.md +54 -20
- package/content/extensions/helpers/kafka/examples.md +21 -16
- package/content/extensions/helpers/kafka/index.md +80 -610
- package/content/extensions/helpers/kafka/producer.md +134 -5
- package/content/extensions/helpers/kafka/schema-registry.md +45 -70
- package/content/extensions/helpers/logger/hf-logger.md +193 -0
- package/content/extensions/helpers/logger/index.md +64 -563
- package/content/extensions/helpers/logger/pino.md +85 -0
- package/content/extensions/helpers/logger/reference.md +746 -0
- package/content/extensions/helpers/network/api.md +241 -195
- package/content/extensions/helpers/network/index.md +72 -530
- package/content/extensions/helpers/queue/index.md +72 -900
- package/content/extensions/helpers/queue/reference.md +467 -0
- package/content/extensions/helpers/redis/index.md +73 -645
- package/content/extensions/helpers/redis/reference.md +727 -0
- package/content/extensions/helpers/secrets/index.md +66 -0
- package/content/extensions/helpers/socket-io/api.md +305 -203
- package/content/extensions/helpers/socket-io/index.md +66 -432
- package/content/extensions/helpers/storage/api.md +564 -462
- package/content/extensions/helpers/storage/index.md +77 -573
- package/content/extensions/helpers/types/index.md +66 -499
- package/content/extensions/helpers/types/reference.md +650 -0
- package/content/extensions/helpers/uid/index.md +58 -227
- package/content/extensions/helpers/websocket/api.md +329 -216
- package/content/extensions/helpers/websocket/index.md +65 -503
- package/content/extensions/helpers/worker-thread/index.md +58 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- package/content/guides/core-concepts/persistent/models.md +1 -1
- package/content/guides/core-concepts/persistent/search-typesense.md +3 -3
- package/content/guides/core-concepts/persistent/transactions.md +1 -1
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- package/content/guides/migrations/redis-helpers-migration.md +1 -1
- package/content/guides/migrations/unified-connectors-migration.md +2 -2
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/references/base/application.md +1 -1
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/datasources-reference.md +599 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +17 -39
- package/content/references/base/filter-system/application-usage.md +69 -121
- package/content/references/base/filter-system/array-operators.md +12 -0
- package/content/references/base/filter-system/comparison-operators.md +12 -0
- package/content/references/base/filter-system/default-filter.md +136 -348
- package/content/references/base/filter-system/fields-order-pagination.md +38 -16
- package/content/references/base/filter-system/index.md +106 -257
- package/content/references/base/filter-system/json-filtering.md +12 -2
- package/content/references/base/filter-system/list-operators.md +16 -2
- package/content/references/base/filter-system/logical-operators.md +13 -0
- package/content/references/base/filter-system/null-operators.md +13 -0
- package/content/references/base/filter-system/pattern-matching.md +12 -0
- package/content/references/base/filter-system/quick-reference.md +11 -2
- package/content/references/base/filter-system/range-operators.md +12 -0
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +156 -233
- package/content/references/base/middlewares.md +35 -21
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +80 -1452
- package/content/references/base/repositories/advanced.md +156 -192
- package/content/references/base/repositories/index.md +77 -650
- package/content/references/base/repositories/mixins.md +22 -18
- package/content/references/base/repositories/relations.md +123 -171
- package/content/references/base/repositories/soft-deletable.md +58 -56
- package/content/references/base/secrets.md +263 -0
- package/content/references/base/services.md +2 -2
- package/content/references/configuration/environment-variables.md +48 -4
- package/content/references/configuration/index.md +49 -31
- package/content/references/quick-reference.md +3 -16
- package/content/references/utilities/crypto.md +35 -76
- package/content/references/utilities/date.md +33 -73
- package/content/references/utilities/index.md +1 -1
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +29 -62
- package/content/references/utilities/parse.md +34 -64
- package/content/references/utilities/performance.md +33 -58
- package/content/references/utilities/promise.md +28 -62
- package/content/references/utilities/request.md +57 -218
- package/content/references/utilities/schema.md +43 -137
- package/content/references/utilities/statuses-reference.md +361 -0
- package/content/references/utilities/statuses.md +63 -667
- package/package.json +8 -8
|
@@ -1,534 +1,163 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|------|-------|
|
|
9
|
-
| **Package** | `@venizia/ignis` |
|
|
10
|
-
| **Class** | `MailComponent` |
|
|
11
|
-
| **Runtimes** | Both |
|
|
12
|
-
|
|
13
|
-
### Key Components
|
|
14
|
-
|
|
15
|
-
| Component | Purpose |
|
|
16
|
-
| --------- | ------- |
|
|
17
|
-
| **MailComponent** | Main component registering mail services, transporters, and executors |
|
|
18
|
-
| **MailService** | Core service for sending emails, batch emails, and template-based emails |
|
|
19
|
-
| **TemplateEngineService** | Simple template engine with <code v-pre>{{variable}}</code> syntax |
|
|
20
|
-
| **NodemailerTransportHelper** | Nodemailer-based email transport implementation |
|
|
21
|
-
| **MailgunTransportHelper** | Mailgun API-based email transport implementation |
|
|
22
|
-
| **DirectMailExecutorHelper** | Execute email sending immediately without queue |
|
|
23
|
-
| **InternalQueueMailExecutorHelper** | Queue emails using in-memory queue |
|
|
24
|
-
| **BullMQMailExecutorHelper** | Queue emails using BullMQ for distributed processing |
|
|
25
|
-
| **MailTransportProvider** | Factory provider that creates transport instances based on configuration |
|
|
26
|
-
| **MailQueueExecutorProvider** | Factory provider that creates queue executor instances based on configuration |
|
|
27
|
-
| **NumericCodeGenerator** | Generates cryptographically random numeric verification codes |
|
|
28
|
-
| **RandomTokenGenerator** | Generates cryptographically random base64url tokens |
|
|
29
|
-
| **DefaultVerificationDataGenerator** | Composes code + token generators into full verification data objects |
|
|
30
|
-
|
|
31
|
-
### Transport Providers
|
|
32
|
-
|
|
33
|
-
| Provider | Value | When to Use |
|
|
34
|
-
| -------- | ----- | ----------- |
|
|
35
|
-
| **Nodemailer** | `MailProviders.NODEMAILER` | SMTP-based email sending (Gmail, SendGrid, etc.) |
|
|
36
|
-
| **Mailgun** | `MailProviders.MAILGUN` | Mailgun API for transactional emails |
|
|
37
|
-
| **Custom** | `MailProviders.CUSTOM` | Custom transport implementation |
|
|
38
|
-
|
|
39
|
-
### Queue Executor Types
|
|
40
|
-
|
|
41
|
-
| Type | Value | When to Use |
|
|
42
|
-
| ---- | ----- | ----------- |
|
|
43
|
-
| **Direct** | `'direct'` | No queue, send immediately |
|
|
44
|
-
| **Internal Queue** | `'internal-queue'` | In-memory queue for simple use cases |
|
|
45
|
-
| **BullMQ** | `'bullmq'` | Redis-backed queue for distributed systems |
|
|
46
|
-
|
|
47
|
-
#### Import Paths
|
|
48
|
-
```typescript
|
|
49
|
-
import {
|
|
50
|
-
MailComponent,
|
|
51
|
-
MailKeys,
|
|
52
|
-
MailProviders,
|
|
53
|
-
MailErrorCodes,
|
|
54
|
-
MailDefaults,
|
|
55
|
-
MailQueueExecutorTypes,
|
|
56
|
-
BullMQExecutorModes,
|
|
57
|
-
MailService,
|
|
58
|
-
TemplateEngineService,
|
|
59
|
-
NumericCodeGenerator,
|
|
60
|
-
RandomTokenGenerator,
|
|
61
|
-
DefaultVerificationDataGenerator,
|
|
62
|
-
MailTransportProvider,
|
|
63
|
-
MailQueueExecutorProvider,
|
|
64
|
-
} from '@venizia/ignis/mail';
|
|
65
|
-
|
|
66
|
-
import type {
|
|
67
|
-
TMailOptions,
|
|
68
|
-
IBaseMailOptions,
|
|
69
|
-
INodemailerMailOptions,
|
|
70
|
-
IMailgunMailOptions,
|
|
71
|
-
ICustomMailOptions,
|
|
72
|
-
IGenericMailOptions,
|
|
73
|
-
IMailService,
|
|
74
|
-
IMailTemplateEngine,
|
|
75
|
-
IMailMessage,
|
|
76
|
-
IMailSendResult,
|
|
77
|
-
IMailTransport,
|
|
78
|
-
IMailAttachment,
|
|
79
|
-
IMailQueueExecutor,
|
|
80
|
-
IMailQueueExecutorConfig,
|
|
81
|
-
IMailQueueOptions,
|
|
82
|
-
IMailQueueResult,
|
|
83
|
-
IMailProcessorResult,
|
|
84
|
-
ITemplate,
|
|
85
|
-
IVerificationCodeGenerator,
|
|
86
|
-
IVerificationTokenGenerator,
|
|
87
|
-
IVerificationDataGenerator,
|
|
88
|
-
IVerificationData,
|
|
89
|
-
IVerificationGenerationOptions,
|
|
90
|
-
TMailProvider,
|
|
91
|
-
TNodemailerConfig,
|
|
92
|
-
TMailgunConfig,
|
|
93
|
-
} from '@venizia/ignis/mail';
|
|
94
|
-
```
|
|
1
|
+
---
|
|
2
|
+
title: Mail Component
|
|
3
|
+
description: Send email through pluggable transports (Nodemailer, Mailgun, custom) with templates, batch sending, and a pluggable queue executor
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Mail Component
|
|
95
8
|
|
|
96
|
-
|
|
9
|
+
`MailComponent` wires a pluggable email transport (Nodemailer, Mailgun, or your own) into `MailService`, adding template rendering, batch sending, and an independent queue executor for verification-code/token flows.
|
|
97
10
|
|
|
98
|
-
|
|
11
|
+
## In one example
|
|
99
12
|
|
|
100
|
-
|
|
13
|
+
Bind `MailKeys.MAIL_OPTIONS`, register `MailComponent`, then inject `IMailService` anywhere to send:
|
|
101
14
|
|
|
102
15
|
```typescript
|
|
103
|
-
|
|
104
|
-
import {
|
|
105
|
-
BaseApplication,
|
|
106
|
-
BaseComponent,
|
|
107
|
-
Binding,
|
|
108
|
-
CoreBindings,
|
|
109
|
-
inject,
|
|
110
|
-
} from '@venizia/ignis';
|
|
111
|
-
import { applicationEnvironment, toBoolean } from '@venizia/ignis-helpers';
|
|
16
|
+
import { BaseApplication, ValueOrPromise } from '@venizia/ignis';
|
|
112
17
|
import { MailComponent, MailKeys, MailProviders } from '@venizia/ignis/mail';
|
|
113
18
|
|
|
114
|
-
export class
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
key: MailKeys.MAIL_OPTIONS,
|
|
126
|
-
}).toValue({
|
|
127
|
-
provider: MailProviders.NODEMAILER,
|
|
128
|
-
from: 'noreply@example.com',
|
|
129
|
-
fromName: 'Example App',
|
|
130
|
-
config: {
|
|
131
|
-
host: applicationEnvironment.get<string>('APP_ENV_MAIL_HOST') ?? 'smtp.gmail.com',
|
|
132
|
-
port: +(applicationEnvironment.get<number>('APP_ENV_MAIL_PORT') ?? 465),
|
|
133
|
-
secure: toBoolean(applicationEnvironment.get<boolean>('APP_ENV_MAIL_SECURE') ?? true),
|
|
134
|
-
auth: {
|
|
135
|
-
type: 'oauth2',
|
|
136
|
-
user: applicationEnvironment.get<string>('APP_ENV_MAIL_USER'),
|
|
137
|
-
clientId: applicationEnvironment.get<string>('APP_ENV_MAIL_CLIENT_ID'),
|
|
138
|
-
clientSecret: applicationEnvironment.get<string>('APP_ENV_MAIL_CLIENT_SECRET'),
|
|
139
|
-
refreshToken: applicationEnvironment.get<string>('APP_ENV_MAIL_REFRESH_TOKEN'),
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
}),
|
|
143
|
-
// Configure queue executor
|
|
144
|
-
[MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG]: Binding.bind({
|
|
145
|
-
key: MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG,
|
|
146
|
-
}).toValue({
|
|
147
|
-
type: 'internal-queue',
|
|
148
|
-
internalQueue: {
|
|
149
|
-
identifier: 'mail-internal-queue',
|
|
150
|
-
},
|
|
151
|
-
}),
|
|
19
|
+
export class Application extends BaseApplication {
|
|
20
|
+
preConfigure(): ValueOrPromise<void> {
|
|
21
|
+
// MAIL_OPTIONS is the only binding MailComponent requires
|
|
22
|
+
this.bind({ key: MailKeys.MAIL_OPTIONS }).toValue({
|
|
23
|
+
provider: MailProviders.NODEMAILER,
|
|
24
|
+
from: 'noreply@example.com',
|
|
25
|
+
config: {
|
|
26
|
+
host: 'smtp.gmail.com',
|
|
27
|
+
port: 465,
|
|
28
|
+
secure: true,
|
|
29
|
+
auth: { user: process.env.APP_ENV_MAIL_USER, pass: process.env.APP_ENV_MAIL_PASS },
|
|
152
30
|
},
|
|
153
31
|
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
override async binding(): Promise<void> {
|
|
157
|
-
this.logger.info('[binding] Binding mail component...');
|
|
158
32
|
|
|
159
|
-
|
|
160
|
-
this.application.component(MailComponent);
|
|
161
|
-
|
|
162
|
-
this.logger.info('[binding] Mail component initialized successfully');
|
|
33
|
+
this.component(MailComponent);
|
|
163
34
|
}
|
|
164
35
|
}
|
|
165
36
|
```
|
|
166
37
|
|
|
167
|
-
### Step 2: Register Component
|
|
168
|
-
|
|
169
38
|
```typescript
|
|
170
|
-
|
|
171
|
-
import {
|
|
172
|
-
import { NodemailerComponent } from './components/mail/component';
|
|
39
|
+
import { BaseService, inject } from '@venizia/ignis';
|
|
40
|
+
import { MailKeys, type IMailService } from '@venizia/ignis/mail';
|
|
173
41
|
|
|
174
|
-
export class
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
42
|
+
export class UserService extends BaseService {
|
|
43
|
+
constructor(@inject({ key: MailKeys.MAIL_SERVICE }) private mailService: IMailService) {
|
|
44
|
+
super({ scope: UserService.name });
|
|
45
|
+
}
|
|
178
46
|
|
|
179
|
-
|
|
47
|
+
async sendWelcomeEmail(email: string) {
|
|
48
|
+
return this.mailService.send({ to: email, subject: 'Welcome!', html: '<h1>Welcome!</h1>' });
|
|
180
49
|
}
|
|
181
50
|
}
|
|
182
51
|
```
|
|
183
52
|
|
|
184
|
-
|
|
53
|
+
`MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG` is optional -- omit it and `MailComponent` binds a `direct` executor (no queue) by default.
|
|
185
54
|
|
|
186
|
-
|
|
55
|
+
## How it works
|
|
187
56
|
|
|
188
|
-
|
|
57
|
+
- **One required binding.** `MailComponent.binding()` throws `Mail options not configured` if `MailKeys.MAIL_OPTIONS` is not bound before registration. Every other binding -- queue executor config, verification generators -- is optional with a working default.
|
|
58
|
+
- **Transport is a discriminated union.** `TMailOptions.provider` selects `NodemailerTransportHelper`, `MailgunTransportHelper`, or a `custom` object you supply that implements `IMailTransport` (`send()` + `verify()`). `MailTransportProvider` is the factory that switches on it and throws for an unsupported provider string.
|
|
59
|
+
- **`MailService` is the one sending entry point.** `send()`, `sendBatch()`, `sendTemplate()`, and `verify()` all validate first, then call the transport directly and synchronously, then normalize failures into `MailErrorCodes`. A validation error (400) passes through unchanged; only a throwing transport gets wrapped as `SEND_FAILED` (500) -- the built-in Nodemailer and Mailgun transports never throw, they return `{ success: false, error }` instead.
|
|
60
|
+
- **The queue executor is a separate subsystem, not a mail queue.** `IMailQueueExecutor` (`direct` / `internal-queue` / `bullmq`) only exposes `enqueueVerificationEmail()` and `setProcessor()` -- it never touches `MailService`. You must call `setProcessor()` with your own function (typically one that calls `mailService.send()` internally) before `enqueueVerificationEmail()` does anything.
|
|
61
|
+
- **Templates are a simple substitution engine.** `TemplateEngineService` stores templates in an in-memory `Map` and replaces <code v-pre>{{variable}}</code> placeholders (dot-notation for nested values). A missing value is logged and left as the literal placeholder text, not blanked out.
|
|
62
|
+
- **Startup logging never leaks credentials.** `MailComponent` logs only `mailOptions.provider` and `queueExecutorConfig.type` -- never the SMTP password, OAuth2 secret, API key, or Redis password nested inside them.
|
|
189
63
|
|
|
190
|
-
|
|
64
|
+
## Common tasks
|
|
191
65
|
|
|
192
|
-
|
|
193
|
-
{
|
|
194
|
-
provider: MailProviders.NODEMAILER,
|
|
195
|
-
from: 'noreply@example.com',
|
|
196
|
-
fromName: 'Example App',
|
|
197
|
-
config: {
|
|
198
|
-
host: 'smtp.gmail.com',
|
|
199
|
-
port: 465,
|
|
200
|
-
secure: true,
|
|
201
|
-
auth: {
|
|
202
|
-
user: 'your-email@gmail.com',
|
|
203
|
-
pass: 'your-app-password',
|
|
204
|
-
},
|
|
205
|
-
},
|
|
206
|
-
}
|
|
207
|
-
```
|
|
66
|
+
### Send an email
|
|
208
67
|
|
|
209
|
-
|
|
68
|
+
Inject `IMailService` via `MailKeys.MAIL_SERVICE` and call `send()`.
|
|
210
69
|
|
|
211
70
|
```typescript
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
config: {
|
|
218
|
-
host: 'smtp.gmail.com',
|
|
219
|
-
port: 465,
|
|
220
|
-
secure: true,
|
|
221
|
-
auth: {
|
|
222
|
-
user: process.env.APP_ENV_MAIL_USER,
|
|
223
|
-
pass: process.env.APP_ENV_MAIL_PASS,
|
|
224
|
-
},
|
|
225
|
-
},
|
|
71
|
+
const result = await this.mailService.send({
|
|
72
|
+
to: 'user@example.com',
|
|
73
|
+
subject: 'Welcome!',
|
|
74
|
+
html: '<h1>Welcome!</h1>',
|
|
75
|
+
text: 'Welcome!',
|
|
226
76
|
});
|
|
227
77
|
```
|
|
228
78
|
|
|
229
|
-
|
|
79
|
+
### Send a batch of emails
|
|
230
80
|
|
|
231
|
-
|
|
232
|
-
{
|
|
233
|
-
provider: MailProviders.MAILGUN,
|
|
234
|
-
from: 'noreply@example.com',
|
|
235
|
-
fromName: 'Example App',
|
|
236
|
-
config: {
|
|
237
|
-
apiKey: process.env.MAILGUN_API_KEY,
|
|
238
|
-
domain: 'mg.example.com',
|
|
239
|
-
host: 'api.eu.mailgun.net', // Optional: EU region
|
|
240
|
-
},
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
**Generic provider example:**
|
|
245
|
-
|
|
246
|
-
The `IGenericMailOptions` variant allows any arbitrary provider string with a `Record<string, AnyType>` config. This is the catch-all for providers not covered by the named variants:
|
|
81
|
+
`sendBatch()` runs each message through `send()` with bounded concurrency (default `5`).
|
|
247
82
|
|
|
248
83
|
```typescript
|
|
249
|
-
{
|
|
250
|
-
provider: 'sendgrid',
|
|
251
|
-
from: 'noreply@example.com',
|
|
252
|
-
config: {
|
|
253
|
-
apiKey: process.env.SENDGRID_API_KEY,
|
|
254
|
-
// Any key-value pairs accepted
|
|
255
|
-
},
|
|
256
|
-
}
|
|
84
|
+
const results = await this.mailService.sendBatch(messages, { concurrency: 5 });
|
|
257
85
|
```
|
|
258
86
|
|
|
259
|
-
|
|
260
|
-
> The `IGenericMailOptions` variant will fall through to the `default` case in `MailTransportProvider` and throw `Unsupported mail provider: <provider>` unless the transport provider is replaced with a custom one that handles the provider string. This variant exists for extensibility -- you must bind a custom `MailTransportProvider` that knows how to handle your provider string.
|
|
87
|
+
### Send a registered template
|
|
261
88
|
|
|
262
|
-
|
|
89
|
+
Register a template on `IMailTemplateEngine`, then send it through `IMailService`.
|
|
263
90
|
|
|
264
91
|
```typescript
|
|
265
|
-
{
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
host: applicationEnvironment.get<string>('APP_ENV_MAIL_HOST') ?? 'smtp.gmail.com',
|
|
271
|
-
port: +(applicationEnvironment.get<number>('APP_ENV_MAIL_PORT') ?? 465),
|
|
272
|
-
secure: toBoolean(applicationEnvironment.get<boolean>('APP_ENV_MAIL_SECURE') ?? true),
|
|
273
|
-
auth: {
|
|
274
|
-
type: 'oauth2',
|
|
275
|
-
user: applicationEnvironment.get<string>('APP_ENV_MAIL_USER'),
|
|
276
|
-
clientId: applicationEnvironment.get<string>('APP_ENV_MAIL_CLIENT_ID'),
|
|
277
|
-
clientSecret: applicationEnvironment.get<string>('APP_ENV_MAIL_CLIENT_SECRET'),
|
|
278
|
-
refreshToken: applicationEnvironment.get<string>('APP_ENV_MAIL_REFRESH_TOKEN'),
|
|
279
|
-
},
|
|
280
|
-
},
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
**Example `.env` file for Nodemailer with OAuth2:**
|
|
285
|
-
|
|
286
|
-
```
|
|
287
|
-
APP_ENV_MAIL_HOST=smtp.gmail.com
|
|
288
|
-
APP_ENV_MAIL_PORT=465
|
|
289
|
-
APP_ENV_MAIL_SECURE=true
|
|
290
|
-
APP_ENV_MAIL_USER=your-email@gmail.com
|
|
291
|
-
APP_ENV_MAIL_CLIENT_ID=your-oauth2-client-id
|
|
292
|
-
APP_ENV_MAIL_CLIENT_SECRET=your-oauth2-client-secret
|
|
293
|
-
APP_ENV_MAIL_REFRESH_TOKEN=your-oauth2-refresh-token
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
> [!TIP]
|
|
297
|
-
> For Gmail OAuth2, follow [Google's OAuth2 setup guide](https://developers.google.com/gmail/api/auth/web-server) to obtain client ID, secret, and refresh token.
|
|
298
|
-
|
|
299
|
-
### Queue Executor Options
|
|
300
|
-
|
|
301
|
-
The `IMailQueueExecutorConfig` configuration determines how emails are queued and processed.
|
|
302
|
-
|
|
303
|
-
**Direct execution (no queue):**
|
|
92
|
+
this.templateEngine.registerTemplate({
|
|
93
|
+
name: 'welcome-email',
|
|
94
|
+
content: '<h1>Welcome {{userName}}!</h1>',
|
|
95
|
+
options: { subject: 'Welcome to {{appName}}' },
|
|
96
|
+
});
|
|
304
97
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
98
|
+
await this.mailService.sendTemplate({
|
|
99
|
+
templateName: 'welcome-email',
|
|
100
|
+
data: { userName: 'Jane', appName: 'My App' },
|
|
101
|
+
recipients: 'user@example.com',
|
|
102
|
+
});
|
|
309
103
|
```
|
|
310
104
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
```typescript
|
|
314
|
-
{
|
|
315
|
-
type: 'internal-queue',
|
|
316
|
-
internalQueue: {
|
|
317
|
-
identifier: 'mail-internal-queue',
|
|
318
|
-
},
|
|
319
|
-
}
|
|
320
|
-
```
|
|
105
|
+
### Switch to Mailgun
|
|
321
106
|
|
|
322
|
-
|
|
107
|
+
`config` must carry `username`, `key`, and `domain` -- the transport validates them eagerly, on construction.
|
|
323
108
|
|
|
324
109
|
```typescript
|
|
325
110
|
{
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
host: 'localhost',
|
|
330
|
-
port: 6379,
|
|
331
|
-
password: 'your-redis-password',
|
|
332
|
-
},
|
|
333
|
-
queue: {
|
|
334
|
-
identifier: 'mail-queue',
|
|
335
|
-
name: 'mail-queue',
|
|
336
|
-
},
|
|
337
|
-
mode: 'both', // 'queue-only', 'worker-only', or 'both'
|
|
338
|
-
},
|
|
111
|
+
provider: MailProviders.MAILGUN,
|
|
112
|
+
from: 'noreply@example.com',
|
|
113
|
+
config: { username: 'api', key: process.env.MAILGUN_API_KEY, domain: 'mg.example.com' },
|
|
339
114
|
}
|
|
340
115
|
```
|
|
341
116
|
|
|
342
|
-
|
|
343
|
-
> - **`'queue-only'`** -- Only enqueues jobs, does not process them (useful for web servers that offload to workers)
|
|
344
|
-
> - **`'worker-only'`** -- Only processes jobs, does not enqueue (useful for dedicated worker processes)
|
|
345
|
-
> - **`'both'`** -- Both enqueues and processes jobs (simplest setup for single-instance apps)
|
|
346
|
-
|
|
347
|
-
> [!NOTE]
|
|
348
|
-
> Choose the right queue executor for your environment:
|
|
349
|
-
> - **`direct`** -- Development or low-volume applications. No queueing overhead.
|
|
350
|
-
> - **`internal-queue`** -- Single-instance applications with moderate volume. In-memory queue with retry support.
|
|
351
|
-
> - **`bullmq`** -- Distributed systems or high-volume applications. Redis-backed with configurable concurrency, priority, and backoff.
|
|
117
|
+
### Queue verification emails
|
|
352
118
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
The `BullMQMailExecutorHelper` supports dynamic worker scaling at runtime. Workers can be added and removed without restarting the application:
|
|
119
|
+
Get the queue executor instance, register a processor, then enqueue.
|
|
356
120
|
|
|
357
121
|
```typescript
|
|
358
|
-
const executor = this.application.get<
|
|
122
|
+
const executor = this.application.get<IMailQueueExecutor>({
|
|
359
123
|
key: MailKeys.MAIL_QUEUE_EXECUTOR_INSTANCE,
|
|
360
124
|
});
|
|
361
125
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
concurrency: 10,
|
|
366
|
-
lockDuration: 60000, // 60 seconds
|
|
126
|
+
executor.setProcessor(async email => {
|
|
127
|
+
await this.mailService.send({ to: email, subject: 'Verify', html: '...' });
|
|
128
|
+
return { success: true, message: 'Sent', expiresInMinutes: 10 };
|
|
367
129
|
});
|
|
368
130
|
|
|
369
|
-
|
|
370
|
-
const count = executor.getWorkerCount(); // e.g. 2
|
|
371
|
-
|
|
372
|
-
// Check current mode
|
|
373
|
-
const mode = executor.getMode(); // e.g. 'both'
|
|
374
|
-
|
|
375
|
-
// Remove a specific worker by index
|
|
376
|
-
await executor.removeWorker(1);
|
|
377
|
-
|
|
378
|
-
// Remove all workers
|
|
379
|
-
await executor.clearWorkers();
|
|
131
|
+
await executor.enqueueVerificationEmail('user@example.com');
|
|
380
132
|
```
|
|
381
133
|
|
|
382
|
-
|
|
134
|
+
### Generate a verification code and token
|
|
383
135
|
|
|
384
|
-
|
|
385
|
-
await executor.setProcessor(
|
|
386
|
-
async (email: string) => {
|
|
387
|
-
// your processing logic
|
|
388
|
-
return { success: true, message: 'Sent', expiresInMinutes: 10 };
|
|
389
|
-
},
|
|
390
|
-
{
|
|
391
|
-
numberOfWorkers: 3, // Spawn 3 workers (default: 1)
|
|
392
|
-
concurrencyPerWorker: 10, // Each worker handles 10 concurrent jobs (default: 5)
|
|
393
|
-
lockDuration: 60000, // Job lock duration in ms (default: 30000)
|
|
394
|
-
},
|
|
395
|
-
);
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
#### Full Transport Options Interface
|
|
399
|
-
|
|
400
|
-
The `TMailOptions` union type has four variants. All extend `IBaseMailOptions`:
|
|
136
|
+
`MAIL_VERIFICATION_DATA_GENERATOR` composes a numeric code and a base64url token in one call.
|
|
401
137
|
|
|
402
138
|
```typescript
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
provider: 'nodemailer';
|
|
410
|
-
config: TNodemailerConfig; // SMTPTransport | SMTPTransport.Options | string
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
interface IMailgunMailOptions extends IBaseMailOptions {
|
|
414
|
-
provider: 'mailgun';
|
|
415
|
-
config: TMailgunConfig; // { domain: string; [key: string]: any }
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
interface ICustomMailOptions extends IBaseMailOptions {
|
|
419
|
-
provider: 'custom';
|
|
420
|
-
config: IMailTransport; // Must implement send() and verify()
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
interface IGenericMailOptions extends IBaseMailOptions {
|
|
424
|
-
provider: string;
|
|
425
|
-
config: Record<string, AnyType>;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
type TMailOptions =
|
|
429
|
-
| INodemailerMailOptions
|
|
430
|
-
| IMailgunMailOptions
|
|
431
|
-
| ICustomMailOptions
|
|
432
|
-
| IGenericMailOptions;
|
|
139
|
+
const data = this.verificationGenerator.generateVerificationData({
|
|
140
|
+
codeLength: 6,
|
|
141
|
+
tokenBytes: 32,
|
|
142
|
+
codeExpiryMinutes: 10,
|
|
143
|
+
tokenExpiryHours: 24,
|
|
144
|
+
});
|
|
433
145
|
```
|
|
434
146
|
|
|
435
|
-
|
|
436
|
-
```typescript
|
|
437
|
-
interface IMailQueueExecutorConfig {
|
|
438
|
-
type: TConstValue<typeof MailQueueExecutorTypes>; // 'direct' | 'internal-queue' | 'bullmq'
|
|
439
|
-
internalQueue?: {
|
|
440
|
-
identifier: string;
|
|
441
|
-
};
|
|
442
|
-
bullmq?: {
|
|
443
|
-
redis: IRedisHelperOptions;
|
|
444
|
-
queue: {
|
|
445
|
-
identifier: string;
|
|
446
|
-
name: string;
|
|
447
|
-
};
|
|
448
|
-
mode: TConstValue<typeof BullMQExecutorModes>; // REQUIRED: 'queue-only' | 'worker-only' | 'both'
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
```
|
|
147
|
+
## See also
|
|
452
148
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
-
|
|
458
|
-
-
|
|
459
|
-
- TLS/SSL connections
|
|
460
|
-
- Custom SMTP headers
|
|
461
|
-
- Connection pooling
|
|
462
|
-
- Attachment handling (file path, buffer, stream)
|
|
463
|
-
- HTML and plain text content
|
|
464
|
-
- SMTP connection verification via `verify()` method
|
|
465
|
-
- Peer dependency validation via `validateModule()` (requires `nodemailer` to be installed)
|
|
466
|
-
|
|
467
|
-
#### Mailgun Transport Capabilities
|
|
468
|
-
- US and EU regional endpoints
|
|
469
|
-
- API key authentication
|
|
470
|
-
- HTML and plain text emails
|
|
471
|
-
- Inline attachments with CID
|
|
472
|
-
- Custom headers (auto-prefixed with `h:`)
|
|
473
|
-
- Batch sending via Mailgun's API
|
|
474
|
-
- Test mode verification via `verify()` method (uses `o:testmode` flag)
|
|
475
|
-
- Peer dependency validation via `validateModule()` (requires `mailgun.js` to be installed)
|
|
476
|
-
|
|
477
|
-
### Constants
|
|
478
|
-
|
|
479
|
-
| Constant | Value | Description |
|
|
480
|
-
|----------|-------|-------------|
|
|
481
|
-
| `MailDefaults.BATCH_CONCURRENCY` | `5` | Default concurrent sends in batch |
|
|
482
|
-
| `MailQueueExecutorTypes.DIRECT` | `'direct'` | Immediate execution |
|
|
483
|
-
| `MailQueueExecutorTypes.INTERNAL_QUEUE` | `'internal-queue'` | In-memory queue |
|
|
484
|
-
| `MailQueueExecutorTypes.BULLMQ` | `'bullmq'` | Redis-backed queue |
|
|
485
|
-
| `BullMQExecutorModes.QUEUE_ONLY` | `'queue-only'` | Producer only (enqueue) |
|
|
486
|
-
| `BullMQExecutorModes.WORKER_ONLY` | `'worker-only'` | Consumer only (process) |
|
|
487
|
-
| `BullMQExecutorModes.BOTH` | `'both'` | Full duplex (produce + consume) |
|
|
488
|
-
|
|
489
|
-
#### MailErrorCodes
|
|
490
|
-
|
|
491
|
-
| Constant | Value | Description |
|
|
492
|
-
|----------|-------|-------------|
|
|
493
|
-
| `MailErrorCodes.INVALID_CONFIGURATION` | `'MAIL_INVALID_CONFIGURATION'` | Invalid or missing configuration (transport, template engine, subject, body) |
|
|
494
|
-
| `MailErrorCodes.SEND_FAILED` | `'MAIL_SEND_FAILED'` | Single email send failed |
|
|
495
|
-
| `MailErrorCodes.VERIFICATION_FAILED` | `'MAIL_VERIFICATION_FAILED'` | Transport connection verification failed |
|
|
496
|
-
| `MailErrorCodes.INVALID_RECIPIENT` | `'MAIL_INVALID_RECIPIENT'` | Missing or empty recipient address |
|
|
497
|
-
| `MailErrorCodes.BATCH_SEND_FAILED` | `'MAIL_BATCH_SEND_FAILED'` | Batch email operation failed |
|
|
498
|
-
| `MailErrorCodes.TEMPLATE_NOT_FOUND` | `'TEMPLATE_NOT_FOUND'` | Template name not found in registry |
|
|
499
|
-
|
|
500
|
-
#### MailQueueExecutorTypes Validation
|
|
501
|
-
|
|
502
|
-
Both `MailQueueExecutorTypes` and `BullMQExecutorModes` include a `SCHEME_SET` / `MODE_SET` and an `isValid()` static method for runtime validation:
|
|
149
|
+
- [Usage & Examples](./usage) -- sending, templates, queue executors, and verification generators
|
|
150
|
+
- [API Reference](./api) -- architecture, binding keys, interfaces, and internals
|
|
151
|
+
- [Error Reference](./errors) -- error codes and troubleshooting
|
|
152
|
+
- [Components Overview](/guides/core-concepts/components) -- component system basics
|
|
153
|
+
- [Queue Helper](/extensions/helpers/queue/) -- the in-memory/BullMQ primitives the queue executors are built on
|
|
154
|
+
- [Redis Helper](/extensions/helpers/redis/) -- `RedisSingleHelper`, required by the BullMQ queue executor
|
|
503
155
|
|
|
504
|
-
|
|
505
|
-
MailQueueExecutorTypes.isValid('bullmq'); // true
|
|
506
|
-
MailQueueExecutorTypes.isValid('unknown'); // false
|
|
507
|
-
BullMQExecutorModes.isValid('both'); // true
|
|
508
|
-
BullMQExecutorModes.isValid('invalid'); // false
|
|
509
|
-
```
|
|
156
|
+
**Files:**
|
|
510
157
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
| `@app/components/mail/service` | `MailKeys.MAIL_SERVICE` | `IMailService` | No | `MailService` (singleton) |
|
|
518
|
-
| `@app/components/mail/services/template-engine` | `MailKeys.MAIL_TEMPLATE_ENGINE` | `IMailTemplateEngine` | No | `TemplateEngineService` (singleton) |
|
|
519
|
-
| `@app/components/mail/transport-provider` | `MailKeys.MAIL_TRANSPORT_PROVIDER` | `TGetMailTransportFn` | No | `MailTransportProvider` (singleton) |
|
|
520
|
-
| `@app/components/mail/transport-instance` | `MailKeys.MAIL_TRANSPORT_INSTANCE` | `IMailTransport` | No | Created by component |
|
|
521
|
-
| `@app/components/mail/queue-executor-provider` | `MailKeys.MAIL_QUEUE_EXECUTOR_PROVIDER` | `TGetMailQueueExecutorFn` | No | `MailQueueExecutorProvider` (singleton) |
|
|
522
|
-
| `@app/components/mail/queue-executor-instance` | `MailKeys.MAIL_QUEUE_EXECUTOR_INSTANCE` | `IMailQueueExecutor` | No | Created by component |
|
|
523
|
-
| `@app/components/mail/verification/code-generator` | `MailKeys.MAIL_VERIFICATION_CODE_GENERATOR` | `IVerificationCodeGenerator` | No | `NumericCodeGenerator` |
|
|
524
|
-
| `@app/components/mail/verification/token-generator` | `MailKeys.MAIL_VERIFICATION_TOKEN_GENERATOR` | `IVerificationTokenGenerator` | No | `RandomTokenGenerator` |
|
|
525
|
-
| `@app/components/mail/verification/data-generator` | `MailKeys.MAIL_VERIFICATION_DATA_GENERATOR` | `IVerificationDataGenerator` | No | `DefaultVerificationDataGenerator` |
|
|
526
|
-
|
|
527
|
-
> [!IMPORTANT]
|
|
528
|
-
> Both `MailKeys.MAIL_OPTIONS` and `MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG` must be bound before registering `MailComponent`. The component throws an error if `MAIL_OPTIONS` is not found.
|
|
529
|
-
|
|
530
|
-
## See Also
|
|
531
|
-
|
|
532
|
-
- [Usage & Examples](./usage) -- Sending emails, templates, queue executors, and verification
|
|
533
|
-
- [API Reference](./api) -- Architecture, interfaces, and internals
|
|
534
|
-
- [Error Reference](./errors) -- Error codes and troubleshooting
|
|
158
|
+
- [`packages/core/src/components/mail/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/component.ts) -- `MailComponent`
|
|
159
|
+
- [`packages/core/src/components/mail/services/mail.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/mail.service.ts) -- `MailService`
|
|
160
|
+
- [`packages/core/src/components/mail/services/template.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/template.service.ts) -- `TemplateEngineService`
|
|
161
|
+
- [`packages/core/src/components/mail/services/generator.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/generator.service.ts) -- verification generators
|
|
162
|
+
- [`packages/core/src/components/mail/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/keys.ts) -- `MailKeys`
|
|
163
|
+
- [`packages/core/src/components/mail/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/types.ts) -- `TMailOptions`, `IMailMessage`, and every mail interface
|