Skip to content

Email and SMTP Issues

This guide covers email sending, SMTP configuration, and template-related problems in Changemaker Lite V2.

Overview

Email System Architecture

Changemaker Lite V2 has dual email systems:

  1. Transactional Emails (BullMQ + Nodemailer)
  2. Campaign advocacy emails
  3. Shift confirmation emails
  4. Response verification emails
  5. System notifications

  6. Newsletter Emails (Listmonk)

  7. Marketing campaigns
  8. Newsletter broadcasts
  9. Subscriber management

Email Flow

User Action → Email Service → BullMQ Queue → Worker → SMTP Server → Recipient

Key Components

  • BullMQ - Job queue for async email sending
  • Nodemailer - SMTP client library
  • Redis - Queue backend
  • MailHog - Development email capture (test mode)
  • Listmonk - Newsletter platform (optional)

SMTP Configuration

Connection Refused

Severity: 🔴 Critical

Symptoms

API logs:

Error: Connection timeout
Error: connect ECONNREFUSED smtp.gmail.com:587
Error: Invalid login: 535-5.7.8 Username and Password not accepted

Emails not sending.

Common Causes

  1. Wrong SMTP host - Incorrect hostname
  2. Port blocked - Firewall blocking port 587/465
  3. Wrong credentials - Invalid username/password
  4. TLS/SSL mismatch - Wrong secure setting

Solutions

Solution 1: Test SMTP connection

# Test with telnet
telnet smtp.gmail.com 587

# Should show:
# 220 smtp.gmail.com ESMTP ...

# Or test with openssl (for SSL)
openssl s_client -connect smtp.gmail.com:465

Solution 2: Verify SMTP configuration

In .env:

# Gmail example (requires app password)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false  # false for STARTTLS on 587, true for SSL on 465
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password  # NOT regular password
SMTP_FROM=your-email@gmail.com

# Office365 example
SMTP_HOST=smtp.office365.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-email@outlook.com
SMTP_PASS=your-password
SMTP_FROM=your-email@outlook.com

# SendGrid example
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=apikey  # Literally "apikey"
SMTP_PASS=your-sendgrid-api-key
SMTP_FROM=your-verified-sender@example.com

Solution 3: Use test mode

# In .env
EMAIL_TEST_MODE=true

# Restart API
docker compose restart api

# All emails now sent to MailHog
# View at http://localhost:8025

Solution 4: Test email sending

# Send test email via API
curl -X POST http://localhost:4000/api/test-email \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{
    "to": "test@example.com",
    "subject": "Test Email",
    "text": "This is a test email from Changemaker Lite"
  }'

# Check API logs
docker compose logs api | grep -i "email\|smtp"

Solution 5: Gmail app password

For Gmail (required if 2FA enabled):

  1. Go to https://myaccount.google.com/apppasswords
  2. Select app: Mail
  3. Select device: Other (Changemaker Lite)
  4. Click Generate
  5. Copy 16-character password
  6. Use in SMTP_PASS (no spaces)

Prevention

  • Test mode for dev - Use MailHog locally
  • Secure credentials - Use app passwords, not real passwords
  • Environment-specific - Different SMTP per environment
  • Health checks - Test SMTP on API startup

Authentication Failed

Severity: 🔴 Critical

Symptoms

Error: Invalid login: 535-5.7.8 Username and Password not accepted
Error: 535 Authentication failed

Common Causes

  1. Wrong password - Incorrect password
  2. 2FA enabled - Need app password
  3. Less secure apps - Gmail blocking
  4. Account locked - Too many failed attempts

Solutions

Solution 1: Verify credentials

# Check .env
cat .env | grep SMTP_

# Test login manually (if possible)
# Gmail doesn't allow this, but some SMTP servers do

Solution 2: Enable less secure apps (Gmail)

⚠️ Not recommended. Use app password instead.

  1. Go to https://myaccount.google.com/lesssecureapps
  2. Turn on "Allow less secure apps"

Solution 3: Check account status

  1. Try logging into email account via web
  2. Check for security alerts
  3. Verify account not locked

Solution 4: Use OAuth2 (advanced)

For production Gmail:

// In email.service.ts
const transporter = nodemailer.createTransporter({
  service: 'gmail',
  auth: {
    type: 'OAuth2',
    user: process.env.SMTP_USER,
    clientId: process.env.GMAIL_CLIENT_ID,
    clientSecret: process.env.GMAIL_CLIENT_SECRET,
    refreshToken: process.env.GMAIL_REFRESH_TOKEN
  }
});

