npm package: @flusys/ng-email
Description: Email management module for FLUSYS Angular applications
Latest version: 4.1.1

# @flusys/ng-email

> Email management UI library for the FLUSYS Angular platform — provider configuration, visual template builder, and programmatic email sending.

[![npm version](https://img.shields.io/npm/v/@flusys/ng-email.svg)](https://www.npmjs.com/package/@flusys/ng-email)
[![Angular](https://img.shields.io/badge/Angular-21-red.svg)](https://angular.io)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

---

## Table of Contents

- [Overview](#overview)
- [Features](#features)
- [Compatibility](#compatibility)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Email Schema](#email-schema)
  - [IEmailSchema](#iemailschema)
  - [Block Types](#block-types)
- [Services](#services)
  - [EmailProviderApiService](#emailproviderapiservice)
  - [EmailTemplateApiService](#emailtemplateapiservice)
  - [EmailSendService](#emailsendservice)
  - [EmailBuilderStateService](#emailbuilderstateservice)
- [Components](#components)
  - [EmailBuilderComponent](#emailbuildercomponent)
  - [EmailPreviewComponent](#emailpreviewcomponent)
- [Email Provider Enum](#email-provider-enum)
- [API Endpoints](#api-endpoints)
- [Configuration Reference](#configuration-reference)
- [Troubleshooting](#troubleshooting)
- [License](#license)

---

## Overview

`@flusys/ng-email` provides a complete email management UI for FLUSYS applications. Administrators can configure SMTP/SendGrid/Mailgun providers, design reusable email templates via a block-based visual builder, and developers can send emails programmatically using `EmailSendService`.

Templates are stored as `IEmailSchema` JSON in the backend (`nestjs-email`) and rendered server-side with `{{variable}}` interpolation.

---

## Features

- ✅ Email provider configuration UI (SMTP, SendGrid, Mailgun)
- ✅ Visual block-based email template builder
- ✅ `{{variable}}` interpolation with XSS protection
- ✅ Email template preview (desktop + mobile viewport)
- ✅ `EmailSendService` for programmatic sending from any feature
- ✅ Template versioning (draft / published)
- ✅ File/image insertion via `ng-storage` integration

---

## Compatibility

| Package | Version |
|---------|---------|
| Angular | 21+ |
| @flusys/ng-core | 4.x |
| @flusys/ng-shared | 4.x |

---

## Installation

```bash
npm install @flusys/ng-email @flusys/ng-core @flusys/ng-shared
```

---

## Quick Start

### 1. Enable Email in Config

```typescript
// environments/environment.ts
export const environment = {
  services: {
    email: { enabled: true },
  },
};
```

### 2. Add Email Routes

```typescript
// app.routes.ts
import { EMAIL_ROUTES } from '@flusys/ng-email';

export const routes: Routes = [
  {
    path: 'email',
    loadChildren: () => EMAIL_ROUTES,
  },
];
```

### 3. Send Email Programmatically

```typescript
import { EmailSendService } from '@flusys/ng-email';

@Injectable({ providedIn: 'root' })
export class OrderService {
  private emailSend = inject(EmailSendService);

  sendOrderConfirmation(order: Order): Observable<IMessageResponse> {
    return this.emailSend.send({
      templateKey: 'order-confirmation',
      to: order.customerEmail,
      variables: {
        customerName: order.customerName,
        orderNumber: order.id,
        totalAmount: order.total.toFixed(2),
      },
    });
  }
}
```

---

## Email Schema

### IEmailSchema

Complete email template definition stored as JSON:

```typescript
interface IEmailSchema {
  id: string;
  name: string;
  key: string;          // Unique identifier for programmatic sending
  subject: string;      // Supports {{variable}} interpolation
  previewText?: string;
  blocks: IEmailBlock[];
  settings: IEmailSettings;
  isDraft: boolean;
  createdAt: string;
  updatedAt: string;
}

interface IEmailSettings {
  backgroundColor: string;
  contentWidth: number;      // pixels (default: 600)
  fontFamily: string;
  padding: number;           // px
}
```

### Block Types

Email templates are composed of blocks:

| Block Type | Description | Key Properties |
|------------|-------------|----------------|
| `header` | Logo + company name header | `logoFileId`, `companyName`, `backgroundColor` |
| `text` | Rich text paragraph | `content` (HTML), `fontSize`, `color`, `align` |
| `heading` | H1-H4 heading | `content`, `level`, `color`, `align` |
| `button` | Call-to-action button | `label`, `url`, `backgroundColor`, `textColor` |
| `image` | Image block | `fileId`, `altText`, `width`, `link` |
| `divider` | Horizontal rule | `color`, `thickness` |
| `spacer` | Vertical whitespace | `height` |
| `columns` | Two-column layout | `leftBlock`, `rightBlock` |
| `footer` | Unsubscribe/legal footer | `content`, `unsubscribeUrl` |

```typescript
interface IEmailBlock {
  id: string;
  type: EmailBlockType;
  [key: string]: unknown; // Block-specific properties
}
```

**Variable Interpolation:**

Use `{{variableName}}` in any text content:

```
Subject: "Order {{orderNumber}} Confirmed"
Content: "Hi {{customerName}}, your order totaling ${{totalAmount}} is confirmed."
```

Variables are XSS-sanitized server-side before rendering.

---

## Services

### EmailProviderApiService

Manages email provider configuration (SMTP, SendGrid, Mailgun):

```typescript
import { EmailProviderApiService } from '@flusys/ng-email';

@Injectable({ ... })
export class MyService {
  private providerApi = inject(EmailProviderApiService);

  getProviders(): Observable<IListResponse<IEmailProvider>> {
    return this.providerApi.getAll({});
  }

  configureSmtp(config: ISmtpConfig): Observable<ISingleResponse<IEmailProvider>> {
    return this.providerApi.insert({
      type: EmailProviderEnum.SMTP,
      ...config,
    });
  }

  testProvider(id: string): Observable<IMessageResponse> {
    return this.providerApi.test(id);
  }
}
```

### EmailTemplateApiService

Manages email template CRUD and publishing:

```typescript
import { EmailTemplateApiService } from '@flusys/ng-email';

@Injectable({ ... })
export class MyService {
  private templateApi = inject(EmailTemplateApiService);

  getTemplates(): Observable<IListResponse<IEmailTemplate>> {
    return this.templateApi.getAll({ pageSize: 50 });
  }

  getByKey(key: string): Observable<ISingleResponse<IEmailTemplate>> {
    return this.templateApi.getByKey(key);
  }

  publish(id: string): Observable<IMessageResponse> {
    return this.templateApi.publish(id);
  }
}
```

### EmailSendService

Programmatic email sending from any feature module:

```typescript
import { EmailSendService } from '@flusys/ng-email';

@Injectable({ providedIn: 'root' })
export class NotificationBridgeService {
  private emailSend = inject(EmailSendService);

  sendWelcomeEmail(user: IUser): Observable<IMessageResponse> {
    return this.emailSend.send({
      templateKey: 'welcome',
      to: user.email,
      variables: {
        firstName: user.firstName,
        loginUrl: 'https://app.example.com/auth/login',
      },
    });
  }

  sendPasswordReset(email: string, resetToken: string): Observable<IMessageResponse> {
    return this.emailSend.send({
      templateKey: 'password-reset',
      to: email,
      variables: { resetToken, expiresIn: '24 hours' },
    });
  }
}
```

**EmailSendService.send() Options:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `templateKey` | `string` | ✅ | Unique template key |
| `to` | `string \| string[]` | ✅ | Recipient(s) |
| `variables` | `Record<string, string \| number>` | — | Template variables |
| `cc` | `string[]` | — | CC recipients |
| `bcc` | `string[]` | — | BCC recipients |
| `replyTo` | `string` | — | Reply-to address |
| `attachments` | `IEmailAttachment[]` | — | File attachments |

### EmailBuilderStateService

Component-scoped service managing the visual builder state:

```typescript
// Component-scoped — not provided at root
@Component({
  providers: [EmailBuilderStateService],
})
export class EmailBuilderComponent {
  private state = inject(EmailBuilderStateService);

  schema = this.state.schema;             // Signal<IEmailSchema>
  selectedBlock = this.state.selectedBlock; // Signal<IEmailBlock | null>
  isDirty = this.state.isDirty;           // Signal<boolean>
  previewMode = this.state.previewMode;   // Signal<'desktop' | 'mobile'>
}
```

---

## Components

### EmailBuilderComponent

Visual block-based email template editor:

```html
<flusys-email-builder
  [templateId]="templateId"
  (saved)="onTemplateSaved($event)"
/>
```

Features:
- Left panel: Block type palette
- Center: Email canvas (drag to reorder blocks)
- Right panel: Selected block properties
- Top bar: Save draft / Publish / Preview toggle

### EmailPreviewComponent

Renders an email template with mock variable values:

```html
<flusys-email-preview
  [schema]="emailSchema"
  [variables]="mockVariables"
  [viewport]="'desktop'"
/>
```

| Input | Type | Description |
|-------|------|-------------|
| `schema` | `IEmailSchema` | Template to preview |
| `variables` | `Record<string, string>` | Mock values for `{{vars}}` |
| `viewport` | `'desktop' \| 'mobile'` | Preview viewport width |

---

## Email Provider Enum

```typescript
import { EmailProviderEnum } from '@flusys/ng-email';

enum EmailProviderEnum {
  SMTP = 'SMTP',
  SENDGRID = 'SENDGRID',
  MAILGUN = 'MAILGUN',
}
```

---

## API Endpoints

| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/email/provider/get-all` | List email providers |
| POST | `/email/provider/get/:id` | Get provider config |
| POST | `/email/provider/insert` | Add provider |
| POST | `/email/provider/update` | Update provider |
| POST | `/email/provider/delete` | Delete provider |
| POST | `/email/provider/test/:id` | Send test email |
| POST | `/email/template/get-all` | List templates |
| POST | `/email/template/get/:id` | Get template |
| POST | `/email/template/insert` | Create template |
| POST | `/email/template/update` | Update template |
| POST | `/email/template/delete` | Delete template |
| POST | `/email/template/publish/:id` | Publish template |
| POST | `/email/send` | Send email |

---

## Configuration Reference

| Config Key | Type | Default | Description |
|------------|------|---------|-------------|
| `services.email.enabled` | `boolean` | `false` | Enable email module |

Email provider credentials (API keys, SMTP host/port) are configured server-side in `nestjs-email`. The Angular client only calls the send API.

---

## Troubleshooting

**`EmailSendService.send()` returns 404**

Template with the given `key` doesn't exist or is still in draft. Publish the template first via the builder UI or `templateApi.publish(id)`.

**Visual builder blocks not reordering**

CDK drag-and-drop requires `@angular/cdk`. Install it and import `DragDropModule`.

**Images in email not displaying for recipients**

Images are referenced by file ID. The backend resolves these to absolute URLs when rendering. Ensure `ng-storage` is configured and the storage backend is publicly accessible (or uses presigned URLs).

**Variables showing as `{{varName}}` in sent emails**

The `variables` object key doesn't match the template placeholder. Check for exact case match: `{{customerName}}` requires `{ customerName: '...' }`.

**Provider test fails with "Connection refused"**

SMTP host/port is incorrect or the email provider's server is blocking the connection. Verify credentials in the Email Providers configuration page.

---

## License

MIT © FLUSYS