Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Encore Health OS supports email delivery for in-app notifications, allowing users to receive important updates directly in their inbox. Emails are sent via the org-configured provider: Microsoft Entra ID (Graph API) or Gmail (Google Workspace).

Configuration

Prerequisites

  • Entra: Configure in Settings → Integrations → Microsoft Entra ID; set ENTRA_CLIENT_SECRET in Supabase secrets.
  • Gmail: Set GMAIL_SERVICE_ACCOUNT_JSON in Supabase secrets; set sender email in Settings → Integrations → Google Workspace (Gmail).
  • Per-org provider choice in HR → Settings → Email (Entra or Gmail).

Email Provider

The platform uses the shared email-provider abstraction (Entra or Gmail):
  • Professional HTML templates
  • Delivery tracking
  • Bounce and failure handling
  • Variable substitution

Email Template Types

Standard Notifications

Basic notifications with auto-generated template wrapper. Used for simple alerts and updates.

Scheduled Report Emails

Professional branded templates for automated report delivery with:
  • Branded Encore Health OS header with gradient
  • Report details card (name, description)
  • Statistics row (generated date, row count, format, file size)
  • Prominent download button with signed URL
  • Next scheduled run indicator
  • Responsive design for mobile

Report Failure Emails

Error notification template for when scheduled reports fail:
  • Red accent error header
  • Error details card with message
  • Troubleshooting suggestions
  • Link to reports page

Localization Support

Email templates support localization via the locale parameter:

Supported Locales

  • en - English (default)
  • es - Spanish (coming soon)
  • fr - French (coming soon)

Adding New Locales

  1. Create locale file: supabase/functions/_shared/email-templates/locales/{locale}.ts
  2. Export translations matching ReportDeliveryStrings and ReportFailedStrings interfaces
  3. Add locale to Locale type in types.ts
  4. Import and add to locale maps in template files

Translation Keys

interface ReportDeliveryStrings {
  greeting: string;           // "Hello {{name}},"
  subject: string;            // "📊 Scheduled Report: {{report_name}}"
  reportReady: string;        // "Your scheduled report is ready"
  downloadButton: string;     // "Download Report"
  linkExpiry: string;         // "Link expires in {{days}} days"
  nextRun: string;            // "Next scheduled run: {{date}}"
  // ... more keys
}
⚠️ Security Note: All template variable values ({{name}}, {{report_name}}, etc.) must be escaped using escapeHtml() from _shared/email-templates/utils.ts before interpolation to prevent XSS attacks in rendered emails.

Features

Automatic Email Delivery

Notifications with channel='email' are automatically sent via the send-email-notification edge function.

Pre-Rendered HTML Support

For complex templates like scheduled reports, you can provide pre-rendered HTML:
await supabase.functions.invoke('send-email-notification', {
  body: {
    notificationId,
    recipientEmail: 'user@example.com',
    recipientName: 'John',
    subject: 'Your Report',
    body: '', // Not used when skipTemplate is true
    html: preRenderedHtml,
    skipTemplate: true,
  },
});

Template Variables

Emails support variable substitution using {{variable}} syntax:
  • {{user.name}} - Recipient’s name
  • {{org.name}} - Organization name
  • {{action.url}} - Action link
  • Custom variables per notification type

Delivery Tracking

All emails track:
  • Sent - Successfully delivered via org provider (Entra or Gmail)
  • Delivered - Confirmed received by recipient
  • Bounced - Email address invalid or rejected
  • Failed - Delivery error occurred

Usage

Sending Standard Email Notifications

import { supabase } from '@/integrations/supabase/client';

await supabase.from('pf_notifications').insert({
  user_id: userId,
  organization_id: orgId,
  title: 'Document Approved',
  body: 'Your document "{{document.name}}" has been approved.',
  type: 'document_approval',
  channel: 'email',
  action_url: '/documents/123',
});

Using Report Email Templates

import { 
  renderReportDeliveryEmail, 
  getReportDeliverySubject 
} from '../_shared/email-templates/index.ts';

