Email Systems
The Volunteer Portal uses Campaign Monitor as its primary email service provider for sending transactional emails and notifications to volunteers, administrators, and restaurant managers.
Architecture Overview
Section titled “Architecture Overview”The email system consists of several key components:
- EmailService (
web/src/lib/email-service.ts) - Main service for sending emails via Campaign Monitor - Email Templates - Pre-configured smart email templates in Campaign Monitor
- Notification Service (
web/src/lib/notification-service.ts) - Handles email notifications for shift-related events
Configuration
Section titled “Configuration”Getting Access
Section titled “Getting Access”Before configuring the email system, ensure you have access to Campaign Monitor and other required services. See the Developer Access Guide for complete setup instructions.
Environment Variables
Section titled “Environment Variables”The email system requires several environment variables to be configured:
# Campaign Monitor API Configuration (get your API key from https://app.campaignmonitor.com/account/)CAMPAIGN_MONITOR_API_KEY="your-campaign-monitor-api-key"
# Smart Email Template IDs (create templates at https://app.campaignmonitor.com/transactional/)CAMPAIGN_MONITOR_MIGRATION_EMAIL_ID="migration-template-id"CAMPAIGN_MONITOR_SHIFT_ADMIN_CANCELLATION_EMAIL_ID="admin-cancellation-template-id"CAMPAIGN_MONITOR_SHIFT_SHORTAGE_EMAIL_ID="shortage-template-id"CAMPAIGN_MONITOR_SHIFT_CONFIRMATION_EMAIL_ID="confirmation-template-id"CAMPAIGN_MONITOR_VOLUNTEER_CANCELLATION_EMAIL_ID="volunteer-cancellation-template-id"CAMPAIGN_MONITOR_EMAIL_VERIFICATION_ID="email-verification-template-id"CAMPAIGN_MONITOR_PARENTAL_CONSENT_APPROVAL_EMAIL_ID="parental-consent-template-id"CAMPAIGN_MONITOR_USER_INVITATION_EMAIL_ID="user-invitation-template-id"
# Base URL for links in emailsNEXTAUTH_URL="https://your-domain.com"Development Mode
Section titled “Development Mode”In development, when Campaign Monitor credentials are not configured:
- Emails are logged to the console instead of being sent
- The system gracefully degrades without throwing errors
- This allows local development without requiring Campaign Monitor setup
Email Types
Section titled “Email Types”All email templates are configured as Campaign Monitor Smart Email Templates, which allow for dynamic content and personalization.
1. Migration Invitation (CAMPAIGN_MONITOR_MIGRATION_EMAIL_ID)
Section titled “1. Migration Invitation (CAMPAIGN_MONITOR_MIGRATION_EMAIL_ID)”Sent to volunteers during data migration from legacy systems.
Data Fields:
firstName- Recipient’s first namelink- Migration link for account setup
2. Shift Confirmation (CAMPAIGN_MONITOR_SHIFT_CONFIRMATION_EMAIL_ID)
Section titled “2. Shift Confirmation (CAMPAIGN_MONITOR_SHIFT_CONFIRMATION_EMAIL_ID)”Sent when a volunteer successfully signs up for a shift.
Data Fields:
firstName- Volunteer’s first namerole- Shift role/type nameshiftDate- Formatted date (e.g., “Monday, January 15, 2024”)shiftTime- Time range (e.g., “6:00 PM - 9:00 PM”)location- Restaurant/venue locationlinkToShift- Direct link to shift detailsaddToGoogleCalendarLink- Google Calendar add linkaddToOutlookCalendarLink- Outlook Calendar add linkaddToCalendarIcsLink- ICS file download linklocationMapLink- Google Maps link to location
3. Shift Cancellation - Manager (CAMPAIGN_MONITOR_SHIFT_ADMIN_CANCELLATION_EMAIL_ID)
Section titled “3. Shift Cancellation - Manager (CAMPAIGN_MONITOR_SHIFT_ADMIN_CANCELLATION_EMAIL_ID)”Sent to restaurant managers when a volunteer cancels their shift.
Data Fields:
managerName- Manager’s namevolunteerName- Name of volunteer who cancelledvolunteerEmail- Volunteer’s email addressshiftName- Shift type nameshiftDate- Formatted dateshiftTime- Time rangelocation- Restaurant locationcancellationTime- When the cancellation occurredremainingVolunteers- Number of volunteers still assignedshiftCapacity- Total capacity needed for the shift
4. Volunteer Cancellation (CAMPAIGN_MONITOR_VOLUNTEER_CANCELLATION_EMAIL_ID)
Section titled “4. Volunteer Cancellation (CAMPAIGN_MONITOR_VOLUNTEER_CANCELLATION_EMAIL_ID)”Sent to volunteers confirming their shift cancellation.
Data Fields:
firstName- Volunteer’s first nameshiftType- Name of the shift typeshiftDate- Formatted dateshiftTime- Time rangelocation- Restaurant locationbrowseShiftsLink- Link to browse available shifts
5. Shift Shortage (CAMPAIGN_MONITOR_SHIFT_SHORTAGE_EMAIL_ID)
Section titled “5. Shift Shortage (CAMPAIGN_MONITOR_SHIFT_SHORTAGE_EMAIL_ID)”Sent to eligible volunteers when a shift needs more volunteers.
Data Fields:
firstName- Volunteer’s first nameshiftType- Name of the shift typeshiftDate- Formatted daterestarauntLocation- Restaurant locationlinkToEvent- Direct link to the shift signup
6. Email Verification (CAMPAIGN_MONITOR_EMAIL_VERIFICATION_ID)
Section titled “6. Email Verification (CAMPAIGN_MONITOR_EMAIL_VERIFICATION_ID)”Sent to new users to verify their email address.
Data Fields:
firstName- User’s first nameverificationLink- Link to verify email address
7. Parental Consent Approval (CAMPAIGN_MONITOR_PARENTAL_CONSENT_APPROVAL_EMAIL_ID)
Section titled “7. Parental Consent Approval (CAMPAIGN_MONITOR_PARENTAL_CONSENT_APPROVAL_EMAIL_ID)”Sent when parental consent is approved for underage volunteers.
Data Fields:
firstName- Volunteer’s first namelinkToDashboard- Link to volunteer dashboard
8. User Invitation (CAMPAIGN_MONITOR_USER_INVITATION_EMAIL_ID)
Section titled “8. User Invitation (CAMPAIGN_MONITOR_USER_INVITATION_EMAIL_ID)”Sent when administrators invite new users to join the volunteer portal.
Data Fields:
firstName- User’s first nameemail- User’s email addressinvitationUrl- Link to complete registrationorganizationName- Name of the organization (Everybody Eats)
Usage Examples
Section titled “Usage Examples”Sending a Shift Confirmation Email
Section titled “Sending a Shift Confirmation Email”import { getEmailService } from "@/lib/email-service";
const emailService = getEmailService();
await emailService.sendShiftConfirmationNotification({ to: volunteer.email, volunteerName: `${volunteer.firstName} ${volunteer.lastName}`, shiftName: shift.shiftType.name, shiftDate: "Monday, January 15, 2024", shiftTime: "6:00 PM - 9:00 PM", location: shift.location, shiftId: shift.id, shiftStart: shift.start, shiftEnd: shift.end,});Sending a User Invitation Email
Section titled “Sending a User Invitation Email”import { getEmailService } from "@/lib/email-service";
const emailService = getEmailService();
await emailService.sendUserInvitation({ to: newUser.email, firstName: newUser.firstName, email: newUser.email, invitationUrl: `${process.env.NEXTAUTH_URL}/register?token=${invitationToken}`, organizationName: "Everybody Eats",});Sending Shortage Notifications
Section titled “Sending Shortage Notifications”// This is typically called from an admin API routeimport { getEmailService } from "@/lib/email-service";
const emailService = getEmailService();
await emailService.sendShiftShortageNotification({ to: volunteer.email, volunteerName: volunteer.name, shiftName: shift.shiftType.name, shiftDate: "Monday, January 15, 2024", shiftTime: "6:00 PM - 9:00 PM", location: shift.location, currentVolunteers: 2, neededVolunteers: 5, shiftId: shift.id,});Error Handling
Section titled “Error Handling”The email service implements robust error handling:
- Development Mode: Emails are logged to console instead of sent
- Missing Configuration: Graceful degradation with warning logs
- API Failures: Errors are logged but don’t crash the application
- Retry Logic: Not implemented - relies on Campaign Monitor’s reliability
Example Error Handling Pattern
Section titled “Example Error Handling Pattern”try { await emailService.sendShiftConfirmationNotification(params); console.log("Email sent successfully");} catch (error) { if (process.env.NODE_ENV === "development") { console.warn("Email sending failed in development (this is OK):", error); } else { console.error("Failed to send email:", error); // Don't throw - continue with other operations }}Integration Points
Section titled “Integration Points”API Routes
Section titled “API Routes”Email sending is integrated into various API routes:
/api/admin/notifications/send-shortage- Sends shortage notifications/api/auth/resend-verification- Resends email verification/api/admin/users/invite- Sends user invitations
Notification Service
Section titled “Notification Service”The NotificationService coordinates email notifications with in-app notifications:
// Send both email and in-app notificationawait this.emailService.sendShiftCancellationNotification(emailParams);await this.createInAppNotification(notificationParams);Calendar Integration
Section titled “Calendar Integration”Shift confirmation emails include calendar integration:
- Google Calendar “Add to Calendar” links
- Outlook Calendar integration
- ICS file downloads for other calendar applications
Best Practices
Section titled “Best Practices”- Always handle email failures gracefully - Don’t let email failures break core functionality
- Use meaningful template data - Provide all required fields for templates
- Test in development - Use console logging to verify email content
- Monitor email delivery - Check Campaign Monitor analytics for delivery rates
- Respect user preferences - Check notification preferences before sending
Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”For additional help, consult the Campaign Monitor Help Center or API Documentation.
Emails not sending in production:
- Verify
CAMPAIGN_MONITOR_API_KEYis set (get from Account Settings) - Check that all template IDs are configured
- Review Campaign Monitor dashboard for delivery status
Template errors:
- Ensure all required data fields are provided
- Verify template IDs match your Campaign Monitor templates
- Check template syntax in the Campaign Monitor template editor
Development setup:
- Emails should log to console when credentials aren’t configured
- Check server logs for email content
- Verify
NEXTAUTH_URLis set for correct links
Link generation issues:
- Ensure
NEXTAUTH_URLenvironment variable is set - Check that shift IDs and other parameters are valid
- Verify calendar URL generation is working