Prevention

  • App passwords - Always use app-specific passwords
  • Test credentials - Verify before deploying
  • Monitor failures - Alert on auth failures
  • Backup SMTP - Configure fallback SMTP server

Invalid Credentials

Severity: 🔴 Critical

Symptoms

Error: Invalid SMTP credentials
Error: Username and Password not accepted

Solutions

See "Authentication Failed" section above.


Port Blocked

Severity: 🟠 High

Symptoms

Error: connect ETIMEDOUT smtp.gmail.com:587
Error: Connection timeout

Connection attempt hangs, then times out after 30+ seconds.

Common Causes

  1. Firewall blocking - Network firewall blocking port
  2. ISP blocking - ISP blocks port 25/587
  3. Docker network - Container can't reach external SMTP

Solutions

Solution 1: Test port access

# From API container
docker compose exec api telnet smtp.gmail.com 587

# If timeout, port is blocked

Solution 2: Try alternative port

# Try port 465 (SSL) instead of 587 (STARTTLS)
SMTP_PORT=465
SMTP_SECURE=true

# Or try port 2525 (some providers)
SMTP_PORT=2525
SMTP_SECURE=false

Solution 3: Check Docker network

# Test external connectivity
docker compose exec api ping -c 3 smtp.gmail.com

# Test DNS resolution
docker compose exec api nslookup smtp.gmail.com

# If fails, Docker network issue

Solution 4: Use SMTP relay

If ISP blocks SMTP, use relay service: - SendGrid - Mailgun - Amazon SES - Postmark

Solution 5: VPN or proxy

As last resort, route SMTP through VPN/proxy.

Prevention

  • Use relay services - More reliable than direct SMTP
  • Multiple ports - Try 587, 465, 2525
  • Test on deploy - Verify SMTP works in production
  • Documentation - Document network requirements

Template Issues

Template Not Found

Severity: 🟠 High

Symptoms

API logs:

Error: Email template not found: campaign-email
Error: ENOENT: no such file or directory, open 'templates/campaign-email.html'

Common Causes

  1. Template file missing - File doesn't exist
  2. Wrong template name - Typo in name
  3. Wrong directory - Looking in wrong path
  4. Deleted template - Template was removed

Solutions

Solution 1: List available templates

# List template files
docker compose exec api ls -la templates/

# Should show:
# campaign-email.html
# shift-confirmation.html
# verification-email.html
# response-verification.html

Solution 2: Create missing template

# Create template file
docker compose exec api sh -c 'cat > templates/my-template.html << EOF
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>{{title}}</title>
</head>
<body>
  <h1>Hello {{name}}</h1>
  <p>{{message}}</p>
</body>
</html>
EOF'

Solution 3: Use email template system

Navigate to /app/email-templates:

  1. Click "Create Template"
  2. Fill in details
  3. Design template
  4. Save (creates file + DB record)

Solution 4: Check template name

// In code, template name must match filename (without .html)
await emailService.sendEmail({
  to: email,
  subject: 'Campaign Email',
  template: 'campaign-email',  // Looks for templates/campaign-email.html
  variables: { ... }
});

Solution 5: Verify template path

In api/src/services/email.service.ts:

const templatePath = path.join(__dirname, '../../templates', `${template}.html`);
// Resolves to: api/templates/campaign-email.html

Prevention

  • Seed templates - Include default templates in seed
  • Template management - Use admin UI to manage
  • Version control - Keep templates in git
  • Validation - Check template exists before sending

Variable Not Replaced

Severity: 🟡 Medium

Symptoms

Email received with unreplaced placeholders:

Hello {{name}},

Your campaign {{campaignName}} is ready.

Common Causes

  1. Variable not provided - Missing from variables object
  2. Typo in variable name - Mismatch between template and code
  3. Wrong delimiter - Using ${} instead of {{}}
  4. Escaping issue - HTML entities interfering

Solutions

Solution 1: List template variables

# Find all variables in template
docker compose exec api grep -o '{{[^}]*}}' templates/campaign-email.html

# Shows:
# {{name}}
# {{campaignName}}
# {{campaignUrl}}

Solution 2: Provide all variables

