Enterprise Outbound Email Delivery Platform

Go 1.22+ PostgreSQL 16 Redis 7 Docker Ready DKIM/SPF/DMARC

🚀 Overview

High-performance email delivery infrastructure for enterprise use

⚡

High Performance

Built in Go with concurrent workers, connection pooling, and intelligent rate limiting

🔐

Full Authentication

DKIM signing, SPF validation, DMARC compliance out of the box

📊

Real-time Metrics

Prometheus + Grafana dashboards for complete visibility

đŸŗ

Docker Ready

One-command deployment with Docker Compose

Key Features

📋 Requirements

System requirements for running MailForge

Component Minimum Version Recommended
Operating System Ubuntu 20.04 / Debian 11 Ubuntu 22.04 LTS
Docker 20.10+ 24.0+
Docker Compose 2.0+ 2.20+
PostgreSQL 14+ 16
Redis 6+ 7+
RAM 2 GB 4 GB+
CPU 2 cores 4+ cores
â„šī¸
Note: For production use, ensure your server IP is not on any blocklists and has proper reverse DNS (PTR record) configured.

đŸ“Ļ Installation

Step-by-step installation guide

Install Docker & Docker Compose

Terminal
# Update system
apt update && apt upgrade -y

# Install Docker
curl -fsSL https://get.docker.com | sh

# Install Docker Compose
apt install docker-compose-plugin -y

# Verify installation
docker --version
docker compose version

Install PostgreSQL

Terminal
# Install PostgreSQL 16
apt install postgresql postgresql-contrib -y

# Start and enable PostgreSQL
systemctl start postgresql
systemctl enable postgresql

# Create database and user
sudo -u postgres psql
PostgreSQL Commands
CREATE USER mailforge WITH PASSWORD 'mailforge';
CREATE DATABASE mailforge OWNER mailforge;
GRANT ALL PRIVILEGES ON DATABASE mailforge TO mailforge;
\q
Configure PostgreSQL for Docker access
# Edit postgresql.conf
nano /etc/postgresql/16/main/postgresql.conf
# Change: listen_addresses = '*'

# Edit pg_hba.conf
nano /etc/postgresql/16/main/pg_hba.conf
# Add: host all all 172.17.0.0/16 md5

# Restart PostgreSQL
systemctl restart postgresql

Install Redis

Terminal
# Install Redis
apt install redis-server -y

# Configure Redis to listen on all interfaces
sed -i 's/bind 127.0.0.1/bind 0.0.0.0/' /etc/redis/redis.conf

# Start Redis
systemctl restart redis
systemctl enable redis

Clone and Deploy MailForge

Terminal
# Clone repository
cd /home
Upload your mailforge.zip and unzip it on /home
cd mailforge

# Run database migrations
PGPASSWORD=mailforge psql -U mailforge -h localhost -d mailforge -f migrations/001_initial_schema.sql

# Build and start
docker compose build
docker compose up -d

# Check logs
docker compose logs -f

Initialize Database Records

Create Account, IP Pool, and IP Address
# Create default account
PGPASSWORD=mailforge psql -U mailforge -h localhost -d mailforge -c "
INSERT INTO accounts (id, name, email, api_key_hash, created_at, updated_at)
VALUES (
  '00000000-0000-0000-0000-000000000001',
  'Default',
  '[email protected]',
  'your_api_key',
  NOW(), NOW()
);"

# Create IP pool
PGPASSWORD=mailforge psql -U mailforge -h localhost -d mailforge -c "
INSERT INTO ip_pools (id, account_id, name, rotation_strategy, active, created_at, updated_at)
VALUES (
  '00000000-0000-0000-0000-000000000001',
  '00000000-0000-0000-0000-000000000001',
  'Default',
  'round-robin',
  true, NOW(), NOW()
);"

# Add your server IP
PGPASSWORD=mailforge psql -U mailforge -h localhost -d mailforge -c "
INSERT INTO ip_addresses (id, ip_pool_id, ip_address, hostname, active, created_at, updated_at)
VALUES (
  '00000000-0000-0000-0000-000000000001',
  '00000000-0000-0000-0000-000000000001',
  'YOUR_SERVER_IP',
  'mail.yourdomain.com',
  true, NOW(), NOW()
);"

🌐 DNS Setup

Configure DNS records for email delivery

âš ī¸
Important: Proper DNS configuration is critical for email deliverability. Missing or incorrect records will cause emails to go to spam or be rejected.

Required DNS Records

Type Name Value Purpose
A mail.yourdomain.com YOUR_SERVER_IP Mail server hostname
PTR YOUR_SERVER_IP mail.yourdomain.com Reverse DNS (contact hosting provider)
MX yourdomain.com 10 mail.yourdomain.com Mail exchange record
TXT yourdomain.com v=spf1 ip4:YOUR_SERVER_IP ~all SPF - Authorizes your IP to send
TXT _dmarc.yourdomain.com v=DMARC1; p=none; rua=mailto:[email protected] DMARC policy
TXT mail._domainkey.yourdomain.com v=DKIM1; k=rsa; p=YOUR_PUBLIC_KEY DKIM public key

Verify DNS Records

Terminal
# Check SPF
dig TXT yourdomain.com +short

# Check DKIM
dig TXT mail._domainkey.yourdomain.com +short

# Check DMARC
dig TXT _dmarc.yourdomain.com +short

# Check PTR (reverse DNS)
dig -x YOUR_SERVER_IP +short

🔑 DKIM Configuration

