@flusys/nestjs-email 1.0.0-rc
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 +552 -0
- package/cjs/config/email-config.service.js +81 -0
- package/cjs/config/email.constants.js +22 -0
- package/cjs/config/index.js +19 -0
- package/cjs/controllers/email-config.controller.js +101 -0
- package/cjs/controllers/email-send.controller.js +142 -0
- package/cjs/controllers/email-template.controller.js +128 -0
- package/cjs/controllers/index.js +20 -0
- package/cjs/docs/email-swagger.config.js +176 -0
- package/cjs/docs/index.js +11 -0
- package/cjs/dtos/email-config.dto.js +238 -0
- package/cjs/dtos/email-send.dto.js +444 -0
- package/cjs/dtos/email-template.dto.js +283 -0
- package/cjs/dtos/index.js +20 -0
- package/cjs/entities/email-config-base.entity.js +111 -0
- package/cjs/entities/email-config-with-company.entity.js +63 -0
- package/cjs/entities/email-config.entity.js +25 -0
- package/cjs/entities/email-template-base.entity.js +133 -0
- package/cjs/entities/email-template-with-company.entity.js +65 -0
- package/cjs/entities/email-template.entity.js +30 -0
- package/cjs/entities/index.js +41 -0
- package/cjs/enums/email-provider-type.enum.js +18 -0
- package/cjs/enums/index.js +18 -0
- package/cjs/index.js +28 -0
- package/cjs/interfaces/email-config.interface.js +4 -0
- package/cjs/interfaces/email-module-options.interface.js +4 -0
- package/cjs/interfaces/email-provider.interface.js +4 -0
- package/cjs/interfaces/email-template.interface.js +4 -0
- package/cjs/interfaces/index.js +21 -0
- package/cjs/modules/email.module.js +161 -0
- package/cjs/modules/index.js +18 -0
- package/cjs/providers/email-factory.service.js +144 -0
- package/cjs/providers/email-provider.registry.js +41 -0
- package/cjs/providers/index.js +22 -0
- package/cjs/providers/mailgun-provider.js +107 -0
- package/cjs/providers/sendgrid-provider.js +135 -0
- package/cjs/providers/smtp-provider.js +166 -0
- package/cjs/services/email-datasource.provider.js +187 -0
- package/cjs/services/email-provider-config.service.js +150 -0
- package/cjs/services/email-send.service.js +211 -0
- package/cjs/services/email-template.service.js +158 -0
- package/cjs/services/index.js +21 -0
- package/cjs/utils/email-templates.util.js +129 -0
- package/cjs/utils/index.js +18 -0
- package/config/email-config.service.d.ts +16 -0
- package/config/email.constants.d.ts +2 -0
- package/config/index.d.ts +2 -0
- package/controllers/email-config.controller.d.ts +17 -0
- package/controllers/email-send.controller.d.ts +11 -0
- package/controllers/email-template.controller.d.ts +25 -0
- package/controllers/index.d.ts +3 -0
- package/docs/email-swagger.config.d.ts +3 -0
- package/docs/index.d.ts +1 -0
- package/dtos/email-config.dto.d.ts +30 -0
- package/dtos/email-send.dto.d.ts +46 -0
- package/dtos/email-template.dto.d.ts +39 -0
- package/dtos/index.d.ts +3 -0
- package/entities/email-config-base.entity.d.ts +11 -0
- package/entities/email-config-with-company.entity.d.ts +4 -0
- package/entities/email-config.entity.d.ts +3 -0
- package/entities/email-template-base.entity.d.ts +14 -0
- package/entities/email-template-with-company.entity.d.ts +4 -0
- package/entities/email-template.entity.d.ts +3 -0
- package/entities/index.d.ts +7 -0
- package/enums/email-provider-type.enum.d.ts +5 -0
- package/enums/index.d.ts +1 -0
- package/fesm/config/email-config.service.js +71 -0
- package/fesm/config/email.constants.js +4 -0
- package/fesm/config/index.js +2 -0
- package/fesm/controllers/email-config.controller.js +91 -0
- package/fesm/controllers/email-send.controller.js +132 -0
- package/fesm/controllers/email-template.controller.js +118 -0
- package/fesm/controllers/index.js +3 -0
- package/fesm/docs/email-swagger.config.js +172 -0
- package/fesm/docs/index.js +1 -0
- package/fesm/dtos/email-config.dto.js +217 -0
- package/fesm/dtos/email-send.dto.js +414 -0
- package/fesm/dtos/email-template.dto.js +262 -0
- package/fesm/dtos/index.js +3 -0
- package/fesm/entities/email-config-base.entity.js +101 -0
- package/fesm/entities/email-config-with-company.entity.js +53 -0
- package/fesm/entities/email-config.entity.js +15 -0
- package/fesm/entities/email-template-base.entity.js +123 -0
- package/fesm/entities/email-template-with-company.entity.js +55 -0
- package/fesm/entities/email-template.entity.js +20 -0
- package/fesm/entities/index.js +20 -0
- package/fesm/enums/email-provider-type.enum.js +8 -0
- package/fesm/enums/index.js +1 -0
- package/fesm/index.js +11 -0
- package/fesm/interfaces/email-config.interface.js +1 -0
- package/fesm/interfaces/email-module-options.interface.js +1 -0
- package/fesm/interfaces/email-provider.interface.js +1 -0
- package/fesm/interfaces/email-template.interface.js +1 -0
- package/fesm/interfaces/index.js +4 -0
- package/fesm/modules/email.module.js +151 -0
- package/fesm/modules/index.js +1 -0
- package/fesm/providers/email-factory.service.js +93 -0
- package/fesm/providers/email-provider.registry.js +31 -0
- package/fesm/providers/index.js +5 -0
- package/fesm/providers/mailgun-provider.js +97 -0
- package/fesm/providers/sendgrid-provider.js +125 -0
- package/fesm/providers/smtp-provider.js +115 -0
- package/fesm/services/email-datasource.provider.js +136 -0
- package/fesm/services/email-provider-config.service.js +140 -0
- package/fesm/services/email-send.service.js +201 -0
- package/fesm/services/email-template.service.js +148 -0
- package/fesm/services/index.js +4 -0
- package/fesm/utils/email-templates.util.js +111 -0
- package/fesm/utils/index.js +1 -0
- package/index.d.ts +10 -0
- package/interfaces/email-config.interface.d.ts +34 -0
- package/interfaces/email-module-options.interface.d.ts +25 -0
- package/interfaces/email-provider.interface.d.ts +34 -0
- package/interfaces/email-template.interface.d.ts +64 -0
- package/interfaces/index.d.ts +4 -0
- package/modules/email.module.d.ts +9 -0
- package/modules/index.d.ts +1 -0
- package/package.json +105 -0
- package/providers/email-factory.service.d.ts +14 -0
- package/providers/email-provider.registry.d.ts +10 -0
- package/providers/index.d.ts +5 -0
- package/providers/mailgun-provider.d.ts +11 -0
- package/providers/sendgrid-provider.d.ts +11 -0
- package/providers/smtp-provider.d.ts +11 -0
- package/services/email-datasource.provider.d.ts +25 -0
- package/services/email-provider-config.service.d.ts +32 -0
- package/services/email-send.service.d.ts +20 -0
- package/services/email-template.service.d.ts +31 -0
- package/services/index.d.ts +4 -0
- package/utils/email-templates.util.d.ts +2 -0
- package/utils/index.d.ts +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
# Email Package Guide
|
|
2
|
+
|
|
3
|
+
> **Package:** `@flusys/nestjs-email`
|
|
4
|
+
> **Type:** Email sending with templates, multiple providers, and multi-tenant support
|
|
5
|
+
|
|
6
|
+
## Table of Contents
|
|
7
|
+
|
|
8
|
+
- [Overview](#overview)
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Module Setup](#module-setup)
|
|
11
|
+
- [Email Providers](#email-providers)
|
|
12
|
+
- [Email Configuration](#email-configuration)
|
|
13
|
+
- [Email Templates](#email-templates)
|
|
14
|
+
- [Email Sending](#email-sending)
|
|
15
|
+
- [API Endpoints](#api-endpoints)
|
|
16
|
+
- [Multi-Tenant Support](#multi-tenant-support)
|
|
17
|
+
- [Best Practices](#best-practices)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Overview
|
|
22
|
+
|
|
23
|
+
`@flusys/nestjs-email` provides:
|
|
24
|
+
|
|
25
|
+
- **Multiple Providers** - SMTP, SendGrid, Mailgun with dynamic registration
|
|
26
|
+
- **Email Templates** - Variable interpolation with `{{variableName}}` syntax
|
|
27
|
+
- **HTML/Plain Text** - Support via `isHtml` toggle
|
|
28
|
+
- **Multi-Tenant Support** - Company-scoped configurations and templates
|
|
29
|
+
- **Attachments** - File attachment support
|
|
30
|
+
|
|
31
|
+
### Package Hierarchy
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
@flusys/nestjs-core ← Foundation
|
|
35
|
+
↓
|
|
36
|
+
@flusys/nestjs-shared ← Shared utilities
|
|
37
|
+
↓
|
|
38
|
+
@flusys/nestjs-email ← Email system (THIS PACKAGE)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install @flusys/nestjs-email
|
|
47
|
+
|
|
48
|
+
# Provider-specific packages (install as needed)
|
|
49
|
+
npm install nodemailer # For SMTP
|
|
50
|
+
npm install @sendgrid/mail # For SendGrid
|
|
51
|
+
npm install mailgun.js form-data # For Mailgun
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Module Setup
|
|
57
|
+
|
|
58
|
+
### Basic Setup
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { EmailModule } from '@flusys/nestjs-email';
|
|
62
|
+
|
|
63
|
+
@Module({
|
|
64
|
+
imports: [
|
|
65
|
+
EmailModule.forRoot({
|
|
66
|
+
global: true,
|
|
67
|
+
includeController: true,
|
|
68
|
+
bootstrapAppConfig: {
|
|
69
|
+
databaseMode: 'single',
|
|
70
|
+
enableCompanyFeature: false,
|
|
71
|
+
},
|
|
72
|
+
config: {
|
|
73
|
+
defaultDatabaseConfig: {
|
|
74
|
+
type: 'postgres',
|
|
75
|
+
host: 'localhost',
|
|
76
|
+
port: 5432,
|
|
77
|
+
username: 'user',
|
|
78
|
+
password: 'password',
|
|
79
|
+
database: 'myapp',
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
84
|
+
})
|
|
85
|
+
export class AppModule {}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### With Company Feature
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
EmailModule.forRoot({
|
|
92
|
+
global: true,
|
|
93
|
+
includeController: true,
|
|
94
|
+
bootstrapAppConfig: {
|
|
95
|
+
databaseMode: 'single',
|
|
96
|
+
enableCompanyFeature: true,
|
|
97
|
+
},
|
|
98
|
+
config: {
|
|
99
|
+
defaultDatabaseConfig: { ... },
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Async Configuration
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
EmailModule.forRootAsync({
|
|
108
|
+
global: true,
|
|
109
|
+
includeController: true,
|
|
110
|
+
bootstrapAppConfig: {
|
|
111
|
+
databaseMode: 'single',
|
|
112
|
+
enableCompanyFeature: true,
|
|
113
|
+
},
|
|
114
|
+
imports: [ConfigModule],
|
|
115
|
+
useFactory: async (configService: ConfigService) => ({
|
|
116
|
+
defaultDatabaseConfig: configService.getDatabaseConfig(),
|
|
117
|
+
}),
|
|
118
|
+
inject: [ConfigService],
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Email Providers
|
|
125
|
+
|
|
126
|
+
### Provider Types
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
enum EmailProviderTypeEnum {
|
|
130
|
+
SMTP = 'smtp',
|
|
131
|
+
SENDGRID = 'sendgrid',
|
|
132
|
+
MAILGUN = 'mailgun',
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Providers are auto-registered at module load via `EmailProviderRegistry`.
|
|
137
|
+
|
|
138
|
+
### SMTP Configuration
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
{
|
|
142
|
+
provider: 'smtp',
|
|
143
|
+
config: {
|
|
144
|
+
host: 'smtp.gmail.com',
|
|
145
|
+
port: 587,
|
|
146
|
+
secure: false,
|
|
147
|
+
auth: { user: 'your@gmail.com', pass: 'app-password' },
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### SendGrid Configuration
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// Requires: npm install @sendgrid/mail
|
|
156
|
+
{
|
|
157
|
+
provider: 'sendgrid',
|
|
158
|
+
config: { apiKey: 'SG.xxxxxxxxxxxx' }
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Mailgun Configuration
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// Requires: npm install mailgun.js form-data
|
|
166
|
+
{
|
|
167
|
+
provider: 'mailgun',
|
|
168
|
+
config: {
|
|
169
|
+
apiKey: 'key-xxxxxxxx',
|
|
170
|
+
domain: 'mail.yourdomain.com',
|
|
171
|
+
region: 'us', // 'us' or 'eu'
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Provider Interface
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
interface IEmailProvider {
|
|
180
|
+
sendEmail(options: IEmailSendOptions): Promise<IEmailSendResult>;
|
|
181
|
+
sendBulkEmails(options: IEmailSendOptions[]): Promise<IEmailSendResult[]>;
|
|
182
|
+
healthCheck(): Promise<boolean>;
|
|
183
|
+
initialize?(config: any): Promise<void>;
|
|
184
|
+
close?(): Promise<void>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
interface IEmailSendOptions {
|
|
188
|
+
to: string | string[];
|
|
189
|
+
cc?: string | string[];
|
|
190
|
+
bcc?: string | string[];
|
|
191
|
+
subject: string;
|
|
192
|
+
html?: string;
|
|
193
|
+
text?: string;
|
|
194
|
+
from?: string;
|
|
195
|
+
fromName?: string;
|
|
196
|
+
replyTo?: string;
|
|
197
|
+
attachments?: IEmailAttachment[];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
interface IEmailSendResult {
|
|
201
|
+
success: boolean;
|
|
202
|
+
messageId?: string;
|
|
203
|
+
error?: string;
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Email Configuration
|
|
210
|
+
|
|
211
|
+
### EmailConfig Entity
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
interface IEmailConfig {
|
|
215
|
+
id: string;
|
|
216
|
+
name: string; // e.g., 'default', 'marketing'
|
|
217
|
+
provider: EmailProviderTypeEnum;
|
|
218
|
+
config: Record<string, any>; // Provider-specific config
|
|
219
|
+
fromEmail: string | null;
|
|
220
|
+
fromName: string | null;
|
|
221
|
+
isActive: boolean;
|
|
222
|
+
isDefault: boolean; // Auto-selected when emailConfigId not provided
|
|
223
|
+
companyId?: string | null; // When company feature enabled
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Default Configuration Resolution
|
|
228
|
+
|
|
229
|
+
When `emailConfigId` is not provided:
|
|
230
|
+
1. Find config with `isDefault: true` and `isActive: true`
|
|
231
|
+
2. Fall back to oldest active config
|
|
232
|
+
|
|
233
|
+
### Creating Configurations
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { EmailProviderConfigService } from '@flusys/nestjs-email';
|
|
237
|
+
|
|
238
|
+
await emailConfigService.insert({
|
|
239
|
+
name: 'default',
|
|
240
|
+
provider: 'smtp',
|
|
241
|
+
fromEmail: 'noreply@example.com',
|
|
242
|
+
fromName: 'My App',
|
|
243
|
+
config: {
|
|
244
|
+
host: 'smtp.gmail.com',
|
|
245
|
+
port: 587,
|
|
246
|
+
auth: { user: '...', pass: '...' },
|
|
247
|
+
},
|
|
248
|
+
isActive: true,
|
|
249
|
+
isDefault: true,
|
|
250
|
+
}, user);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Email Templates
|
|
256
|
+
|
|
257
|
+
### EmailTemplate Entity
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
interface IEmailTemplate {
|
|
261
|
+
id: string;
|
|
262
|
+
name: string;
|
|
263
|
+
slug: string; // URL-friendly identifier
|
|
264
|
+
description: string | null;
|
|
265
|
+
subject: string; // Supports {{variables}}
|
|
266
|
+
schema: Record<string, unknown>;
|
|
267
|
+
htmlContent: string;
|
|
268
|
+
textContent: string | null;
|
|
269
|
+
schemaVersion: number; // Auto-incremented on schema change
|
|
270
|
+
isActive: boolean;
|
|
271
|
+
isHtml: boolean; // true=HTML, false=plain text
|
|
272
|
+
metadata: Record<string, unknown> | null;
|
|
273
|
+
companyId?: string | null;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Creating Templates
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
import { EmailTemplateService } from '@flusys/nestjs-email';
|
|
281
|
+
|
|
282
|
+
await templateService.insert({
|
|
283
|
+
name: 'Welcome Email',
|
|
284
|
+
slug: 'welcome-email',
|
|
285
|
+
subject: 'Welcome to {{appName}}, {{userName}}!',
|
|
286
|
+
isHtml: true,
|
|
287
|
+
htmlContent: `
|
|
288
|
+
<h1>Welcome, {{userName}}!</h1>
|
|
289
|
+
<p>Thank you for joining {{appName}}.</p>
|
|
290
|
+
<a href="{{verificationLink}}">Verify Email</a>
|
|
291
|
+
`,
|
|
292
|
+
textContent: 'Welcome! Verify: {{verificationLink}}',
|
|
293
|
+
schema: {},
|
|
294
|
+
isActive: true,
|
|
295
|
+
}, user);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Variable Interpolation
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
// Template: "Hello {{userName}}, your order #{{orderId}} is {{status}}."
|
|
302
|
+
// Variables: { userName: "John", orderId: "12345", status: "shipped" }
|
|
303
|
+
// Result: "Hello John, your order #12345 is shipped."
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### isHtml Toggle
|
|
307
|
+
|
|
308
|
+
- **`isHtml: true`** - Sends `htmlContent` as HTML, `textContent` as fallback
|
|
309
|
+
- **`isHtml: false`** - Sends `textContent` only (no HTML)
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Email Sending
|
|
314
|
+
|
|
315
|
+
### EmailSendService
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { EmailSendService } from '@flusys/nestjs-email';
|
|
319
|
+
|
|
320
|
+
// Send direct email
|
|
321
|
+
const result = await emailSendService.sendEmail({
|
|
322
|
+
to: 'user@example.com',
|
|
323
|
+
subject: 'Hello!',
|
|
324
|
+
html: '<h1>Hello World</h1>',
|
|
325
|
+
text: 'Hello World',
|
|
326
|
+
emailConfigId: 'config-uuid', // Optional - uses default
|
|
327
|
+
}, user);
|
|
328
|
+
|
|
329
|
+
// Send using template
|
|
330
|
+
const result = await emailSendService.sendTemplateEmail({
|
|
331
|
+
templateSlug: 'welcome-email',
|
|
332
|
+
to: 'user@example.com',
|
|
333
|
+
variables: {
|
|
334
|
+
userName: 'John',
|
|
335
|
+
appName: 'My App',
|
|
336
|
+
},
|
|
337
|
+
}, user);
|
|
338
|
+
|
|
339
|
+
// Send with attachments
|
|
340
|
+
const result = await emailSendService.sendEmail({
|
|
341
|
+
to: 'user@example.com',
|
|
342
|
+
subject: 'Your Invoice',
|
|
343
|
+
html: '<p>Invoice attached.</p>',
|
|
344
|
+
attachments: [{
|
|
345
|
+
filename: 'invoice.pdf',
|
|
346
|
+
content: base64Content,
|
|
347
|
+
contentType: 'application/pdf',
|
|
348
|
+
}],
|
|
349
|
+
}, user);
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## API Endpoints
|
|
355
|
+
|
|
356
|
+
All endpoints use POST (RPC pattern) and require JWT authentication.
|
|
357
|
+
|
|
358
|
+
### Email Configuration
|
|
359
|
+
|
|
360
|
+
| Endpoint | Description |
|
|
361
|
+
|----------|-------------|
|
|
362
|
+
| `POST /email/email-config/insert` | Create configuration |
|
|
363
|
+
| `POST /email/email-config/get/:id` | Get by ID |
|
|
364
|
+
| `POST /email/email-config/get-all` | Get all (paginated) |
|
|
365
|
+
| `POST /email/email-config/update` | Update |
|
|
366
|
+
| `POST /email/email-config/delete` | Delete |
|
|
367
|
+
|
|
368
|
+
### Email Templates
|
|
369
|
+
|
|
370
|
+
| Endpoint | Description |
|
|
371
|
+
|----------|-------------|
|
|
372
|
+
| `POST /email/email-template/insert` | Create template |
|
|
373
|
+
| `POST /email/email-template/get/:id` | Get by ID |
|
|
374
|
+
| `POST /email/email-template/get-all` | Get all (paginated) |
|
|
375
|
+
| `POST /email/email-template/get-by-slug` | Get by slug |
|
|
376
|
+
| `POST /email/email-template/update` | Update |
|
|
377
|
+
| `POST /email/email-template/delete` | Delete |
|
|
378
|
+
|
|
379
|
+
### Email Sending
|
|
380
|
+
|
|
381
|
+
| Endpoint | Description |
|
|
382
|
+
|----------|-------------|
|
|
383
|
+
| `POST /email/send/direct` | Send direct email |
|
|
384
|
+
| `POST /email/send/template` | Send using template |
|
|
385
|
+
| `POST /email/send/test` | Test configuration |
|
|
386
|
+
|
|
387
|
+
### Example Requests
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
# Send template email
|
|
391
|
+
curl -X POST http://localhost:3000/email/send/template \
|
|
392
|
+
-H "Authorization: Bearer <token>" \
|
|
393
|
+
-H "Content-Type: application/json" \
|
|
394
|
+
-d '{
|
|
395
|
+
"templateSlug": "welcome-email",
|
|
396
|
+
"to": "user@example.com",
|
|
397
|
+
"variables": { "userName": "John" }
|
|
398
|
+
}'
|
|
399
|
+
|
|
400
|
+
# Test configuration
|
|
401
|
+
curl -X POST http://localhost:3000/email/send/test \
|
|
402
|
+
-H "Authorization: Bearer <token>" \
|
|
403
|
+
-d '{ "emailConfigId": "uuid", "recipient": "test@example.com" }'
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Multi-Tenant Support
|
|
409
|
+
|
|
410
|
+
### Company Isolation
|
|
411
|
+
|
|
412
|
+
When `enableCompanyFeature: true`:
|
|
413
|
+
- Email configs are company-scoped
|
|
414
|
+
- Templates are company-scoped
|
|
415
|
+
- Users can only access their company's resources
|
|
416
|
+
|
|
417
|
+
### Company Filtering
|
|
418
|
+
|
|
419
|
+
Services automatically filter by `companyId`:
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
// In EmailTemplateService
|
|
423
|
+
if (this.emailConfig.isCompanyFeatureEnabled() && user?.companyId) {
|
|
424
|
+
query.andWhere('emailTemplate.companyId = :companyId', {
|
|
425
|
+
companyId: user.companyId,
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Dynamic Entity Selection
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
protected resolveEntity(): EntityTarget<EmailTemplateBase> {
|
|
434
|
+
return this.emailConfig.isCompanyFeatureEnabled()
|
|
435
|
+
? EmailTemplateWithCompany
|
|
436
|
+
: EmailTemplate;
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## Best Practices
|
|
443
|
+
|
|
444
|
+
### 1. Use Template Slugs
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
// Use slug for stable references
|
|
448
|
+
await emailSendService.sendTemplateEmail({
|
|
449
|
+
templateSlug: 'welcome-email', // Stable
|
|
450
|
+
...
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// Avoid hardcoded IDs
|
|
454
|
+
templateId: 'f47ac10b-58cc-4372-a567-...' // May change
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### 2. Provide Both HTML and Text
|
|
458
|
+
|
|
459
|
+
```typescript
|
|
460
|
+
await templateService.insert({
|
|
461
|
+
isHtml: true,
|
|
462
|
+
htmlContent: '<h1>Thank you!</h1>',
|
|
463
|
+
textContent: 'Thank you!', // For clients that don't render HTML
|
|
464
|
+
});
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### 3. Test Before Production
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
const result = await emailSendService.sendTestEmail(
|
|
471
|
+
configId,
|
|
472
|
+
'admin@example.com',
|
|
473
|
+
user,
|
|
474
|
+
);
|
|
475
|
+
if (!result.success) throw new Error(result.error);
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### 4. Use Variables for Personalization
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
// Template
|
|
482
|
+
subject: 'Hello {{userName}}!'
|
|
483
|
+
|
|
484
|
+
// Sending
|
|
485
|
+
variables: { userName: 'John' }
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## API Reference
|
|
491
|
+
|
|
492
|
+
### Main Exports
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
// Module
|
|
496
|
+
import { EmailModule } from '@flusys/nestjs-email';
|
|
497
|
+
|
|
498
|
+
// Services
|
|
499
|
+
import {
|
|
500
|
+
EmailProviderConfigService,
|
|
501
|
+
EmailTemplateService,
|
|
502
|
+
EmailSendService,
|
|
503
|
+
EmailDataSourceProvider,
|
|
504
|
+
} from '@flusys/nestjs-email/services';
|
|
505
|
+
|
|
506
|
+
// Entities
|
|
507
|
+
import {
|
|
508
|
+
EmailConfig,
|
|
509
|
+
EmailConfigBase,
|
|
510
|
+
EmailConfigWithCompany,
|
|
511
|
+
EmailTemplate,
|
|
512
|
+
EmailTemplateBase,
|
|
513
|
+
EmailTemplateWithCompany,
|
|
514
|
+
} from '@flusys/nestjs-email/entities';
|
|
515
|
+
|
|
516
|
+
// DTOs
|
|
517
|
+
import {
|
|
518
|
+
CreateEmailConfigDto,
|
|
519
|
+
UpdateEmailConfigDto,
|
|
520
|
+
EmailConfigResponseDto,
|
|
521
|
+
CreateEmailTemplateDto,
|
|
522
|
+
UpdateEmailTemplateDto,
|
|
523
|
+
EmailTemplateResponseDto,
|
|
524
|
+
SendEmailDto,
|
|
525
|
+
SendTemplateEmailDto,
|
|
526
|
+
TestEmailDto,
|
|
527
|
+
EmailSendResultDto,
|
|
528
|
+
} from '@flusys/nestjs-email/dtos';
|
|
529
|
+
|
|
530
|
+
// Interfaces
|
|
531
|
+
import {
|
|
532
|
+
IEmailProvider,
|
|
533
|
+
IEmailSendOptions,
|
|
534
|
+
IEmailSendResult,
|
|
535
|
+
IEmailConfig,
|
|
536
|
+
IEmailTemplate,
|
|
537
|
+
EmailModuleOptions,
|
|
538
|
+
} from '@flusys/nestjs-email/interfaces';
|
|
539
|
+
|
|
540
|
+
// Providers
|
|
541
|
+
import {
|
|
542
|
+
EmailProviderRegistry,
|
|
543
|
+
EmailFactoryService,
|
|
544
|
+
SmtpProvider,
|
|
545
|
+
SendGridProvider,
|
|
546
|
+
MailgunProvider,
|
|
547
|
+
} from '@flusys/nestjs-email/providers';
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
**Last Updated:** 2026-02-18
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "EmailConfigService", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return EmailConfigService;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _common = require("@nestjs/common");
|
|
12
|
+
const _interfaces = require("../interfaces");
|
|
13
|
+
const _emailconstants = require("./email.constants");
|
|
14
|
+
function _define_property(obj, key, value) {
|
|
15
|
+
if (key in obj) {
|
|
16
|
+
Object.defineProperty(obj, key, {
|
|
17
|
+
value: value,
|
|
18
|
+
enumerable: true,
|
|
19
|
+
configurable: true,
|
|
20
|
+
writable: true
|
|
21
|
+
});
|
|
22
|
+
} else {
|
|
23
|
+
obj[key] = value;
|
|
24
|
+
}
|
|
25
|
+
return obj;
|
|
26
|
+
}
|
|
27
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
28
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
29
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
30
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
31
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
32
|
+
}
|
|
33
|
+
function _ts_metadata(k, v) {
|
|
34
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
35
|
+
}
|
|
36
|
+
function _ts_param(paramIndex, decorator) {
|
|
37
|
+
return function(target, key) {
|
|
38
|
+
decorator(target, key, paramIndex);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
let EmailConfigService = class EmailConfigService {
|
|
42
|
+
isCompanyFeatureEnabled() {
|
|
43
|
+
return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
|
|
44
|
+
}
|
|
45
|
+
getDatabaseMode() {
|
|
46
|
+
return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
|
|
47
|
+
}
|
|
48
|
+
isMultiTenant() {
|
|
49
|
+
return this.getDatabaseMode() === 'multi-tenant';
|
|
50
|
+
}
|
|
51
|
+
getRateLimitPerMinute() {
|
|
52
|
+
return this.options.config?.rateLimitPerMinute ?? 60;
|
|
53
|
+
}
|
|
54
|
+
isLoggingEnabled() {
|
|
55
|
+
return this.options.config?.enableLogging ?? false;
|
|
56
|
+
}
|
|
57
|
+
getDefaultProvider() {
|
|
58
|
+
return this.options.config?.defaultProvider;
|
|
59
|
+
}
|
|
60
|
+
getDefaultFromName() {
|
|
61
|
+
return _emailconstants.DEFAULT_FROM_NAME;
|
|
62
|
+
}
|
|
63
|
+
getDefaultDatabaseConfig() {
|
|
64
|
+
return this.options.config?.defaultDatabaseConfig;
|
|
65
|
+
}
|
|
66
|
+
getOptions() {
|
|
67
|
+
return this.options;
|
|
68
|
+
}
|
|
69
|
+
constructor(options){
|
|
70
|
+
_define_property(this, "options", void 0);
|
|
71
|
+
this.options = options;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
EmailConfigService = _ts_decorate([
|
|
75
|
+
(0, _common.Injectable)(),
|
|
76
|
+
_ts_param(0, (0, _common.Inject)(_emailconstants.EMAIL_MODULE_OPTIONS)),
|
|
77
|
+
_ts_metadata("design:type", Function),
|
|
78
|
+
_ts_metadata("design:paramtypes", [
|
|
79
|
+
typeof _interfaces.EmailModuleOptions === "undefined" ? Object : _interfaces.EmailModuleOptions
|
|
80
|
+
])
|
|
81
|
+
], EmailConfigService);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email Module Constants
|
|
3
|
+
*/ "use strict";
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
function _export(target, all) {
|
|
8
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
_export(exports, {
|
|
14
|
+
get DEFAULT_FROM_NAME () {
|
|
15
|
+
return DEFAULT_FROM_NAME;
|
|
16
|
+
},
|
|
17
|
+
get EMAIL_MODULE_OPTIONS () {
|
|
18
|
+
return EMAIL_MODULE_OPTIONS;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
const EMAIL_MODULE_OPTIONS = 'EMAIL_MODULE_OPTIONS';
|
|
22
|
+
const DEFAULT_FROM_NAME = 'FLUSYS';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./email.constants"), exports);
|
|
6
|
+
_export_star(require("./email-config.service"), exports);
|
|
7
|
+
function _export_star(from, to) {
|
|
8
|
+
Object.keys(from).forEach(function(k) {
|
|
9
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
10
|
+
Object.defineProperty(to, k, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function() {
|
|
13
|
+
return from[k];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return from;
|
|
19
|
+
}
|