Email Reminder Configuration - Anthony-Bible/password-exchange GitHub Wiki

Email Reminder Configuration

The reminder system automatically sends email notifications for unviewed messages, helping ensure important passwords and sensitive information aren't forgotten.

Overview

When a message is created but remains unviewed, the reminder system can automatically send email notifications to the recipient at configurable intervals. This feature is particularly useful for:

  • Critical passwords that need immediate attention
  • Time-sensitive information that shouldn't be forgotten
  • Ensuring important messages don't expire unnoticed

Configuration Options

Core Settings

Setting Environment Variable CLI Flag Description Default Valid Range
enabled PASSWORDEXCHANGE_REMINDER_ENABLED N/A Enable/disable reminder system true true/false
checkafterhours PASSWORDEXCHANGE_REMINDER_CHECKAFTERHOURS --older-than-hours Hours to wait before first reminder 24 1-8760 (1 hour to 1 year)
maxreminders PASSWORDEXCHANGE_REMINDER_MAXREMINDERS --max-reminders Maximum reminders per message 3 1-10
reminderinterval PASSWORDEXCHANGE_REMINDER_REMINDERINTERVAL N/A Hours between subsequent reminders 24 1-720 (1 hour to 30 days)

Default Values & Validation

Default Value Behavior:

  • All reminder settings have sensible defaults that will be applied automatically
  • If a setting is not provided or set to zero, the default value will be used
  • If a setting is outside the valid range, it will be reset to the default value
  • This ensures the reminder system always operates with valid configuration

Validation Rules:

  • checkafterhours: Must be between 1 and 8760 hours (1 hour to 1 year)
  • maxreminders: Must be between 1 and 10 reminders per message
  • reminderinterval: Must be between 1 and 720 hours (1 hour to 30 days)

Default Values Applied When:

  • Configuration value is missing or zero
  • Configuration value is outside valid range
  • Environment variable is not set
  • Configuration file doesn't specify the setting

Configuration Methods

1. Configuration File

Add to your config.yaml:

reminder:
  enabled: true
  checkafterhours: 24    # Send first reminder after 24 hours
  maxreminders: 3        # Send up to 3 reminders total
  reminderinterval: 24   # Wait 24 hours between reminders

2. Environment Variables

Set environment variables with the PASSWORDEXCHANGE_REMINDER_ prefix:

export PASSWORDEXCHANGE_REMINDER_ENABLED=true
export PASSWORDEXCHANGE_REMINDER_CHECKAFTERHOURS=24
export PASSWORDEXCHANGE_REMINDER_MAXREMINDERS=3
export PASSWORDEXCHANGE_REMINDER_REMINDERINTERVAL=24

3. CLI Flags

Override configuration when running manually:

# Run with custom settings
./app reminder --config=config.yaml --older-than-hours=48 --max-reminders=5

# Dry run to see what would happen
./app reminder --config=config.yaml --dry-run

# Use configuration file defaults
./app reminder --config=config.yaml

Usage Examples

Development/Testing

# Quick test - check messages older than 1 hour, max 1 reminder
./app reminder --older-than-hours=1 --max-reminders=1 --dry-run

# Send reminder for very old messages
./app reminder --older-than-hours=168 --max-reminders=1  # 1 week old

Production Scenarios

# Conservative: Wait 2 days, send max 2 reminders
export PASSWORDEXCHANGE_REMINDER_CHECKAFTERHOURS=48
export PASSWORDEXCHANGE_REMINDER_MAXREMINDERS=2

# Aggressive: Wait 8 hours, send up to 5 reminders  
export PASSWORDEXCHANGE_REMINDER_CHECKAFTERHOURS=8
export PASSWORDEXCHANGE_REMINDER_MAXREMINDERS=5
export PASSWORDEXCHANGE_REMINDER_REMINDERINTERVAL=12  # Every 12 hours

Deployment

Kubernetes CronJob Deployment

Step 1: Deploy the CronJob

The reminder system is deployed as a Kubernetes CronJob that runs daily. Use the provided manifest in k8s/reminder-cronjob.yaml:

# Deploy the reminder CronJob
kubectl apply -f k8s/reminder-cronjob.yaml

# Verify deployment
kubectl get cronjobs
kubectl describe cronjob password-exchange-reminder

Step 2: Full CronJob Manifest

apiVersion: batch/v1
kind: CronJob
metadata:
  name: password-exchange-reminder
  namespace: default
  labels:
    app: password-exchange
    component: reminder
