# Newsletter Integration (Listmonk) The Newsletter Integration provides automated synchronization between Changemaker Lite and Listmonk newsletter platform. Campaign participants, volunteers, and locations can be automatically synced to Listmonk lists for targeted email campaigns. ## Overview The Listmonk integration provides: - **Opt-in Sync** - Controlled by `LISTMONK_SYNC_ENABLED` flag - **Automatic Subscriber Creation** - Campaign participants → subscribers - **List Management** - Campaigns → lists, Locations → lists - **User Role Sync** - User roles → list assignment - **Bi-directional Updates** - Keep data synchronized - **Admin Interface** - Manual sync controls and monitoring ## Features ### Subscriber Sync Automatically sync users to Listmonk: - **Campaign Participants** - Email senders become subscribers - **Shift Signups** - Volunteers added to lists - **Response Submitters** - Response wall participants - **Manual Users** - User role-based list assignment ### List Management Auto-create and manage lists: - **Campaign Lists** - One list per campaign - **Location Lists** - One list per geographic area - **Role Lists** - Lists for each user role - **Custom Lists** - Admin-defined lists ### Sync Triggers Automatic sync on: - Campaign email sent - Shift signup - Response submission - User registration - Manual admin trigger ### Admin Controls - View sync status - Manual sync buttons - Test connection - List statistics - Reinitialize lists ## Architecture ### Backend Components **Listmonk Client:** - `api/src/services/listmonk.client.ts` - Typed HTTP client (native fetch) - Basic auth integration - Full REST API coverage **Listmonk Sync Service:** - `api/src/services/listmonk-sync.service.ts` - Sync orchestration - Participant → subscriber mapping - List creation and management - Error handling and logging **Admin Module:** - `api/src/modules/listmonk/listmonk.routes.ts` - Admin endpoints - Status, stats, sync controls **Database:** - No new tables (uses existing User, Campaign, Location) - Listmonk IDs stored in Prisma models (future) ### Frontend Components **Admin Page:** - `admin/src/pages/ListmonkPage.tsx` - Newsletter management - Connection status display - Sync controls - List statistics table ## Configuration ### Environment Variables ```bash # Enable Listmonk sync (opt-in) LISTMONK_SYNC_ENABLED=true # Listmonk connection LISTMONK_API_URL=http://listmonk:9000 LISTMONK_API_USER=api_user LISTMONK_API_TOKEN=your_api_token # Web admin credentials (for setup) LISTMONK_WEB_ADMIN_USER=admin LISTMONK_WEB_ADMIN_PASSWORD=password ``` ### Docker Setup Listmonk runs as a service in `docker-compose.yml`: ```yaml listmonk: image: listmonk/listmonk:latest ports: - "9001:9000" depends_on: - listmonk-db environment: LISTMONK_app__admin_username: ${LISTMONK_WEB_ADMIN_USER} LISTMONK_app__admin_password: ${LISTMONK_WEB_ADMIN_PASSWORD} ``` ### Initialization Auto-create API user via `listmonk-init` container: ```sql INSERT INTO users (email, name, password, type, status, created_at, updated_at) VALUES ( '${LISTMONK_API_USER}', 'API User', '${LISTMONK_API_TOKEN}', -- Plaintext (Listmonk API tokens) 'api', 'enabled', NOW(), NOW() ); ``` ## Sync Process ### Campaign Participant Sync 1. **Email Sent** - Campaign email sent via API 2. **Create Subscriber** - POST `/api/subscribers` - Email, name from user - Status: `enabled` 3. **Get/Create List** - GET/POST `/api/lists` - List name: Campaign name - Type: `public` or `private` 4. **Subscribe to List** - PUT `/api/subscribers/:id/lists` - Add subscriber to campaign list ### Location Sync 1. **Location Created** - New location added 2. **Get/Create List** - List name: Location name/city 3. **Sync Users** - All users in location → list ### User Role Sync 1. **User Registration** - New user account 2. **Get Role List** - `SUPER_ADMIN`, `INFLUENCE_ADMIN`, etc. 3. **Subscribe User** - Add to role-based list ## API Integration ### Listmonk Client Usage ```typescript import { listmonkClient } from '../services/listmonk.client'; // Create subscriber const subscriber = await listmonkClient.createSubscriber({ email: 'user@example.com', name: 'User Name', status: 'enabled', lists: [listId], }); // Get/Create list let list = await listmonkClient.getListByName('Campaign Name'); if (!list) { list = await listmonkClient.createList({ name: 'Campaign Name', type: 'public', optin: 'double', }); } // Subscribe to list await listmonkClient.subscribeToList(subscriberId, [listId]); ``` ### Sync Service Usage ```typescript import { listmonkSyncService } from '../services/listmonk-sync.service'; // Sync campaign participant await listmonkSyncService.syncCampaignParticipant( campaign.id, user.email, user.name ); // Sync all participants await listmonkSyncService.syncAllParticipants(campaign.id); // Sync location members await listmonkSyncService.syncLocationMembers(location.id); ``` ## Admin Interface ### Connection Status Display: - Connected/disconnected status - Listmonk version - API endpoint - Last sync time ### Sync Controls Buttons: - **Sync All Participants** - Sync all campaign participants - **Sync All Locations** - Sync all location members - **Test Connection** - Verify API access - **Reinitialize** - Reset lists and subscribers ### List Statistics Table showing: - List name - Subscriber count - Campaign/location association - Last updated time ## Security ### API Authentication Listmonk v6+ requires auth on all endpoints: ```typescript const headers = { 'Authorization': `Basic ${btoa(`${apiUser}:${apiToken}`)}`, 'Content-Type': 'application/json', }; ``` ### Token Storage API tokens stored as plaintext in Listmonk DB: - Not bcrypt hashed - Direct upsert possible - Secure via Redis authentication ### Data Privacy - Opt-in sync only - User consent required (future) - Unsubscribe support - Data deletion on request ## Error Handling ### Sync Failures Handled gracefully: - Network errors logged - Failed syncs retried - Admin notifications - Error statistics ### Rate Limiting Respect Listmonk limits: - Batch operations - Delay between requests - Queue large syncs ## Listmonk Features ### Campaign Management Listmonk provides: - Email campaign creation - Template management - Scheduling - A/B testing - Analytics ### Subscriber Management - Import/export subscribers - List segmentation - Tags and attributes - Bounce handling - Unsubscribe management ### Analytics - Open rates - Click rates - Bounce rates - Unsubscribe rates - Campaign reports ## API Endpoints ### Admin Endpoints ``` GET /api/listmonk/status # Connection status GET /api/listmonk/stats # Sync statistics POST /api/listmonk/sync-participants # Sync campaign participants POST /api/listmonk/sync-locations # Sync location members POST /api/listmonk/test-connection # Test API connection POST /api/listmonk/reinitialize # Reset and reinitialize ``` ## Limitations ### Current Limitations - Listmonk v6+ only (auth required on all endpoints) - No webhook support (future) - Manual sync triggers - No bi-directional sync (Listmonk → CM Lite) ### Future Enhancements - Webhook integration - Real-time sync - Custom field mapping - Advanced segmentation - Campaign stats in CM Lite ## Troubleshooting ### Connection Issues 1. Check `LISTMONK_SYNC_ENABLED=true` 2. Verify `LISTMONK_API_URL` reachable 3. Confirm API user created 4. Test credentials with curl ### Sync Failures 1. Check logs for errors 2. Verify Listmonk database 3. Test API connection 4. Reinitialize if needed ## Related Documentation - [Listmonk Page](../../frontend/pages/admin/listmonk-page.md) - [Listmonk Client](../../backend/services/index.md) - [Campaign Module](../../backend/modules/campaigns.md) - [Environment Variables](../../deployment/environment-variables.md) - [Docker Compose](../../deployment/docker-compose.md)