Generate and configure DKIM keys for email signing

Generate DKIM Key Pair

Terminal
# Generate 2048-bit RSA key pair
openssl genrsa -out yourdomain.com.private 2048
openssl rsa -in yourdomain.com.private -pubout -out yourdomain.com.public

# View private key (save for database)
cat yourdomain.com.private

# View public key (for DNS record)
cat yourdomain.com.public

Add Domain to Database

Terminal
PGPASSWORD=mailforge psql -U mailforge -h localhost -d mailforge -c "
INSERT INTO domains (id, account_id, domain, dkim_private_key, dkim_selector, dkim_enabled, verified, created_at, updated_at)
VALUES (
  '00000000-0000-0000-0000-000000000001',
  '00000000-0000-0000-0000-000000000001',
  'yourdomain.com',
  '-----BEGIN PRIVATE KEY-----
YOUR_PRIVATE_KEY_HERE
-----END PRIVATE KEY-----',
  'mail',
  true,
  true,
  NOW(), NOW()
);"

Add DKIM DNS Record

Create a TXT record with the following format:

DNS TXT Record
Name: mail._domainkey.yourdomain.com
Value: v=DKIM1; k=rsa; p=YOUR_PUBLIC_KEY_BASE64_WITHOUT_HEADERS
💡
Remove the -----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY----- lines and all newlines from the public key when adding to DNS.

🔌 API Usage

Send emails using the REST API

Authentication

All API requests require an API key in the X-API-Key header.

Send Single Email

cURL
curl -X POST http://localhost:8080/api/v1/messages \
  -H "Content-Type: application/json" \
  -H "X-API-Key: mf_test_key_12345" \
  -d '{
    "from": "[email protected]",
    "to": "[email protected]",
    "subject": "Hello World",
    "html_body": "<h1>Hello!</h1><p>This is a test email.</p>"
  }'

Send Campaign with CSV

Bash Script - send_campaign.sh
#!/bin/bash

API_URL="http://localhost:8080/api/v1"
API_KEY="mf_test_key_12345"
CSV_FILE="contacts.csv"

# Email content
FROM_NAME="Your Company"
FROM_EMAIL="[email protected]"
SUBJECT="Hello {{name}}!"
HTML_BODY="<h1>Hi {{name}}!</h1><p>Thanks for subscribing!</p>"

# DKIM settings
DKIM_DOMAIN="yourdomain.com"
DKIM_SELECTOR="mail"

# Create campaign
CAMPAIGN_ID=$(curl -s -X POST "$API_URL/campaigns" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $API_KEY" \
  -d '{"name": "My Campaign"}' | jq -r '.id')

echo "Created campaign: $CAMPAIGN_ID"

# Read CSV
CSV_CONTENT=$(cat "$CSV_FILE" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))')

# Send campaign
curl -X POST "$API_URL/campaigns/$CAMPAIGN_ID/import" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $API_KEY" \
  -d "{
    \"from_name\": \"$FROM_NAME\",
    \"from_email\": \"$FROM_EMAIL\",
    \"subject\": \"$SUBJECT\",
    \"html_body\": \"$HTML_BODY\",
    \"dkim_domain\": \"$DKIM_DOMAIN\",
    \"dkim_selector\": \"$DKIM_SELECTOR\",
    \"csv\": $CSV_CONTENT
  }"

CSV Format

contacts.csv
email,name
[email protected],John Doe
[email protected],Jane Smith
[email protected],Bob Wilson

API Endpoints

Method Endpoint Description
POST /api/v1/messages Send single email
POST /api/v1/campaigns Create campaign
POST /api/v1/campaigns/:id/import Import CSV and send
GET /api/v1/campaigns/:id/stats Get campaign statistics
POST /api/v1/suppressions Add to suppression list
GET /api/v1/suppressions List suppressions
GET /health Health check
GET /metrics Prometheus metrics

📈 Monitoring

Monitor your email delivery with Grafana dashboards

Access Dashboards

📊

Grafana

URL: http://your-server:3000
User: admin
Password: admin

đŸ”Ĩ

Prometheus

URL: http://your-server:9091
Metrics endpoint: /metrics

Key Metrics

Metric Description
mailforge_messages_total Total messages by status (delivered, bounced, deferred)
mailforge_queue_size Current queue size
mailforge_workers_active Number of active workers
mailforge_delivery_duration_seconds Email delivery time histogram
mailforge_smtp_connections Active SMTP connections

Check Logs

Terminal
# View all logs
docker compose logs -f

# View only mailforge logs
docker compose logs -f mailforge

# Filter for errors
docker compose logs -f mailforge 2>&1 | grep -i error

# Filter for DKIM
docker compose logs -f mailforge 2>&1 | grep -i dkim

🔧 Troubleshooting

Common issues and solutions

Emails Going to Spam

Connection Refused

Terminal
# Check if PostgreSQL is listening
netstat -tlnp | grep 5432

# Check if Redis is listening
netstat -tlnp | grep 6379

# Test PostgreSQL connection from Docker
docker run --rm postgres:16 psql -h host.docker.internal -U mailforge -d mailforge -c "SELECT 1"

No IP Available

Terminal
# Check if IP addresses exist in database
PGPASSWORD=mailforge psql -U mailforge -h localhost -d mailforge -c "SELECT * FROM ip_addresses;"

# Check if IP pool exists
PGPASSWORD=mailforge psql -U mailforge -h localhost -d mailforge -c "SELECT * FROM ip_pools;"