Operations

Troubleshooting

Common issues and their solutions.

Common Issues

ProblemSolution
Port 25 blockedContact your VPS provider to unblock outbound port 25. Test with nc -zv gmail-smtp-in.l.google.com 25
DKIM not verifyingWait 24-48h for DNS propagation. Check with dig TXT postal._domainkey.yourdomain.com
License activation failsEnsure APP_ENV=production is set. Check network connectivity to api.dodopayments.com
Emails going to spamCheck SPF/DKIM/DMARC are all green in dashboard. Warm up mailboxes first (2-3 weeks)
Server won't startCheck logs: docker compose logs cleanmails. Usually missing MASTER_KEY
SQLite locked errorsEnsure only one instance is running. WAL mode handles concurrency automatically
SMTP test fails on sender creationVerify host/port/credentials. For Mailcow-managed senders, this is handled automatically
Campaign not sendingCheck: status is "running", schedule window is active, senders have remaining daily limit, leads are not unsubscribed
Warmup not workingNeed at least 2 senders in warmup mode. Check both have status "ready"
AI tags showing fallbackCheck Gemini API key in Settings → AI. Verify key is valid at aistudio.google.com

Checking Logs

Docker Compose deployment

bash
# All services
docker compose logs -f

# Just Cleanmails
docker compose logs -f cleanmails

# Just mail server
docker compose logs -f mailserver

# Last 100 lines
docker compose logs --tail=100 cleanmails

Systemd deployment

bash
# Live logs
journalctl -u cleanmails -f

# Last hour
journalctl -u cleanmails --since "1 hour ago"

# Application log file
tail -f /opt/cleanmails/cleanmails.log

Health Check

bash
# Basic health
curl http://localhost:8080/health

# Detailed outreach health (port 25, queues, runtime)
curl http://localhost:8080/v1/outreach/health

# Network check (port 25 status)
curl http://localhost:8080/v1/outreach/health | jq '.checks.port_25_outgoing'

Database Issues

Corrupted database

bash
# Stop the service
docker compose down

# Check integrity
sqlite3 /opt/cleanmails/data/cleanmails.db "PRAGMA integrity_check;"

# If corrupted, restore from backup
cp /backups/cleanmails-YYYYMMDD.db /opt/cleanmails/data/cleanmails.db

# Restart
docker compose up -d

Database is locked

This usually means multiple processes are trying to write simultaneously. Cleanmails uses a single-connection pool to prevent this, but if you're running multiple instances:

bash
# Check for multiple processes
ps aux | grep bulkserver

# Kill duplicates (keep only one)
kill <PID>

Email Deliverability Issues

Check DNS records

bash
# SPF
dig TXT yourdomain.com

# DKIM
dig TXT postal._domainkey.yourdomain.com

# DMARC
dig TXT _dmarc.yourdomain.com

# MX
dig MX yourdomain.com

Check IP blacklists

Visit MXToolbox Blacklist Check and enter your server IP.

Resetting Admin Password

If you've lost your admin password, you can reset it directly in the database:

Direct database access

This requires SSH access to your server. The password must be bcrypt-hashed.

bash
# Generate a bcrypt hash for your new password
docker exec cleanmails sh -c 'echo -n "YourNewPassword" | htpasswd -niBC 10 "" | cut -d: -f2'

# Update in database
sqlite3 /opt/cleanmails/data/cleanmails.db "UPDATE users SET password='BCRYPT_HASH_HERE' WHERE role='admin';"

# Restart to clear sessions
docker compose restart cleanmails

Getting Help

If you're still stuck:

  • Use the AI Copilot in your dashboard — it has full context of your workspace
  • Check the Support page for direct assistance
  • Include your logs and health check output when reporting issues