# 📧 Royal Enfield Workflow - Email Templates
Professional, responsive, and dynamic email templates for the Royal Enfield Workflow System.
---
## 🎯 Key Features
✅ **Dynamic & Adaptive** - Templates adjust based on request data, priority, and workflow state
✅ **Single Action Button** - Only "View Request Details" button that redirects to request URL
✅ **Fully Responsive** - Mobile-friendly design that works across all devices
✅ **Professional Design** - Royal Enfield branded with color-coded scenarios
✅ **Email Client Compatible** - Table-based layout for maximum compatibility
✅ **Placeholder-Based** - Easy to integrate with backend templating engines
---
## 📁 Template Files (12 Templates)
### Core Workflow Templates
1. **RequestCreated.html** - Request submission confirmation
2. **ApprovalRequest.html** - Single approver notification
3. **MultiApproverRequest.html** - Multi-level approver notification with chain
4. **ApprovalConfirmation.html** - Approval confirmation notification
5. **RejectionNotification.html** - Rejection notification
### TAT Management Templates
6. **TATReminder.html** - TAT deadline reminder (80% threshold)
7. **TATBreached.html** - TAT breach escalation
### Workflow Control Templates
8. **WorkflowPaused.html** - Workflow pause notification
9. **WorkflowResumed.html** - Workflow resume notification
### Participant Management Templates
10. **ParticipantAdded.html** - New approver/spectator welcome
11. **ApproverSkipped.html** - Approver skip notification
12. **RequestClosed.html** - Request closure summary
---
## 🎨 Visual Design
Each template uses color-coded gradients to indicate the scenario:
| Template | Header Color | Purpose |
|----------|-------------|---------|
| RequestCreated | Purple (#667eea) | Information |
| ApprovalRequest | Purple (#667eea) | Action Required |
| MultiApproverRequest | Purple (#667eea) | Action Required |
| ApprovalConfirmation | Green (#28a745) | Success |
| RejectionNotification | Red (#dc3545) | Error/Rejection |
| TATReminder | Orange (#ff9800) | Warning |
| TATBreached | Red (#dc3545) | Critical |
| WorkflowPaused | Gray (#6c757d) | Neutral |
| WorkflowResumed | Green (#28a745) | Success |
| ParticipantAdded | Purple (#667eea) | Information |
| ApproverSkipped | Cyan (#17a2b8) | Information |
| RequestClosed | Purple (#6f42c1) | Complete |
---
## 🔗 View Details Button
All templates feature a single action button:
- **Text:** "View Request Details" / "Review Request Now" / "Take Action Now"
- **Link Format:** `{baseURL}/request/{requestNumber}`
- **Example:** `https://workflow.royalenfield.com/request/REQ-2025-12-0013`
No approval/rejection buttons in emails - all actions happen within the application.
---
## 📋 How to Use Templates
### 1. Load Template File
```javascript
const fs = require('fs');
const template = fs.readFileSync('./emailtemplates/ApprovalRequest.html', 'utf8');
```
### 2. Replace Placeholders
```javascript
let emailContent = template
.replace(/\[ApproverName\]/g, approverName)
.replace(/\[InitiatorName\]/g, initiatorName)
.replace(/\[RequestId\]/g, requestId)
.replace(/\[ViewDetailsLink\]/g, `${baseURL}/request/${requestNumber}`)
.replace(/\[CompanyName\]/g, 'Royal Enfield');
```
### 3. Handle Dynamic Sections
```javascript
// Priority Section Example
if (priority === 'HIGH' || priority === 'CRITICAL') {
const priorityHTML = `
High Priority
This request has been marked as ${priority} priority and requires prompt attention.
`;
emailContent = emailContent.replace('[PrioritySection]', priorityHTML);
} else {
emailContent = emailContent.replace('[PrioritySection]', '');
}
```
### 4. Send Email
```javascript
await sendEmail({
to: recipientEmail,
subject: `[${requestId}] New Approval Request`,
html: emailContent
});
```
---
## 📖 Complete Documentation
See **TEMPLATE_MAPPING.md** for:
- Complete list of all placeholders for each template
- Dynamic section handling instructions
- Priority-based sending strategy
- Usage scenarios and triggers
- Security considerations
- Implementation examples
---
## 🚀 Integration Steps
### Step 1: Email Service Setup
```typescript
// services/email.service.ts
import nodemailer from 'nodemailer';
import fs from 'fs';
import path from 'path';
class EmailService {
private transporter;
constructor() {
this.transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
secure: process.env.SMTP_SECURE === 'true',
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD
}
});
}
async sendEmail(to: string, subject: string, html: string) {
return await this.transporter.sendMail({
from: process.env.EMAIL_FROM,
to,
subject,
html
});
}
loadTemplate(templateName: string): string {
const templatePath = path.join(__dirname, '../emailtemplates', `${templateName}.html`);
return fs.readFileSync(templatePath, 'utf8');
}
replaceplaceholders(template: string, data: Record): string {
let result = template;
for (const [key, value] of Object.entries(data)) {
const regex = new RegExp(`\\[${key}\\]`, 'g');
result = result.replace(regex, value);
}
return result;
}
}
export const emailService = new EmailService();
```
### Step 2: Create Email Handlers
```typescript
// services/emailNotification.service.ts
export async function sendApprovalRequest(approverEmail: string, requestData: any) {
const template = emailService.loadTemplate('ApprovalRequest');
const placeholders = {
ApproverName: approverEmail.split('@')[0],
InitiatorName: requestData.initiatorName,
RequestId: requestData.requestNumber,
RequestDate: formatDate(requestData.createdAt),
RequestTime: formatTime(requestData.createdAt),
RequestType: requestData.requestType,
RequestDescription: requestData.description,
PrioritySection: getPrioritySection(requestData.priority),
ViewDetailsLink: `${process.env.BASE_URL}/request/${requestData.requestNumber}`,
CompanyName: 'Royal Enfield'
};
const html = emailService.replaceplaceholders(template, placeholders);
await emailService.sendEmail(
approverEmail,
`[${requestData.requestNumber}] New Approval Request`,
html
);
}
```
### Step 3: Add to Workflow Events
```typescript
// In workflow.service.ts
await sendApprovalRequest(approverEmail, requestData);
```
---
## 🔧 Environment Variables Required
Add to your `.env` file:
```env
# SMTP Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-email@domain.com
SMTP_PASSWORD=your-app-password
# Email Settings
EMAIL_FROM=RE Workflow System
BASE_URL=https://workflow.royalenfield.com
COMPANY_NAME=Royal Enfield
```
---
## ✅ Testing Templates
### Preview in Browser
Open any `.html` file directly in a browser to see the design. Placeholders will be visible as `[PlaceholderName]`.
### Test Email Sending
```typescript
// test/email.test.ts
import { emailService } from '../services/email.service';
describe('Email Templates', () => {
it('should send approval request email', async () => {
const template = emailService.loadTemplate('ApprovalRequest');
const testData = {
ApproverName: 'John Doe',
InitiatorName: 'Jane Smith',
RequestId: 'REQ-2025-12-0013',
// ... other test data
};
const html = emailService.replaceplaceholders(template, testData);
// Send to test email
await emailService.sendEmail('test@example.com', 'Test Email', html);
});
});
```
---
## 📊 Template Selection Logic
```typescript
function getTemplateForScenario(scenario: string, hasMultipleApprovers: boolean): string {
switch(scenario) {
case 'request_created':
return 'RequestCreated';
case 'approval_required':
return hasMultipleApprovers ? 'MultiApproverRequest' : 'ApprovalRequest';
case 'request_approved':
return 'ApprovalConfirmation';
case 'request_rejected':
return 'RejectionNotification';
case 'tat_reminder':
return 'TATReminder';
case 'tat_breached':
return 'TATBreached';
case 'workflow_paused':
return 'WorkflowPaused';
case 'workflow_resumed':
return 'WorkflowResumed';
case 'participant_added':
return 'ParticipantAdded';
case 'approver_skipped':
return 'ApproverSkipped';
case 'request_closed':
return 'RequestClosed';
default:
throw new Error(`Unknown scenario: ${scenario}`);
}
}
```
---
## 🎯 Priority Queue Implementation
Use Bull/BullMQ for reliable email delivery:
```typescript
import Queue from 'bull';
const emailQueue = new Queue('email-notifications', {
redis: {
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT
}
});
// Add email to queue with priority
export async function queueEmail(emailData: any, priority: 'critical' | 'high' | 'medium' | 'low') {
const priorityMap = { critical: 1, high: 2, medium: 3, low: 4 };
await emailQueue.add('send-email', emailData, {
priority: priorityMap[priority],
attempts: 3,
backoff: {
type: 'exponential',
delay: 5000
}
});
}
// Process email queue
emailQueue.process('send-email', async (job) => {
const { to, subject, html } = job.data;
await emailService.sendEmail(to, subject, html);
});
```
---
## 📞 Support & Customization
For template customization or issues:
1. Check **TEMPLATE_MAPPING.md** for complete documentation
2. Test templates in email clients (Gmail, Outlook, Apple Mail)
3. Validate HTML using online validators
4. Use email testing services (Litmus, Email on Acid)
---
## 📝 Change Log
**Version 2.0** (Dec 4, 2025)
- ✅ Removed all action buttons (Approve/Reject)
- ✅ Added single "View Request Details" button
- ✅ Made templates fully dynamic with conditional sections
- ✅ Added 12 templates for all scenarios
- ✅ Improved mobile responsiveness
- ✅ Professional design without emojis
- ✅ Added comprehensive documentation
**Version 1.0** (Initial Release)
- Basic templates with action buttons
- 4 templates (Approval, Rejection, Multi-Approver, Confirmation)
---
**Maintained by:** Royal Enfield Development Team
**Last Updated:** December 4, 2025
**Email Template Version:** 2.0