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
- Kubernetes cluster with kubectl access
- Docker registry access for container images
- Database secrets configured in Kubernetes
- Email service running and accessible
- 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
- Message Creation: When a message is created, it's tracked in the database with creation timestamp
- Age Calculation: The reminder job calculates message age based on creation time
- Eligibility Check: Messages older than
checkafterhours
and with fewer thanmaxreminders
sent are eligible - Reminder Dispatch: Eligible messages trigger email notifications via RabbitMQ
- Tracking Update: Reminder count is incremented and last reminder time is recorded
- 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:
[email protected]
→u***[email protected]
- Protects recipient privacy in application logs
- Full email addresses only used for actual email delivery
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:
- Check
reminder.enabled
istrue
- Verify messages are older than
checkafterhours
- Confirm email service is running and connected to RabbitMQ
- Check reminder count hasn't exceeded
maxreminders
Reminders sent too frequently:
- Verify
reminderinterval
setting - Check CronJob schedule frequency
- Review message timestamps in database
Configuration not loading:
- Verify environment variable names (must include
PASSWORDEXCHANGE_REMINDER_
prefix) - Check config file format and path
- Validate CLI flag syntax
- 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
- Environment Variables - Complete environment variable reference
- Containers - Container deployment guide
- Encryption - Security and encryption details