await emailService.sendEmail({
  to: email,
  subject: 'Campaign Ready',
  template: 'campaign-email',
  variables: {
    name: user.name,  // Must provide ALL variables in template
    campaignName: campaign.name,
    campaignUrl: `${process.env.PUBLIC_URL}/campaigns/${campaign.id}`
  }
});

Solution 3: Check variable delimiter

<!-- Correct (Handlebars-style) -->
<h1>Hello {{name}}</h1>
<p>Your campaign {{campaignName}} is ready.</p>

<!-- Wrong -->
<h1>Hello ${name}</h1>  <!-- JavaScript template literal -->
<p>Your campaign {campaignName} is ready.</p>  <!-- Single braces -->

Solution 4: Test template rendering

# Test template rendering
curl -X POST http://localhost:4000/api/test-template \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{
    "template": "campaign-email",
    "variables": {
      "name": "John",
      "campaignName": "Save the Planet",
      "campaignUrl": "https://example.com/campaigns/123"
    }
  }'

# Returns rendered HTML

Solution 5: Use default values

<!-- In template, provide fallback -->
<h1>Hello {{name || "Friend"}}</h1>

Or in code:

const variables = {
  name: user.name || 'Friend',
  campaignName: campaign.name || 'Campaign',
  campaignUrl: campaignUrl || '#'
};

Prevention

  • Template validation - Check all variables exist
  • TypeScript types - Type template variables
  • Default values - Always provide defaults
  • Testing - Test all templates with sample data

Syntax Errors

Severity: 🟠 High

Symptoms

Error: Parse error in template at line 15
Error: Unexpected token in template

Email fails to send.

Common Causes

  1. Invalid HTML - Malformed HTML
  2. Unclosed tags - Missing closing tags
  3. Special characters - Unescaped < > &
  4. Handlebars syntax - Invalid {{}} usage

Solutions

Solution 1: Validate HTML

# Use HTML validator
# Copy template content to https://validator.w3.org/nu/

# Or validate locally
docker compose exec api npx html-validate templates/campaign-email.html

Solution 2: Check common errors

<!-- Unclosed tag -->
<div>Content here
<!-- Should be: -->
<div>Content here</div>

<!-- Unescaped characters -->
Price: $50 < $100
<!-- Should be: -->
Price: $50 &lt; $100