spec:
  # Run daily at 9:00 AM UTC
  schedule: "0 9 * * *"
  # Alternatively, run every 24 hours from first execution: "@every 24h"
  concurrencyPolicy: Forbid  # Don't allow overlapping jobs
  failedJobsHistoryLimit: 3
  successfulJobsHistoryLimit: 1
  startingDeadlineSeconds: 300  # Job must start within 5 minutes of scheduled time
  jobTemplate:
    spec:
      # Clean up completed jobs after 6 hours
      ttlSecondsAfterFinished: 21600
      template:
        metadata:
          labels:
            app: password-exchange
            component: reminder
        spec:
          restartPolicy: OnFailure
          containers:
          - name: reminder
            image: ${REGISTRY_URL}/${IMAGE_NAME}:${IMAGE_TAG}
            imagePullPolicy: Always
            command: ["/app/app"]
            args: ["reminder", "--config=/config/config.yaml"]
            env:
            # Database configuration (from secrets)
            - name: PASSWORDEXCHANGE_DBHOST
              valueFrom:
                secretKeyRef:
                  name: password-exchange-secrets
                  key: db-host
            - name: PASSWORDEXCHANGE_DBUSER
              valueFrom:
                secretKeyRef:
                  name: password-exchange-secrets
                  key: db-user
            - name: PASSWORDEXCHANGE_DBPASS
              valueFrom:
                secretKeyRef:
                  name: password-exchange-secrets
                  key: db-password
            - name: PASSWORDEXCHANGE_DBNAME
              valueFrom:
                secretKeyRef:
                  name: password-exchange-secrets
                  key: db-name
            # Reminder configuration
            - name: PASSWORDEXCHANGE_REMINDER_ENABLED
              value: "true"
            - name: PASSWORDEXCHANGE_REMINDER_CHECKAFTERHOURS
              value: "24"
            - name: PASSWORDEXCHANGE_REMINDER_MAXREMINDERS
              value: "3"
            - name: PASSWORDEXCHANGE_REMINDER_INTERVAL
              value: "24"
            # Logging
            - name: PASSWORDEXCHANGE_LOGLEVEL
              value: "info"
            volumeMounts:
            - name: config
              mountPath: /config
              readOnly: true
            resources:
              requests:
                memory: "64Mi"
                cpu: "50m"
              limits:
                memory: "128Mi"
                cpu: "100m"
          volumes:
          - name: config
            configMap:
              name: password-exchange-config
          # Use a service account with appropriate permissions
          serviceAccountName: password-exchange
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: password-exchange-config
  namespace: default
  labels:
    app: password-exchange
data:
  config.yaml: |
    # Minimal config for reminder service
    loglevel: info
    reminder:
      enabled: true
      checkafterhours: 24
      maxreminders: 3
      reminderinterval: 24

Step 3: Verify Deployment

# Check CronJob status
kubectl get cronjob password-exchange-reminder

# View recent jobs
kubectl get jobs -l app=password-exchange,component=reminder

# Check job logs
kubectl logs -l app=password-exchange,component=reminder

# Monitor next scheduled run
kubectl describe cronjob password-exchange-reminder | grep "Last Schedule"

Production Deployment Steps

Prerequisites

  1. Kubernetes cluster with kubectl access
  2. Docker registry access for container images
  3. Database secrets configured in Kubernetes
  4. Email service running and accessible
  5. RabbitMQ message queue deployed

Complete Deployment Process

# 1. Build and push container images
./test-build.sh  # Builds app and generates manifests

# 2. Update image variables in reminder-cronjob.yaml
export REGISTRY_URL="your-registry.com"
export IMAGE_NAME="password-exchange"
export IMAGE_TAG="latest"

# 3. Deploy database secrets (if not already deployed)
kubectl apply -f kubernetes/secrets.encrypted.yaml

# 4. Deploy the reminder CronJob
kubectl apply -f k8s/reminder-cronjob.yaml

# 5. Verify all components
kubectl get cronjobs,configmaps,secrets | grep password-exchange

# 6. Test manual execution (optional)
kubectl create job reminder-test --from=cronjob/password-exchange-reminder
kubectl logs -f job/reminder-test

Alternative Schedule Options

Customize the CronJob schedule in k8s/reminder-cronjob.yaml:

# Run every hour (for high-frequency reminders)
schedule: "0 * * * *"

# Run daily at 9 AM UTC (default)
schedule: "0 9 * * *"

# Run every 4 hours during business hours (9 AM to 5 PM UTC)
schedule: "0 9,13,17 * * *"

# Run every 6 hours
schedule: "0 */6 * * *"

# Run twice daily (9 AM and 9 PM UTC)
schedule: "0 9,21 * * *"

How It Works

