Re_Backend/src/emailtemplates/IMPLEMENTATION_PLAN.md

29 KiB

Email Notification Implementation Plan

📊 Current State Analysis

Existing Notification Types in System:

Based on codebase analysis, your system currently sends in-app notifications for:

Notification Type Current Method Should Send Email?
request_submitted In-app YES (High)
assignment In-app YES (High)
approval In-app YES (High)
rejection In-app YES (Critical)
workflow_paused In-app ⚠️ CONDITIONAL
workflow_resumed In-app YES (High)
pause_retrigger_request In-app ⚠️ CONDITIONAL
pause_retriggered In-app NO (In-app only)
tat_reminder (50%) In-app YES (Medium)
tat_reminder (75%) In-app YES (High)
tat_breach (100%) In-app YES (Critical)
mention (work notes) In-app NO (In-app only)
comment In-app NO (In-app only)
status_change In-app NO (In-app only)
document_added In-app NO (In-app only)
ai_conclusion_generated In-app NO (In-app only)
summary_generated In-app NO (In-app only)
approval_pending_closure In-app ⚠️ CONDITIONAL
auto-resume-workflow In-app NO (System)
closed In-app YES (Low)

🎯 Email vs In-App Notification Strategy

SEND EMAIL (High Impact, Action Required)

Criteria:

  • Requires user action
  • Time-sensitive
  • Critical for workflow progress
  • User might not be logged in

Scenarios:

  1. Request Created → Send to Initiator (confirmation)
  2. Approval Request → Send to Approver (action required)
  3. Request Approved → Send to Initiator (important update)
  4. Request Rejected → Send to Initiator (critical)
  5. TAT Reminder 50% → Send to Approver (early warning)
  6. TAT Reminder 75% → Send to Approver (urgent)
  7. TAT Breached 100% → Send to Approver + Management (critical)
  8. Workflow Resumed → Send to Current Approver (action needed)
  9. Request Closed → Send to All Participants (summary)

IN-APP ONLY (Low Impact, Real-time)

Criteria:

  • Real-time collaboration
  • Minor updates
  • User likely logged in
  • Frequent notifications

Scenarios:

  1. @Mentions in Work Notes → In-app only
  2. Comments Added → In-app only
  3. Documents Uploaded → In-app only
  4. Status Changes → In-app only
  5. AI Conclusion Generated → In-app only
  6. Summary Generated → In-app only
  7. Pause Retriggered → In-app only

⚠️ CONDITIONAL (Based on Settings)

Scenarios:

  1. Workflow Paused → Email if paused > 24 hours
  2. Participant Added → Email if user preference enabled
  3. Approver Skipped → Email to skipped approver only

📋 Template Mapping to Scenarios

Critical Priority Emails (Send Immediately)

Scenario Template Trigger Point Recipients
TAT Breached getTATBreachedEmail() TAT timer breach Approver, Management
Request Rejected getRejectionNotificationEmail() Approver rejects Initiator, Spectators

High Priority Emails (Send within 1 minute)

Scenario Template Trigger Point Recipients
Request Created getRequestCreatedEmail() Workflow created Initiator
Approval Request getApprovalRequestEmail() or getMultiApproverRequestEmail() Level assigned Approver
Request Approved getApprovalConfirmationEmail() Approver approves Initiator
TAT Reminder getTATReminderEmail() 80% TAT elapsed Approver
Workflow Resumed getWorkflowResumedEmail() Workflow resumed Approver, Initiator

Medium Priority Emails (Send within 5 minutes)

Scenario Template Trigger Point Recipients
Workflow Paused (>24h) getWorkflowPausedEmail() Long pause Approver, Initiator
Participant Added getParticipantAddedEmail() User preference New participant
Approver Skipped getApproverSkippedEmail() Skip action Skipped approver

Low Priority Emails (Batch send)

Scenario Template Trigger Point Recipients
Request Closed getRequestClosedEmail() Workflow closed All participants