<!-- Invalid Handlebars -->
{{if name}}  <!-- No "if" helper by default -->
<!-- Should be: -->
{{#if name}}...{{/if}}  <!-- Or don't use if -->

Solution 3: Escape HTML

// In email.service.ts
import handlebars from 'handlebars';

// Register escape helper
handlebars.registerHelper('escape', (str) => {
  return handlebars.escapeExpression(str);
});

// In template
<p>Message: {{escape message}}</p>

Solution 4: Test template compilation

// Test if template compiles
import handlebars from 'handlebars';
import fs from 'fs';

const templateSource = fs.readFileSync('templates/campaign-email.html', 'utf8');
try {
  const template = handlebars.compile(templateSource);
  console.log('Template compiles successfully');
} catch (error) {
  console.error('Template error:', error.message);
}

Prevention

  • HTML validation - Validate before saving
  • Linting - Use HTML linter in editor
  • Simple templates - Keep templates simple
  • Testing - Test rendering before deploying

Queue Issues

Queue Stuck

Severity: 🟠 High

Symptoms

Emails queued but not sending. Queue shows jobs but no progress.

Solutions

Solution 1: Check queue status

# View queue stats
curl http://localhost:4000/api/influence/email-queue/stats \
  -H "Authorization: Bearer YOUR_TOKEN"

# Shows:
# {
#   "waiting": 50,
#   "active": 0,  # Should be > 0 if processing
#   "completed": 1000,
#   "failed": 5
# }

Solution 2: Check worker is running

# Worker should log processing
docker compose logs api | grep -i "email worker\|processing email"

# Should show:
# Email worker started
# Processing email job for campaign: abc-123

Solution 3: Restart worker

# Restart API (restarts worker)
docker compose restart api

# Check worker started
docker compose logs api | grep "Email worker started"

Solution 4: Check Redis

# Test Redis connection
docker compose exec redis redis-cli -a YOUR_REDIS_PASSWORD ping

# Check queue keys
docker compose exec redis redis-cli -a YOUR_REDIS_PASSWORD keys "bull:email-queue:*"

Solution 5: Process stuck jobs

# Retry failed jobs
curl -X POST http://localhost:4000/api/influence/email-queue/retry-failed \
  -H "Authorization: Bearer YOUR_TOKEN"

# Clean old jobs
curl -X POST http://localhost:4000/api/influence/email-queue/clean \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"status": "completed", "grace": 86400000}'  # Clean completed > 1 day

Prevention

  • Health checks - Monitor worker health
  • Auto-restart - Restart worker if stuck
  • Alerting - Alert if queue backed up
  • Dead letter queue - Move repeatedly failed jobs

Jobs Failing

Severity: 🟠 High

Symptoms

High failed job count. Emails not reaching recipients.

Solutions

Solution 1: View failed jobs

# Get failed job details
curl http://localhost:4000/api/influence/email-queue/failed \
  -H "Authorization: Bearer YOUR_TOKEN"

# Shows:
# [
#   {
#     "id": "123",
#     "data": { "to": "user@example.com", "subject": "..." },
#     "failedReason": "SMTP connection failed",
#     "attemptsMade": 3
#   }
# ]

Solution 2: Check error patterns

# Common failure reasons
docker compose logs api | grep "Email failed" | sort | uniq -c

# Example output:
#  25 Email failed: Invalid email address
#  10 Email failed: SMTP connection refused
#   3 Email failed: Recipient mailbox full

Solution 3: Retry with fixes

# Fix SMTP config if needed
# Then retry failed jobs
curl -X POST http://localhost:4000/api/influence/email-queue/retry-failed \
  -H "Authorization: Bearer YOUR_TOKEN"

Solution 4: Manual intervention

For repeatedly failing emails:

  1. Check email address validity
  2. Verify SMTP configuration
  3. Test with different recipient
  4. Check if recipient's mailbox full

Prevention

  • Retry logic - Auto-retry with exponential backoff
  • Email validation - Validate before queuing
  • Error categorization - Permanent vs transient failures
  • Bounce handling - Handle bounce notifications

Delivery Issues

Emails Not Arriving

Severity: 🔴 Critical

Symptoms

Emails sent successfully (no errors) but not received.

Common Causes

  1. Spam folder - Filtered to spam
  2. Email delay - Taking long to deliver
  3. Email blocking - Recipient server blocking
  4. Wrong address - Typo in email address

Solutions

Solution 1: Check spam folder

  1. Check spam/junk folder
  2. Check promotions tab (Gmail)
  3. Mark as "Not Spam" to whitelist

Solution 2: Check email logs

# Verify email was sent
docker compose logs api | grep "Email sent"

# Should show:
# Email sent to user@example.com: Campaign Email

Solution 3: Use MailHog to test

# In .env
EMAIL_TEST_MODE=true

# Restart API
docker compose restart api

# Send test email
curl -X POST http://localhost:4000/api/test-email \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"to": "test@example.com", "subject": "Test", "text": "Test"}'

# Check MailHog
# http://localhost:8025

# If appears in MailHog, SMTP working
# If not appearing in real inbox, delivery issue

Solution 4: Check email headers

In MailHog or received email: 1. View full headers 2. Check "Received" path 3. Look for spam scores 4. Check SPF/DKIM/DMARC status

Solution 5: Test with different address

# Try sending to different email provider
# Gmail vs Outlook vs Yahoo
# If some work and others don't, specific provider blocking

Prevention

  • Email authentication - SPF, DKIM, DMARC
  • Reputation management - Maintain good sender reputation
  • Bounce handling - Monitor bounces
  • Testing - Regular delivery tests

Marked as Spam

Severity: 🟠 High

Symptoms

Emails consistently go to spam folder.

Solutions

Solution 1: Configure SPF

Add TXT record to DNS:

v=spf1 include:_spf.google.com ~all

Or for SendGrid:

v=spf1 include:sendgrid.net ~all

Solution 2: Configure DKIM

  1. Generate DKIM keys (via email provider)
  2. Add DKIM TXT record to DNS
  3. Enable DKIM signing in SMTP settings

Solution 3: Configure DMARC

Add TXT record to DNS:

v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com

Solution 4: Improve email content

  • Use plain text version alongside HTML
  • Avoid spam trigger words ("FREE", "CLICK HERE", "ACT NOW")
  • Proper from/reply-to addresses
  • Unsubscribe link
  • Physical address in footer

Solution 5: Warm up IP

If using dedicated IP: 1. Start with low volume 2. Gradually increase over weeks 3. Monitor reputation scores

Prevention

  • Email authentication - SPF, DKIM, DMARC mandatory
  • Content quality - Professional, non-spammy content
  • Reputation monitoring - Monitor sender scores
  • Engagement - High engagement = good reputation

Bounce Errors

Severity: 🟡 Medium

Symptoms

Email bounced: user@example.com
554 Recipient address rejected: User unknown

Common Causes

  1. Invalid address - Email doesn't exist
  2. Full mailbox - Recipient mailbox full
  3. Temporary failure - Server temporarily unavailable
  4. Blocked sender - Your domain/IP blocked

Solutions

Solution 1: Categorize bounces

Hard bounces (permanent): - User unknown - Domain doesn't exist - Invalid address format

Soft bounces (temporary): - Mailbox full - Server temporarily unavailable - Message too large

Solution 2: Handle hard bounces

# Remove hard bounce addresses
docker compose exec v2-postgres psql -U changemaker -d changemaker_v2 \
  -c "UPDATE \"User\" SET \"emailBounced\" = true
      WHERE email = 'bounced@example.com';"

# Don't send to bounced addresses

Solution 3: Retry soft bounces

# Retry soft bounces after delay
curl -X POST http://localhost:4000/api/influence/email-queue/retry-failed \
  -H "Authorization: Bearer YOUR_TOKEN"

Solution 4: Validate emails before sending

import validator from 'validator';

const isValidEmail = validator.isEmail(email);
if (!isValidEmail) {
  throw new Error('Invalid email address');
}

Prevention

  • Email validation - Validate before saving
  • Bounce tracking - Track bounces per address
  • Automatic removal - Don't send to bounced addresses
  • Double opt-in - Confirm email addresses work

Listmonk Integration

API Connection Failed

Severity: 🟠 High

Symptoms

Error: Failed to connect to Listmonk API
Error: ECONNREFUSED localhost:9001

Solutions

Solution 1: Check Listmonk is running

docker compose ps listmonk

# Should show "Up"
# If not:
docker compose up -d listmonk

Solution 2: Verify API credentials

# Check .env
cat .env | grep LISTMONK_

# Required:
LISTMONK_URL=http://listmonk:9001
LISTMONK_ADMIN_USER=admin
LISTMONK_ADMIN_PASSWORD=password

Solution 3: Test API connection

# From API container
docker compose exec api curl -u admin:password http://listmonk:9001/api/health

# Should return:
# {"data": "OK"}

Solution 4: Check Docker network

# Both on same network?
docker inspect changemaker-lite-api-1 | grep NetworkMode
docker inspect changemaker-lite-listmonk-1 | grep NetworkMode

# Should both show "changemaker-lite"

Prevention

  • Health checks - Verify Listmonk health on API startup
  • Proper credentials - Use API user (not web admin)
  • Network config - Ensure same Docker network
  • Error handling - Graceful degradation if Listmonk down

Sync Errors

Severity: 🟡 Medium

Symptoms

Error: Failed to sync subscribers to Listmonk
Error: 400 Bad Request: Invalid email format

Solutions

Solution 1: Check sync status

Navigate to /app/listmonk:

  • View sync statistics
  • See last sync time
  • Check error count

Solution 2: View sync logs

docker compose logs api | grep -i "listmonk\|sync"

# Shows:
# Syncing 150 participants to Listmonk
# Created list: Campaign Participants
# Added 145 subscribers, 5 failed

Solution 3: Manual sync

# Trigger manual sync
curl -X POST http://localhost:4000/api/listmonk/sync \
  -H "Authorization: Bearer YOUR_TOKEN"

Solution 4: Check subscriber data

# View failed subscribers
docker compose logs api | grep "Failed to add subscriber"

# Common issues:
# - Invalid email format
# - Email already exists
# - Missing required fields

Prevention

  • Data validation - Validate before sync
  • Duplicate handling - Handle existing subscribers
  • Error logging - Log sync errors
  • Regular syncs - Automated periodic syncs

Performance Issues

Slow Email Sending

Severity: 🟡 Medium

Symptoms

Sending emails takes several seconds each. Bulk sends very slow.

Solutions

Solution 1: Use queue system

# Don't send synchronously
# Queue emails instead
curl -X POST http://localhost:4000/api/influence/campaigns/CAMPAIGN_ID/send-bulk \
  -H "Authorization: Bearer YOUR_TOKEN"

# Processes in background via queue

Solution 2: Increase worker concurrency

In api/src/services/email-queue.service.ts:

const worker = new Worker('email-queue', processor, {
  concurrency: 5,  // Process 5 emails at a time (default: 1)
  limiter: {
    max: 50,  // Max 50 emails per second
    duration: 1000
  }
});

Solution 3: Use batch sending

For transactional email services:

// Some SMTP services support batch sending
// Send 100 emails in single API call instead of 100 separate calls

Solution 4: Check SMTP performance

# Test SMTP connection speed
time curl -X POST http://localhost:4000/api/test-email \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"to": "test@example.com", "subject": "Test", "text": "Test"}'

# Should complete in < 2 seconds
# If > 5 seconds, SMTP server slow

Solution 5: Use email service

For high volume, use transactional email service: - SendGrid - Mailgun - Amazon SES - Postmark

Faster and more reliable than SMTP.

Prevention

  • Queue system - Never send synchronously
  • Worker concurrency - Process multiple at once
  • Email service - Use dedicated email service
  • Rate limiting - Respect provider limits

Queue Backlog

Severity: 🟡 Medium

Symptoms

Thousands of emails waiting in queue. Taking hours to process.

Solutions

Solution 1: Increase worker count

Start multiple API instances:

# In docker-compose.yml
api:
  deploy:
    replicas: 3  # 3 API instances

Each instance runs its own worker.

Solution 2: Increase concurrency

See "Slow Email Sending" section above.

Solution 3: Pause new emails

# Pause queue
curl -X POST http://localhost:4000/api/influence/email-queue/pause \
  -H "Authorization: Bearer YOUR_TOKEN"

# Process backlog
# Resume when caught up
curl -X POST http://localhost:4000/api/influence/email-queue/resume \
  -H "Authorization: Bearer YOUR_TOKEN"

Solution 4: Clean old jobs

# Remove completed jobs
curl -X POST http://localhost:4000/api/influence/email-queue/clean \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"status": "completed", "grace": 3600000}'  # Older than 1 hour

Prevention

  • Monitor queue size - Alert when > 1000 waiting
  • Rate limiting - Don't queue faster than can process
  • Capacity planning - Size workers for expected load
  • Cleanup jobs - Regular cleanup of old jobs

Useful Commands

Testing Email

# Send test email
curl -X POST http://localhost:4000/api/test-email \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{
    "to": "test@example.com",
    "subject": "Test Email",
    "text": "This is a test email",
    "html": "<h1>Test Email</h1><p>This is a test email</p>"
  }'

# Test with template
curl -X POST http://localhost:4000/api/test-template-email \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{
    "to": "test@example.com",
    "subject": "Test Template",
    "template": "campaign-email",
    "variables": {
      "name": "Test User",
      "campaignName": "Test Campaign"
    }
  }'

