27 KiB
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:
-
Transactional Emails (BullMQ + Nodemailer)
- Campaign advocacy emails
- Shift confirmation emails
- Response verification emails
- System notifications
-
Newsletter Emails (Listmonk)
- Marketing campaigns
- Newsletter broadcasts
- 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
- Wrong SMTP host - Incorrect hostname
- Port blocked - Firewall blocking port 587/465
- Wrong credentials - Invalid username/password
- 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):
- Go to https://myaccount.google.com/apppasswords
- Select app: Mail
- Select device: Other (Changemaker Lite)
- Click Generate
- Copy 16-character password
- 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
- Wrong password - Incorrect password
- 2FA enabled - Need app password
- Less secure apps - Gmail blocking
- 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.
- Go to https://myaccount.google.com/lesssecureapps
- Turn on "Allow less secure apps"
Solution 3: Check account status
- Try logging into email account via web
- Check for security alerts
- 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
- Firewall blocking - Network firewall blocking port
- ISP blocking - ISP blocks port 25/587
- 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
- Template file missing - File doesn't exist
- Wrong template name - Typo in name
- Wrong directory - Looking in wrong path
- 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:
- Click "Create Template"
- Fill in details
- Design template
- 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
- Variable not provided - Missing from variables object
- Typo in variable name - Mismatch between template and code
- Wrong delimiter - Using ${} instead of {{}}
- 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
- Invalid HTML - Malformed HTML
- Unclosed tags - Missing closing tags
- Special characters - Unescaped < > &
- 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 < $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:
- Check email address validity
- Verify SMTP configuration
- Test with different recipient
- 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
- Spam folder - Filtered to spam
- Email delay - Taking long to deliver
- Email blocking - Recipient server blocking
- Wrong address - Typo in email address
Solutions
Solution 1: Check spam folder
- Check spam/junk folder
- Check promotions tab (Gmail)
- 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:
- View full headers
- Check "Received" path
- Look for spam scores
- 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
- Generate DKIM keys (via email provider)
- Add DKIM TXT record to DNS
- 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:
- Start with low volume
- Gradually increase over weeks
- 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
- Invalid address - Email doesn't exist
- Full mailbox - Recipient mailbox full
- Temporary failure - Server temporarily unavailable
- 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"
Related Documentation
Email Documentation
- Email Issues - This guide
- Email Templates Feature - Template management
- Email Queue - Queue monitoring
Other Troubleshooting
- Common Errors - General errors
- Performance Optimization - Email performance
External Resources
- Nodemailer Documentation
- BullMQ Documentation
- Listmonk Documentation
- Gmail SMTP Settings
- SPF/DKIM/DMARC Guide
Last Updated: February 2026 Version: V2.0 Status: Complete