Reminder Process Flow

  1. Message Creation: When a message is created, it's tracked in the database with creation timestamp
  2. Age Calculation: The reminder job calculates message age based on creation time
  3. Eligibility Check: Messages older than checkafterhours and with fewer than maxreminders sent are eligible
  4. Reminder Dispatch: Eligible messages trigger email notifications via RabbitMQ
  5. Tracking Update: Reminder count is incremented and last reminder time is recorded
  6. Repeat Cycle: Process repeats until message is viewed or maxreminders limit reached

Example Timeline

With default settings (checkafterhours: 24, maxreminders: 3, reminderinterval: 24):

  • Day 0: Message created at 10:00 AM
  • Day 1: First reminder sent at 10:00 AM (24 hours later)
  • Day 2: Second reminder sent at 10:00 AM (48 hours after creation)
  • Day 3: Third reminder sent at 10:00 AM (72 hours after creation)
  • Day 4+: No more reminders (reached max limit)
  • Day 7: Message expires automatically

Database Tracking

The system tracks:

  • Message creation timestamp
  • Number of reminders sent
  • Last reminder timestamp
  • Message view status
  • Expiration date

Security and Privacy

Email Sanitization

All email addresses are sanitized in logs for privacy:

Error Handling

  • Partial Failures: Individual message failures don't stop processing other messages
  • Circuit Breaker: Prevents cascading failures when external services are down
  • Retry Logic: Automatic retry with exponential backoff for transient failures
  • Graceful Degradation: System continues operating even if reminder service fails

Monitoring and Observability

Logging

The reminder service provides structured logging with:

  • Message processing counts
  • Error details with context
  • Performance metrics
  • Privacy-compliant email masking

Metrics

Key metrics to monitor:

  • Messages processed per run
  • Reminders sent successfully
  • Error rates and types
  • Processing duration
  • Queue backlog (if using RabbitMQ)

Health Checks

Monitor reminder system health by checking:

  • CronJob execution status in Kubernetes
  • Database connectivity
  • Email service availability
  • Configuration validation

Troubleshooting

Common Issues

No reminders being sent:

  1. Check reminder.enabled is true
  2. Verify messages are older than checkafterhours
  3. Confirm email service is running and connected to RabbitMQ
  4. Check reminder count hasn't exceeded maxreminders

Reminders sent too frequently:

  1. Verify reminderinterval setting
  2. Check CronJob schedule frequency
  3. Review message timestamps in database

Configuration not loading:

  1. Verify environment variable names (must include PASSWORDEXCHANGE_REMINDER_ prefix)
  2. Check config file format and path
  3. Validate CLI flag syntax
  4. Review application logs for configuration errors

Debug Commands

# Test configuration loading
./app reminder --config=config.yaml --dry-run

# Check specific message
./app reminder --older-than-hours=1 --max-reminders=10 --dry-run

# Enable debug logging
PASSWORDEXCHANGE_LOG_LEVEL=debug ./app reminder --config=config.yaml

Best Practices

Configuration Recommendations

  • Development: Short intervals for testing (checkafterhours: 1, reminderinterval: 1)
  • Production: Conservative settings (checkafterhours: 24, maxreminders: 3)
  • High-priority systems: More aggressive reminders (checkafterhours: 8, maxreminders: 5)

Deployment Guidelines

Resource Management

  • Memory: 64Mi request, 128Mi limit (handles typical workloads)
  • CPU: 50m request, 100m limit (sufficient for batch processing)
  • Job History: Keep 1 successful, 3 failed jobs for debugging
  • Cleanup: Jobs auto-delete after 6 hours (ttlSecondsAfterFinished)

Scheduling Best Practices

  • Production: Daily at consistent time (9 AM UTC recommended)
  • Development: Every 6 hours for testing (0 */6 * * *)
  • High-priority: Every 4 hours during business hours
  • Concurrency: Forbid prevents overlapping executions

Monitoring and Alerts

# Set up monitoring for:
kubectl get cronjob password-exchange-reminder -o jsonpath='{.status.lastScheduleTime}'
kubectl get jobs -l component=reminder --sort-by=.metadata.creationTimestamp

# Alert on job failures:
kubectl get jobs -l component=reminder -o jsonpath='{.items[*].status.failed}'

Troubleshooting Deployment Issues

  • ImagePullBackOff: Verify registry access and image tags
  • ConfigMap missing: Ensure password-exchange-config exists
  • Secret errors: Check password-exchange-secrets deployment
  • Permission denied: Verify password-exchange service account

Email Considerations

  • Ensure email service has sufficient capacity for reminder volume
  • Consider rate limiting to prevent overwhelming email servers
  • Test email deliverability in your environment
  • Monitor for bounce rates and spam filtering

Related Documentation