@zola_do/email 0.2.4 → 0.2.6

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 CHANGED
@@ -1,6 +1,20 @@
1
1
  # @zola_do/email
2
2
 
3
- Email service for NestJS applications with SMTP and Handlebars template support.
3
+ [![npm version](https://img.shields.io/npm/v/@zola_do/email.svg)](https://www.npmjs.com/package/@zola_do/email)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@zola_do/email.svg)](https://www.npmjs.com/package/@zola_do/email)
5
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
6
+
7
+ Email service for NestJS applications with SMTP transport and Handlebars template support.
8
+
9
+ ## Overview
10
+
11
+ `@zola_do/email` provides:
12
+
13
+ - **SMTP Transport** — Configurable via environment variables
14
+ - **Handlebars Templates** — Server-side template rendering
15
+ - **HTML Emails** — Send rich HTML content
16
+ - **Connection Verification** — Test SMTP connection
17
+ - **NestJS Integration** — Module-based setup
4
18
 
5
19
  ## Installation
6
20
 
@@ -12,13 +26,31 @@ npm install @zola_do/email
12
26
  npm install @zola_do/nestjs-shared
13
27
  ```
14
28
 
15
- ## Usage
29
+ ### Dependencies
30
+
31
+ ```bash
32
+ npm install @nestjs-modules/mailer nodemailer
33
+ npm install @types/nodemailer --save-dev
34
+ ```
35
+
36
+ ## Quick Start
16
37
 
17
- ### Module Setup
38
+ ### 1. Configure Environment
39
+
40
+ ```bash
41
+ # .env
42
+ EMAIL_SMTP=smtp.example.com
43
+ EMAIL_SMTP_PORT=587
44
+ EMAIL_SMTP_USERNAME=your-username
45
+ EMAIL_SMTP_PASSWORD=your-password
46
+ EMAIL_SMTP_DISPLAY_NAME=My App <noreply@example.com>
47
+ ```
48
+
49
+ ### 2. Register Module
18
50
 
19
51
  ```typescript
20
- import { Module } from '@nestjs/common';
21
- import { EmailModule } from '@zola_do/email';
52
+ import { Module } from "@nestjs/common";
53
+ import { EmailModule } from "@zola_do/email";
22
54
 
23
55
  @Module({
24
56
  imports: [EmailModule],
@@ -26,50 +58,415 @@ import { EmailModule } from '@zola_do/email';
26
58
  export class AppModule {}
27
59
  ```
28
60
 
29
- ### Sending Emails
30
-
31
- Inject `EmailService` and send emails:
61
+ ### 3. Send Emails
32
62
 
33
63
  ```typescript
34
- import { Injectable } from '@nestjs/common';
35
- import { EmailService } from '@zola_do/email';
64
+ import { Injectable } from "@nestjs/common";
65
+ import { EmailService } from "@zola_do/email";
36
66
 
37
67
  @Injectable()
38
68
  export class NotificationService {
39
69
  constructor(private readonly emailService: EmailService) {}
40
70
 
41
71
  async sendWelcomeEmail(userEmail: string, userName: string) {
42
- const body = `<h1>Welcome, ${userName}!</h1><p>Thanks for signing up.</p>`;
43
- await this.emailService.sendEmail(userEmail, 'Welcome', body);
72
+ await this.emailService.sendEmail({
73
+ to: userEmail,
74
+ subject: "Welcome to Our App",
75
+ html: `
76
+ <h1>Welcome, ${userName}!</h1>
77
+ <p>Thanks for signing up.</p>
78
+ `,
79
+ });
80
+ }
81
+ }
82
+ ```
83
+
84
+ ## Email Architecture
85
+
86
+ ```
87
+ ┌─────────────────────────────────────────────────────────────────────┐
88
+ │ Email Flow │
89
+ ├─────────────────────────────────────────────────────────────────────┤
90
+ │ │
91
+ │ Controller/Service │
92
+ │ │ │
93
+ │ │ 1. Prepare email data │
94
+ │ ▼ │
95
+ │ ┌─────────────────────────────────────┐ │
96
+ │ │ EmailService │ │
97
+ │ │ │ │
98
+ │ │ sendEmail({ to, subject, html }) │ │
99
+ │ └──────────────────┬──────────────────┘ │
100
+ │ │ │
101
+ │ │ 2. Render template (optional) │
102
+ │ ▼ │
103
+ │ ┌─────────────────────────────────────┐ │
104
+ │ │ templates/ │ │
105
+ │ │ welcome.hbs │ │
106
+ │ └──────────────────┬──────────────────┘ │
107
+ │ │ │
108
+ │ │ 3. Send via SMTP │
109
+ │ ▼ │
110
+ │ ┌─────────────────────────────────────┐ │
111
+ │ │ nodemailer │ │
112
+ │ │ (SMTP Transport) │ │
113
+ │ └──────────────────┬──────────────────┘ │
114
+ │ │ │
115
+ │ ▼ │
116
+ │ ┌──────────────┐ │
117
+ │ │ SMTP │ │
118
+ │ │ Server │ │
119
+ │ └──────────────┘ │
120
+ │ │
121
+ └─────────────────────────────────────────────────────────────────────┘
122
+ ```
123
+
124
+ ## EmailService
125
+
126
+ ### Send HTML Email
127
+
128
+ ```typescript
129
+ async sendEmail(options: {
130
+ to: string | string[];
131
+ subject: string;
132
+ html: string;
133
+ from?: string;
134
+ replyTo?: string;
135
+ cc?: string | string[];
136
+ bcc?: string | string[];
137
+ attachments?: Attachment[];
138
+ }): Promise<SentMessageInfo>
139
+ ```
140
+
141
+ ### Send with Template
142
+
143
+ ```typescript
144
+ import { MailerService } from "@nestjs-modules/mailer";
145
+ import { context } from "@handlebars/noder";
146
+
147
+ @Injectable()
148
+ export class NotificationService {
149
+ constructor(
150
+ private readonly emailService: EmailService,
151
+ private readonly mailerService: MailerService,
152
+ ) {}
153
+
154
+ async sendWelcomeWithTemplate(user: User) {
155
+ await this.mailerService.sendMail({
156
+ to: user.email,
157
+ subject: "Welcome!",
158
+ template: "welcome", // Looks for templates/welcome.hbs
159
+ context: {
160
+ name: user.name,
161
+ verifyUrl: `https://example.com/verify/${user.token}`,
162
+ },
163
+ });
44
164
  }
45
165
  }
46
166
  ```
47
167
 
48
- ### Handlebars Templates
168
+ ### Verify Connection
169
+
170
+ ```typescript
171
+ async testConnection() {
172
+ const isConnected = await this.emailService.verify();
173
+ if (!isConnected) {
174
+ throw new Error('Email service not available');
175
+ }
176
+ }
177
+ ```
178
+
179
+ ## Handlebars Templates
180
+
181
+ ### Template Location
182
+
183
+ Templates should be placed in `process.cwd() + '/templates/'`:
184
+
185
+ ```
186
+ project/
187
+ ├── templates/
188
+ │ ├── welcome.hbs
189
+ │ ├── reset-password.hbs
190
+ │ └── invoice.hbs
191
+ ├── src/
192
+ │ └── app.module.ts
193
+ └── package.json
194
+ ```
195
+
196
+ ### Template Example
49
197
 
50
- The module uses `@nestjs-modules/mailer` with a Handlebars adapter. Place templates in `process.cwd() + '/templates/'` and use the MailerService directly for template-based emails (inject `MailerService` from `@nestjs-modules/mailer`).
198
+ ```handlebars
199
+ {{! templates/welcome.hbs }}
200
+
201
+ <html>
202
+ <head>
203
+ <meta charset="utf-8" />
204
+ <title>Welcome</title>
205
+ <style>
206
+ body {
207
+ font-family: Arial, sans-serif;
208
+ }
209
+ .container {
210
+ max-width: 600px;
211
+ margin: 0 auto;
212
+ }
213
+ </style>
214
+ </head>
215
+ <body>
216
+ <div class="container">
217
+ <h1>Welcome, {{name}}!</h1>
218
+ <p>Thank you for joining {{appName}}.</p>
219
+ <a href="{{verifyUrl}}">Verify your email</a>
220
+ <p>Best,<br />The Team</p>
221
+ </div>
222
+ </body>
223
+ </html>
224
+ ```
225
+
226
+ ### Template Features
227
+
228
+ ```handlebars
229
+ {{! Conditionals }}
230
+ {{#if user.isPremium}}
231
+ <p>You have premium access!</p>
232
+ {{else}}
233
+ <p>Upgrade to premium for more features.</p>
234
+ {{/if}}
235
+
236
+ {{! Loops }}
237
+ {{#each items}}
238
+ <li>{{ this.name }} - {{ this.price }}</li>
239
+ {{/each}}
240
+
241
+ {{! Partials }}
242
+ {{> header }}
243
+ {{> footer }}
244
+
245
+ {{! Helpers }}
246
+ {{formatDate date 'MMMM Do YYYY'}}
247
+ {{currency amount}}
248
+ {{uppercase name}}
249
+ ```
250
+
251
+ ## EmailConfig
252
+
253
+ ### Default Configuration
254
+
255
+ ```typescript
256
+ {
257
+ transport: {
258
+ host: process.env.EMAIL_SMTP,
259
+ port: parseInt(process.env.EMAIL_SMTP_PORT, 10),
260
+ secure: false, // true for 465, false for other ports
261
+ auth: {
262
+ user: process.env.EMAIL_SMTP_USERNAME,
263
+ pass: process.env.EMAIL_SMTP_PASSWORD,
264
+ },
265
+ },
266
+ defaults: {
267
+ from: process.env.EMAIL_SMTP_DISPLAY_NAME || 'noreply@example.com',
268
+ },
269
+ template: {
270
+ dir: process.cwd() + '/templates/',
271
+ adapter: new HandlebarsAdapter(),
272
+ options: {
273
+ strict: true,
274
+ },
275
+ },
276
+ }
277
+ ```
51
278
 
52
- ### Verifying Connection
279
+ ### Custom Configuration
53
280
 
54
281
  ```typescript
55
- await this.emailService.verify();
282
+ import { Module } from "@nestjs/common";
283
+ import { EmailModule, EmailConfig } from "@zola_do/email";
284
+
285
+ @Module({
286
+ imports: [
287
+ EmailModule.forRoot({
288
+ transport: {
289
+ host: "smtp.gmail.com",
290
+ port: 465,
291
+ secure: true,
292
+ auth: {
293
+ user: "your-email@gmail.com",
294
+ pass: "your-app-password",
295
+ },
296
+ },
297
+ defaults: {
298
+ from: '"My App" <noreply@myapp.com>',
299
+ },
300
+ template: {
301
+ dir: __dirname + "/templates",
302
+ adapter: new HandlebarsAdapter(),
303
+ },
304
+ } as EmailConfig),
305
+ ],
306
+ })
307
+ export class AppModule {}
56
308
  ```
57
309
 
58
310
  ## Environment Variables
59
311
 
60
- | Variable | Description |
61
- |----------|-------------|
62
- | `EMAIL_SMTP` | SMTP host |
63
- | `EMAIL_SMTP_PORT` | SMTP port |
64
- | `EMAIL_SMTP_USERNAME` | SMTP username |
65
- | `EMAIL_SMTP_PASSWORD` | SMTP password |
66
- | `EMAIL_SMTP_DISPLAY_NAME` | From display name (defaults) |
312
+ | Variable | Description | Default |
313
+ | ------------------------- | ----------------- | --------------------- |
314
+ | `EMAIL_SMTP` | SMTP host | Required |
315
+ | `EMAIL_SMTP_PORT` | SMTP port | `587` |
316
+ | `EMAIL_SMTP_USERNAME` | SMTP username | Required |
317
+ | `EMAIL_SMTP_PASSWORD` | SMTP password | Required |
318
+ | `EMAIL_SMTP_DISPLAY_NAME` | Default from name | `noreply@example.com` |
319
+
320
+ ## SMTP Ports
321
+
322
+ | Port | Use | Secure |
323
+ | ------ | ----------- | -------- |
324
+ | `25` | Legacy | No |
325
+ | `465` | SMTPS | Yes |
326
+ | `587` | Submission | No (TLS) |
327
+ | `2525` | Alternative | No |
328
+
329
+ ## Common Email Patterns
330
+
331
+ ### Welcome Email
332
+
333
+ ```typescript
334
+ async sendWelcomeEmail(user: User) {
335
+ await this.mailerService.sendMail({
336
+ to: user.email,
337
+ subject: 'Welcome to Our Platform!',
338
+ template: 'welcome',
339
+ context: {
340
+ name: user.firstName,
341
+ verifyUrl: `${BASE_URL}/verify/${user.verificationToken}`,
342
+ },
343
+ });
344
+ }
345
+ ```
346
+
347
+ ### Password Reset
348
+
349
+ ```typescript
350
+ async sendPasswordReset(user: User) {
351
+ await this.mailerService.sendMail({
352
+ to: user.email,
353
+ subject: 'Password Reset Request',
354
+ template: 'reset-password',
355
+ context: {
356
+ name: user.name,
357
+ resetUrl: `${BASE_URL}/reset-password/${user.resetToken}`,
358
+ expiresIn: '1 hour',
359
+ },
360
+ });
361
+ }
362
+ ```
363
+
364
+ ### Invoice Email
365
+
366
+ ```typescript
367
+ async sendInvoice(user: User, invoice: Invoice) {
368
+ await this.mailerService.sendMail({
369
+ to: user.email,
370
+ subject: `Invoice #${invoice.number}`,
371
+ template: 'invoice',
372
+ context: {
373
+ invoiceNumber: invoice.number,
374
+ amount: invoice.amount,
375
+ dueDate: invoice.dueDate,
376
+ items: invoice.items,
377
+ total: invoice.total,
378
+ },
379
+ attachments: [
380
+ {
381
+ filename: `invoice-${invoice.number}.pdf`,
382
+ path: invoice.pdfPath,
383
+ },
384
+ ],
385
+ });
386
+ }
387
+ ```
388
+
389
+ ## API Reference
390
+
391
+ ### EmailModule
392
+
393
+ ```typescript
394
+ // Default configuration from environment
395
+ EmailModule.forRoot()
396
+
397
+ // Custom configuration
398
+ EmailModule.forRoot(config: EmailConfig)
399
+ ```
400
+
401
+ ### EmailService
402
+
403
+ ```typescript
404
+ class EmailService {
405
+ constructor(private readonly mailerService: MailerService) {}
406
+
407
+ async sendEmail(options: SendEmailOptions): Promise<SentMessageInfo>;
408
+ async verify(): Promise<boolean>;
409
+ }
410
+ ```
411
+
412
+ ### SendEmailOptions
413
+
414
+ ```typescript
415
+ interface SendEmailOptions {
416
+ to: string | string[];
417
+ subject: string;
418
+ html?: string;
419
+ text?: string;
420
+ from?: string;
421
+ replyTo?: string;
422
+ cc?: string | string[];
423
+ bcc?: string | string[];
424
+ attachments?: Attachment[];
425
+ }
426
+ ```
427
+
428
+ ## Troubleshooting
429
+
430
+ ### Q: Emails not sending?
431
+
432
+ 1. Check SMTP credentials in environment
433
+ 2. Verify SMTP server is accessible
434
+ 3. Test connection: `await emailService.verify()`
435
+
436
+ ### Q: Templates not found?
437
+
438
+ Ensure templates are in `process.cwd() + '/templates/'`:
439
+
440
+ ```typescript
441
+ // Check template path
442
+ console.log(process.cwd() + "/templates/");
443
+ ```
444
+
445
+ ### Q: Handlebars syntax errors?
446
+
447
+ Enable strict mode to see detailed errors:
448
+
449
+ ```typescript
450
+ template: {
451
+ options: { strict: true },
452
+ }
453
+ ```
454
+
455
+ ### Q: Gmail authentication fails?
456
+
457
+ If using Gmail with 2FA, create an App Password:
458
+
459
+ 1. Google Account → Security
460
+ 2. 2-Step Verification → App Passwords
461
+ 3. Generate new app password for your app
462
+
463
+ ## Related Packages
464
+
465
+ None - standalone email package
67
466
 
68
- ## Exports
467
+ ## License
69
468
 
70
- - `EmailModule` — Register the email module
71
- - `EmailService` — Send emails and verify connection
72
- - `EmailConfig` — Mailer configuration factory
469
+ ISC
73
470
 
74
471
  ## Community
75
472
 
@@ -0,0 +1,10 @@
1
+ export interface ZolaEmailMessage {
2
+ to: string | string[];
3
+ subject: string;
4
+ html?: string;
5
+ text?: string;
6
+ from?: string;
7
+ }
8
+ export interface ZolaEmailTransport {
9
+ send(mail: ZolaEmailMessage): Promise<unknown>;
10
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=email-transport.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-transport.interface.js","sourceRoot":"","sources":["../src/email-transport.interface.ts"],"names":[],"mappings":""}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './email.config';
2
2
  export * from './email.service';
3
3
  export * from './email.module';
4
+ export * from './email-transport.interface';
package/dist/index.js CHANGED
@@ -17,4 +17,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./email.config"), exports);
18
18
  __exportStar(require("./email.service"), exports);
19
19
  __exportStar(require("./email.module"), exports);
20
+ __exportStar(require("./email-transport.interface"), exports);
20
21
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA+B;AAC/B,kDAAgC;AAChC,iDAA+B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA+B;AAC/B,kDAAgC;AAChC,iDAA+B;AAC/B,8DAA4C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zola_do/email",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Email service for NestJS",
5
5
  "author": "zolaDO",
6
6
  "license": "ISC",