Queue Management

# Get queue stats
curl http://localhost:4000/api/influence/email-queue/stats \
  -H "Authorization: Bearer YOUR_TOKEN"

# Pause queue
curl -X POST http://localhost:4000/api/influence/email-queue/pause \
  -H "Authorization: Bearer YOUR_TOKEN"

# Resume queue
curl -X POST http://localhost:4000/api/influence/email-queue/resume \
  -H "Authorization: Bearer YOUR_TOKEN"

# Retry failed
curl -X POST http://localhost:4000/api/influence/email-queue/retry-failed \
  -H "Authorization: Bearer YOUR_TOKEN"

# Clean completed
curl -X POST http://localhost:4000/api/influence/email-queue/clean \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"status": "completed", "grace": 86400000}'

Listmonk Operations

# Test Listmonk connection
curl -u admin:password http://localhost:9001/api/health

# Get lists
curl -u admin:password http://localhost:9001/api/lists

# Sync subscribers
curl -X POST http://localhost:4000/api/listmonk/sync \
  -H "Authorization: Bearer YOUR_TOKEN"

# Get sync status
curl http://localhost:4000/api/listmonk/status \
  -H "Authorization: Bearer YOUR_TOKEN"

Email Documentation

Other Troubleshooting

External Resources


Last Updated: February 2026 Version: V2.0 Status: Complete