🔐 CRITICAL: Email Preference Control

Two-Level Preference System:

┌─────────────────────────────────────┐
│  Email Notification Request         │
└──────────────┬──────────────────────┘
               │
               ▼
        ┌──────────────┐
        │ Admin Level  │
        │ Enabled?     │ ──NO──> ❌ Don't send (admin disabled)
        └──────┬───────┘
               │ YES
               ▼
        ┌──────────────┐
        │ User Level   │
        │ Enabled?     │ ──NO──> ❌ Don't send (user disabled)
        └──────┬───────┘
               │ YES
               ▼
        ┌──────────────┐
        │ ✅ Send Email │
        └───────────────┘

IMPORTANT: Activity logs are ALWAYS captured regardless of preferences!

Preference Logic:

// Check before sending ANY email
const shouldSend = await shouldSendEmail(userId, EmailNotificationType.APPROVAL_REQUEST);

if (shouldSend) {
  await emailService.sendEmail(...);
} else {
  logger.info('Email skipped due to preferences');
}

// Activity ALWAYS logged regardless
await activityService.log({
  type: 'assignment',
  // ... activity data
});

Critical Emails (Override User Preference):

Some emails are TOO important to be disabled by users:

  • Request Rejected - User must know
  • TAT Breached - Critical escalation

For these, only admin can disable (user preference ignored):

if (CRITICAL_EMAILS.includes(emailType)) {
  // Check admin only, ignore user preference
  const adminEnabled = await isAdminEmailEnabled(emailType);
  if (adminEnabled) return true;
}

🔧 Implementation Architecture

Phase 0: Preference System (REQUIRED FIRST)

Create preference checking before ANY email:

A. Email Preferences Helper (emailPreferences.helper.ts) Created

B. System Config Table:

-- Admin-level email controls
INSERT INTO system_configs (config_key, config_value, description) VALUES
('email.enabled', 'true', 'Global email notifications enabled/disabled'),
('email.request_created.enabled', 'true', 'Request created emails'),
('email.approval_request.enabled', 'true', 'Approval request emails'),
('email.request_approved.enabled', 'true', 'Approval confirmation emails'),
('email.request_rejected.enabled', 'true', 'Rejection emails (critical)'),
('email.tat_reminder_50.enabled', 'true', 'TAT 50% reminder emails'),
('email.tat_reminder_75.enabled', 'true', 'TAT 75% reminder emails'),
('email.tat_breached.enabled', 'true', 'TAT breach emails (critical)'),
('email.workflow_resumed.enabled', 'true', 'Workflow resumed emails'),
('email.request_closed.enabled', 'true', 'Request closed emails');

C. User Preferences Table:

// UserPreference.preferences column (JSONB)
{
  "email": {
    "enabled": true,  // Global email preference
    "request_created": true,
    "approval_request": true,
    "request_approved": true,
    "request_rejected": true,  // Can be overridden for critical
    "tat_reminder_50": true,
    "tat_reminder_75": true,
    "tat_breached": true,      // Can be overridden for critical
    "workflow_resumed": true,
    "request_closed": false     // User can opt-out of closure emails
  },
  "notification": {
    "enabled": true,
    "mention": true,
    "comment": true,
    "assignment": true,
    "status_change": true
  }
}

Phase 1: Email Service Creation

Create email.service.ts:

import nodemailer from 'nodemailer';
import { 
  getRequestCreatedEmail,
  getApprovalRequestEmail,
  // ... all template functions
} from '@/emailtemplates';

export class EmailService {
  private transporter: nodemailer.Transporter;
  