const emailHtml = renderReportDeliveryEmail({
  recipientName: 'John',
  reportName: 'Monthly Revenue',
  reportDescription: 'Revenue summary by department',
  generatedAt: new Date(),
  rowCount: 1500,
  format: 'csv',
  fileSizeBytes: 45000,
  downloadUrl: signedUrl,
  expiryDays: 7,
  nextRunAt: new Date('2026-02-01'),
  organizationName: 'Acme Corp',
  locale: 'en',
});

const subject = getReportDeliverySubject('Monthly Revenue', 'en');

Checking Delivery Status

import { useNotificationDelivery } from '@/platform/notifications/hooks/useNotificationDelivery';

function NotificationRow({ notificationId }) {
  const { data: delivery } = useNotificationDelivery(notificationId);
  
  return (
    <div>
      Status: {delivery?.delivery_status}
      {delivery?.delivered_at && `Delivered at: ${delivery.delivered_at}`}
      {delivery?.delivery_error && `Error: ${delivery.delivery_error}`}
    </div>
  );
}

UI Component

import { NotificationDeliveryStatus } from '@/platform/notifications/components/NotificationDeliveryStatus';

<NotificationDeliveryStatus notificationId={notification.id} />

Email Template Architecture

supabase/functions/_shared/email-templates/
├── index.ts              # Exports all templates and utilities
├── base-layout.ts        # Shared HTML layout (header, footer, styles)
├── report-delivery.ts    # Scheduled report delivery template
├── report-failed.ts      # Report failure notification template
└── locales/
    ├── types.ts          # Translation key type definitions
    └── en.ts             # English translations

Template Features

Base Layout (base-layout.ts)

  • Responsive design (max-width 600px)
  • Branded header with Encore Health OS gradient
  • Dark mode ready with prefers-color-scheme meta
  • Consistent footer with preferences link
  • Utility functions: interpolate(), formatBytes(), formatDate()

Report Delivery Template

  • Personalized greeting
  • Report details card
  • Stats row with 4 columns
  • Large download CTA button
  • Column summary (optional)
  • Next run indicator
  • Auto-generated notice

Report Failed Template

  • Error-state red header
  • Error details card with message
  • Suggestion box with troubleshooting tips
  • View Reports button

Best Practices

  1. Use Clear Subjects: Keep subject lines under 50 characters
  2. Provide Context: Include relevant details in the body
  3. Add Action URLs: Always link to the relevant page
  4. Test Variables: Ensure all variables are defined before sending
  5. Monitor Bounces: Review bounced emails and update user profiles
  6. Use Pre-Rendered HTML: For complex templates, use skipTemplate: true

Error Handling

Failed emails are automatically logged with:
  • Error message stored in delivery_error
  • Status set to 'failed'
  • Notification remains viewable in-app
Common errors:
  • Invalid email address → Update user profile
  • Rate limit exceeded → Emails queued automatically
  • Auth/API error → Check Entra or Gmail configuration (Settings → Integrations)

Rate Limits

Provider rate limits:
  • Free tier: 100 emails/day
  • Paid tier: Custom limits
Batch sending automatically respects rate limits with exponential backoff.

Testing

Development Testing

Test email delivery:
  1. Configure Entra or Gmail per org (Settings → Integrations)
  2. In HR → Settings → Email, use “Send Test Email” to verify

Production Testing

  1. Verify sender identity (Entra mailbox or Gmail/Workspace user)
  2. Update from address in edge function
  3. Test with real email addresses
  4. Monitor delivery in Supabase logs and provider dashboards

Troubleshooting

Emails Not Sending

  1. Check Entra or Gmail secrets and org config (Settings → Integrations)
  2. Verify edge function deployed successfully
  3. Check notification has channel='email'
  4. Review edge function logs

Emails Bouncing

  1. Verify email address format (must be valid)
  2. Check recipient’s email server isn’t blocking
  3. Confirm sender domain is verified (production)
  4. Review function logs and provider dashboards for bounce/failure reasons

Variables Not Replacing

  1. Ensure variables use {{key}} format
  2. Verify variable data is provided in notification
  3. Check for typos in variable names
  4. Test with simple variables first

Pre-Rendered HTML Not Working

  1. Ensure skipTemplate: true is set
  2. Verify html field contains valid HTML
  3. Check that body field is empty string (not undefined)