  constructor() {
    this.transporter = nodemailer.createTransport({
      host: process.env.SMTP_HOST,
      port: parseInt(process.env.SMTP_PORT || '587'),
      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): Promise<void> {
    try {
      await this.transporter.sendMail({
        from: process.env.EMAIL_FROM,
        to,
        subject,
        html
      });
      logger.info(`✅ Email sent to ${to}: ${subject}`);
    } catch (error) {
      logger.error(`❌ Failed to send email to ${to}:`, error);
      throw error;
    }
  }
}

export const emailService = new EmailService();

Phase 2: Email Notification Service

Create emailNotification.service.ts:

import { emailService } from './email.service';
import { 
  getRequestCreatedEmail,
  getApprovalRequestEmail,
  getMultiApproverRequestEmail,
  getApprovalConfirmationEmail,
  getRejectionNotificationEmail,
  getTATReminderEmail,
  getTATBreachedEmail,
  getWorkflowPausedEmail,
  getWorkflowResumedEmail,
  getParticipantAddedEmail,
  getApproverSkippedEmail,
  getRequestClosedEmail,
  getViewDetailsLink
} from '@/emailtemplates';

export class EmailNotificationService {
  
  /**
   * Send request created email to initiator
   */
  async sendRequestCreated(request: any, initiator: any, firstApprover: any) {
    const data = {
      recipientName: initiator.name,
      requestId: request.requestNumber,
      requestTitle: request.title,
      initiatorName: initiator.name,
      firstApproverName: firstApprover.name,
      requestType: request.type,
      priority: request.priority,
      requestDate: formatDate(request.createdAt),
      requestTime: formatTime(request.createdAt),
      totalApprovers: request.totalApprovers,
      expectedTAT: request.tatHours,
      viewDetailsLink: getViewDetailsLink(request.requestNumber),
      companyName: 'Royal Enfield'
    };
    
    const html = getRequestCreatedEmail(data);
    await emailService.sendEmail(
      initiator.email,
      `[${request.requestNumber}] Request Created Successfully`,
      html
    );
  }
  
  /**
   * Send approval request email to approver
   */
  async sendApprovalRequest(request: any, approver: any, initiator: any, isMultiLevel: boolean) {
    if (isMultiLevel) {
      // Use multi-approver template with approval chain
      const data = {
        recipientName: approver.name,
        requestId: request.requestNumber,
        approverName: approver.name,
        initiatorName: initiator.name,
        requestType: request.type,
        requestDescription: request.description,
        priority: request.priority,
        requestDate: formatDate(request.createdAt),
        requestTime: formatTime(request.createdAt),
        approverLevel: approver.levelNumber,
        totalApprovers: request.totalApprovers,
        approversList: buildApprovalChain(request.approvalLevels, approver.levelNumber),
        viewDetailsLink: getViewDetailsLink(request.requestNumber),
        companyName: 'Royal Enfield'
      };
      
      const html = getMultiApproverRequestEmail(data);
      await emailService.sendEmail(
        approver.email,
        `[${request.requestNumber}] Multi-Level Approval Request - Your Turn`,
        html
      );
    } else {
      // Use single approver template
      const data = {
        recipientName: approver.name,
        requestId: request.requestNumber,
        approverName: approver.name,
        initiatorName: initiator.name,
        requestType: request.type,
        requestDescription: request.description,
        priority: request.priority,
        requestDate: formatDate(request.createdAt),
        requestTime: formatTime(request.createdAt),
        viewDetailsLink: getViewDetailsLink(request.requestNumber),
        companyName: 'Royal Enfield'
      };
      
      const html = getApprovalRequestEmail(data);
      await emailService.sendEmail(
        approver.email,
        `[${request.requestNumber}] Approval Request - Action Required`,
        html
      );
    }
  }
  
  // ... Add methods for other email types
}

export const emailNotificationService = new EmailNotificationService();

Phase 3: Integration Points

Update existing services to send emails alongside in-app notifications:

A. workflow.service.ts - createWorkflow()

// After creating workflow (around line 2362)

import { shouldSendEmail, shouldSendInAppNotification, EmailNotificationType } from '@/emailtemplates/emailPreferences.helper';

// Check preferences before sending in-app notification
const sendInAppToInitiator = await shouldSendInAppNotification(
  initiatorId,
  'request_submitted'
);

if (sendInAppToInitiator) {
  await notificationService.sendToUsers([initiatorId], {
    title: 'Request Submitted Successfully',
    body: `Your request "${workflowData.title}" has been submitted...`,
    type: 'request_submitted',
    priority: 'MEDIUM'
  });
}

// Check preferences before sending email
const sendEmailToInitiator = await shouldSendEmail(
  initiatorId,
  EmailNotificationType.REQUEST_CREATED
);

if (sendEmailToInitiator) {
  await emailNotificationService.sendRequestCreated(
    workflow,
    initiator,
    firstApprover
  );
}

// APPROVER NOTIFICATION
const sendInAppToApprover = await shouldSendInAppNotification(
  approverId,
  'assignment'
);

if (sendInAppToApprover) {
  await notificationService.sendToUsers([approverId], {
    title: 'New Request Assigned',
    type: 'assignment',
    priority: 'HIGH',
    actionRequired: true
  });
}

// Check preferences before sending email to approver
const sendEmailToApprover = await shouldSendEmail(
  approverId,
  EmailNotificationType.APPROVAL_REQUEST
);

if (sendEmailToApprover) {
  const isMultiLevel = approvalLevels.length > 1;
  await emailNotificationService.sendApprovalRequest(
    workflow,
    approver,
    initiator,
    isMultiLevel
  );
}

// ACTIVITY LOG - Always captured regardless of preferences
await activityService.log({
  requestId: workflow.requestId,
  type: 'created',
  user: { userId: initiatorId, name: initiatorName },
  timestamp: new Date().toISOString(),
  action: 'Request created',
  details: `Request ${requestNumber} created and assigned to ${approverName}`
});

B. approval.service.ts - approveRequest()

// After approval (around line 134)

// EXISTING: In-app notification
await notificationService.sendToUsers([initiatorId], {
  title: 'Request Approved',
  type: 'approval',
  priority: 'HIGH'
});

// NEW: Send email
await emailNotificationService.sendApprovalConfirmation(
  request,
  approver,
  initiator,
  isFinalApproval,
  nextApprover
);

C. approval.service.ts - rejectRequest()

// After rejection (around line 513)

// EXISTING: In-app notification
await notificationService.sendToUsers([initiatorId], {
  title: 'Request Rejected',
  type: 'rejection',
  priority: 'HIGH'
});

// NEW: Send email (CRITICAL)
await emailNotificationService.sendRejectionNotification(
  request,
  approver,
  initiator,
  rejectionReason
);

D. tatProcessor.ts - TAT Notifications

// TAT Reminder (80%)
if (type === 'threshold1') {
  // In-app notification
  await notificationService.sendToUsers([approverId], {...});
  
  // Email notification
  await emailNotificationService.sendTATReminder(request, approver);
}

// TAT Breached
if (type === 'breach') {
  // In-app notification
  await notificationService.sendToUsers([approverId], {...});
  
  // Email notification (CRITICAL)
  await emailNotificationService.sendTATBreached(
    request,
    approver,
    managementUsers // Also notify management
  );
}

E. pause.service.ts - Pause/Resume

// Workflow Paused
await notificationService.sendToUsers([...], {...});

// Email ONLY if pause > 24 hours
const pauseDuration = dayjs(resumeDate).diff(dayjs(), 'hours');
if (pauseDuration > 24) {
  await emailNotificationService.sendWorkflowPaused(...);
}

// Workflow Resumed
await notificationService.sendToUsers([...], {...});
await emailNotificationService.sendWorkflowResumed(...);

🎯 Email Sending Decision Tree

┌─────────────────────────────────┐
│  Notification Triggered         │
└────────────┬────────────────────┘
             │
             ▼
      ┌──────────────┐
      │ Is Critical? │ ──YES──> Send Email Immediately
      │ (Rejection,  │          (Critical Priority)
      │  TAT Breach) │
      └──────┬───────┘
             │ NO
             ▼
      ┌──────────────┐
      │ Requires     │ ──YES──> Send Email
      │ Action?      │          (High Priority)
      │ (Approval,   │
      │  Assignment) │
      └──────┬───────┘
             │ NO
             ▼
      ┌──────────────┐
      │ Important    │ ──YES──> Send Email
      │ Update?      │          (Medium Priority)
      │ (Approved,   │
      │  Resumed)    │
      └──────┬───────┘
             │ NO
             ▼
      ┌──────────────┐
      │ Real-time    │ ──YES──> In-App ONLY
      │ Interaction? │          (No email)
      │ (@mention,   │
      │  comment,    │
      │  status)     │
      └──────────────┘

📧 Email Scenarios - Detailed Implementation

Scenario 1: Request Created

When: User submits a new workflow request
Template: getRequestCreatedEmail()
Recipients: Initiator (confirmation)
Priority: High
Also Send In-App: Yes

Integration Point:

// File: services/workflow.service.ts
// Method: createWorkflow()
// Line: ~2362-2373

// Add after in-app notification
await emailNotificationService.sendRequestCreated(
  workflow,
  initiatorUser,
  firstApproverUser
);

Scenario 2: Approval Request (Assignment)

When: Request assigned to approver
Template: getApprovalRequestEmail() OR getMultiApproverRequestEmail()
Recipients: Approver
Priority: High
Also Send In-App: Yes
Action Required: YES

Decision Logic:

  • If totalApprovers > 1 → Use MultiApproverRequest template
  • If totalApprovers === 1 → Use ApprovalRequest template

Integration Point:

// File: services/workflow.service.ts
// Method: createWorkflow()
// Line: ~2374-2396

// Add after in-app notification to approver
const isMultiLevel = approvalLevels.length > 1;
await emailNotificationService.sendApprovalRequest(
  workflow,
  approverUser,
  initiatorUser,
  isMultiLevel
);

Scenario 3: Request Approved

When: Approver approves the request
Template: getApprovalConfirmationEmail()
Recipients: Initiator
Priority: High
Also Send In-App: Yes

Integration Point:

// File: services/approval.service.ts
// Method: approveRequest()
// Line: ~134-145

// Add after in-app notification
await emailNotificationService.sendApprovalConfirmation(
  workflow,
  approverUser,
  initiatorUser,
  isFinalApproval,
  nextApproverUser
);

Scenario 4: Request Rejected

When: Approver rejects the request
Template: getRejectionNotificationEmail()
Recipients: Initiator, Spectators
Priority: CRITICAL
Also Send In-App: Yes

Integration Point:

// File: services/approval.service.ts
// Method: rejectRequest()
// Line: ~513-525

// Add after in-app notification
await emailNotificationService.sendRejectionNotification(
  workflow,
  approverUser,
  initiatorUser,
  rejectionReason
);

Scenario 5: TAT Reminders (3 Levels)

When: 50%, 75%, and 100% (breach) of TAT elapsed
Template: getTATReminderEmail() (50%, 75%), getTATBreachedEmail() (100%)
Recipients: Approver
Priority: Medium (50%), High (75%), Critical (100%)
Also Send In-App: Yes

Integration Point:

// File: queues/tatProcessor.ts
// Update TAT thresholds to: 50%, 75%, 100% (breach)

// TAT 50% - Early Warning
if (elapsedPercentage >= 50 && !reminded50) {
  // In-app notification
  await notificationService.sendToUsers([approverId], {
    title: 'TAT Reminder - 50% Elapsed',
    type: 'tat_reminder_50',
    priority: 'MEDIUM'
  });
  
  // Email (check preferences)
  const shouldEmail = await shouldSendEmail(
    approverId,
    EmailNotificationType.TAT_REMINDER_50
  );
  
  if (shouldEmail) {
    await emailNotificationService.sendTATReminder(
      workflow,
      approver,
      { threshold: 50, timeRemaining: '...' }
    );
  }
}

// TAT 75% - Urgent Warning
if (elapsedPercentage >= 75 && !reminded75) {
  // In-app notification
  await notificationService.sendToUsers([approverId], {
    title: 'TAT Reminder - 75% Elapsed',
    type: 'tat_reminder_75',
    priority: 'HIGH'
  });
  
  // Email (check preferences)
  const shouldEmail = await shouldSendEmail(
    approverId,
    EmailNotificationType.TAT_REMINDER_75
  );
  
  if (shouldEmail) {
    await emailNotificationService.sendTATReminder(
      workflow,
      approver,
      { threshold: 75, timeRemaining: '...' }
    );
  }
}

// TAT 100% - BREACH (Critical)
if (elapsedPercentage >= 100) {
  // In-app notification
  await notificationService.sendToUsers([approverId], {
    title: 'TAT BREACHED',
    type: 'tat_breach',
    priority: 'URGENT'
  });
  
  // Email (CRITICAL - check with override)
  const shouldEmail = await shouldSendEmailWithOverride(
    approverId,
    EmailNotificationType.TAT_BREACHED
  );
  
  if (shouldEmail) {
    await emailNotificationService.sendTATBreached(
      workflow,
      approver,
      { timeOverdue: '...' }
    );
    
    // Also notify management
    const mgmtUsers = await getManagementUsers();
    for (const mgmt of mgmtUsers) {
      await emailNotificationService.sendTATBreached(
        workflow,
        mgmt,
        { timeOverdue: '...' }
      );
    }
  }
}

Note: Activity logs are captured at ALL TAT thresholds regardless of email/notification preferences!


Scenario 6: TAT Breached

When: TAT deadline passed
Template: getTATBreachedEmail()
Recipients: Approver, Management (escalation)
Priority: CRITICAL
Also Send In-App: Yes

Integration Point:

// File: queues/tatProcessor.ts
// When: breach occurs
// Line: ~250-265

if (type === 'breach') {
  // Existing in-app notification
  await notificationService.sendToUsers([...]);
  
  // Add email to approver
  await emailNotificationService.sendTATBreached(
    workflow,
    approverUser,
    tatData
  );
  
  // Also notify management
  const managementUsers = await getManagementUsers();
  for (const mgmt of managementUsers) {
    await emailNotificationService.sendTATBreached(
      workflow,
      mgmt,
      tatData
    );
  }
}

Scenario 7: Workflow Resumed

When: Paused workflow resumes (auto or manual)
Template: getWorkflowResumedEmail()
Recipients: Current Approver, Initiator
Priority: High
Also Send In-App: Yes

Integration Point:

// File: services/pause.service.ts
// Method: resumeWorkflow()
// Line: ~455-510

// Add after in-app notifications
await emailNotificationService.sendWorkflowResumed(
  workflow,
  approverUser,
  initiatorUser,
  resumedByUser,
  pauseDuration
);

Scenario 8: Request Closed

When: Initiator closes the request after all approvals
Template: getRequestClosedEmail()
Recipients: All participants (approvers, spectators)
Priority: Low (can be batched)
Also Send In-App: Yes

Integration Point:

// File: controllers/conclusion.controller.ts
// Method: finalizeConclusion()
// Line: ~365-380

// Add after workflow closure
const allParticipants = await getRequestParticipants(requestId);
for (const participant of allParticipants) {
  await emailNotificationService.sendRequestClosed(
    workflow,
    participant,
    conclusionData
  );
}

🚫 DO NOT Send Email For:

Real-Time Collaboration (In-App Only):

  1. @Mentions in Work Notes

    • Type: mention
    • Why: Real-time, user is likely active
    • Keep: In-app notification only
  2. Comments/Work Notes Added

    • Type: comment
    • Why: Frequent, real-time discussion
    • Keep: In-app notification only
  3. Documents Uploaded

    • Type: document_added
    • Why: Minor update, user can see in activity
    • Keep: In-app notification only
  4. Status Changes

    • Type: status_change
    • Why: Covered by other email notifications
    • Keep: In-app notification only
  5. AI/Summary Generation

    • Type: ai_conclusion_generated, summary_generated
    • Why: Background process, not urgent
    • Keep: In-app notification only
  6. System Events

    • Type: auto-resume-workflow
    • Why: System-triggered, covered by resume email
    • Keep: In-app notification only

🔄 Implementation Phases

Phase 1: Core Email Service (Week 1)

  • Create email.service.ts
  • Configure SMTP with nodemailer
  • Test email sending with test account
  • Add error handling and retry logic

Phase 2: Email Notification Service (Week 1-2)

  • Create emailNotification.service.ts
  • Implement all 12 template functions
  • Add data formatting helpers
  • Test with sample data

Phase 3: Critical Notifications (Week 2)

  • Integrate TAT Breached emails
  • Integrate Rejection emails
  • Test critical scenarios

Phase 4: High Priority Notifications (Week 2-3)

  • Integrate Request Created emails
  • Integrate Approval Request emails
  • Integrate Approval Confirmation emails
  • Integrate TAT Reminder emails
  • Integrate Workflow Resumed emails

Phase 5: Medium/Low Priority (Week 3)

  • Integrate Workflow Paused emails (conditional)
  • Integrate Participant Added emails (conditional)
  • Integrate Approver Skipped emails
  • Integrate Request Closed emails

Phase 6: Email Queue System (Week 4)

  • Install Bull/BullMQ
  • Create email queue
  • Implement priority-based sending
  • Add retry mechanism
  • Monitor email delivery

Phase 7: User Preferences (Week 4-5)

  • Add email preferences to user settings
  • Allow users to opt-in/out of certain emails
  • Keep critical emails always enabled
  • Add digest email option (daily summary)

⚙️ Environment Configuration

Add to .env:

# Email Service
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=notifications@royalenfield.com
SMTP_PASSWORD=your-app-specific-password
EMAIL_FROM=RE Flow <noreply@royalenfield.com>

# Email Settings
EMAIL_ENABLED=true
EMAIL_QUEUE_ENABLED=true
EMAIL_BATCH_SIZE=50
EMAIL_RETRY_ATTEMPTS=3

# Application
BASE_URL=https://workflow.royalenfield.com
COMPANY_NAME=Royal Enfield
COMPANY_WEBSITE=https://www.royalenfield.com
SUPPORT_EMAIL=support@royalenfield.com

📊 Expected Email Volume

Based on typical workflow usage:

Email Type Frequency Daily Volume (Est.)
Request Created Per new request 20-50
Approval Request Per assignment 20-50
Approval Confirmation Per approval 15-40
Rejection Occasional 2-5
TAT Reminder 80% threshold 5-15
TAT Breached Critical 1-5
Workflow Resumed Occasional 2-10
Request Closed Per closure 10-30
TOTAL 75-205 emails/day

No emails for @mentions, comments, documents (could be 100s per day).


Success Metrics

Email Delivery:

  • Delivery rate > 98%
  • Bounce rate < 2%
  • Open rate > 40% (approvers)
  • Click rate > 25% (View Details button)

User Experience:

  • Reduced missed approvals
  • Faster TAT completion
  • Better stakeholder awareness
  • No email fatigue (not too many emails)

🚀 Next Steps

  1. Review this plan - Confirm scenarios and priorities
  2. Configure SMTP - Set up email credentials
  3. Start with Phase 1 - Build email service
  4. Test thoroughly - Use test account first
  5. Roll out gradually - Start with critical emails only
  6. Monitor metrics - Track delivery and engagement
  7. Gather feedback - Adjust based on user preferences

Ready to start implementation? 🎯