Skip to content

ivpn/mailx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Email Service

API

  • Go
  • Fiber (API, middleware)
  • Gorm (ORM)
  • MariaDB (Database)
  • Redis (Cache)
  • Docker (Containerization)
  • Swagger (API Documentation)

App

  • TypeScript
  • Vue.js
  • Vite (Bundler)
  • Tailwind (Styling)
  • Docker (Containerization)

Mailserver

Installation

Prerequisites

Important

Docker Mailserver officially supports Linux. If you want to run it on macOS, please read this.

Config

cp api/.env.sample api/.env
cp app/.env.sample app/.env
cp mailserver/.env.sample mailserver/.env
mkdir -p mailserver/docker-data/dms/config/rspamd/override.d
cp mailserver/config/postfix-main.cf.sample mailserver/docker-data/dms/config/postfix-main.cf
cp mailserver/config/postfix-virtual.cf.sample mailserver/docker-data/dms/config/postfix-virtual.cf
cp mailserver/config/postfix-aliases.cf.sample mailserver/docker-data/dms/config/postfix-aliases.cf
cp mailserver/config/user-patches.sh.sample mailserver/docker-data/dms/config/user-patches.sh
cp mailserver/config/rspamd/override.d/milter_headers.conf.sample mailserver/docker-data/dms/config/rspamd/override.d/milter_headers.conf

Important

Make sure to set up the required config:

  • api/.env: DOMAINS, SMTP_CLIENT_*
  • app/src/env.json: DOMAINS
  • mailserver/.env: HOSTNAME
  • mailserver/docker-data/dms/config/postfix-virtual.cf: @your-domain.net curl_email

Tip

For local testing, you can use MailHog or MailTrap as outbound SMTP client (SMTP_CLIENT_*).

API + App

Move to api directory

cd api

Run

docker compose up -d

App:
http://localhost:3001

API:
http://localhost:3000

Mailserver

Move to mailserver directory

cd mailserver

Run

# localhost
docker compose up -d

# Staging|Production
docker compose -f compose.deploy.yml up -d

Setup Postfix

docker exec -it mailserver sh

# Build the db file
postmap /etc/postfix/virtual

# Update the alias table
newaliases

# Enable DKIM signing, this will output the contents of DKIM TXT DNS record (mail._domainkey.domain.com)
setup config dkim selector mail

# Restart Postfix
supervisorctl restart postfix

# Show logs
setup debug show-mail-logs

Setup DKIM Signing

Update dkim_signing.conf:

nano docker-data/dms/config/rspamd/override.d/dkim_signing.conf

dkim_signing.conf:

# documentation: https://rspamd.com/doc/modules/dkim_signing.html

enabled = true;

sign_authenticated = true;
sign_local = true;
try_fallback = false;

use_domain = "header";
use_domain_sign_local = "header";
use_redis = false; # don't change unless Redis also provides the DKIM keys
use_esld = true;
allow_username_mismatch = true;

check_pubkey = false; # you want to use this in the beginning

domain {
    domain.com {
        path = "/tmp/docker-mailserver/rspamd/dkim/rsa-2048-mail-domain.com.private.txt";
        selector = "mail";
    }
}

Restart Mailserver:

docker compose down
docker compose up -d

Test DKIM signing with https://dkimvalidator.com:

echo "Test email" | mail -s "Test email" wyygMXeSfnzl5l@dkimvalidator.com

Update Mailserver

docker compose pull
docker compose down
docker compose up -d

Add New Domain

Mailserver

Update postfix-virtual.cf:

nano docker-data/dms/config/postfix-virtual.cf
@domain.com curl_email

Setup Postfix:

docker exec -it mailserver sh
postmap /etc/postfix/virtual
newaliases
setup config dkim selector mail domain domain.com
supervisorctl restart postfix

Update dkim_signing.conf:

nano docker-data/dms/config/rspamd/override.d/dkim_signing.conf
domain.com {
    path = "/tmp/docker-mailserver/rspamd/dkim/rsa-2048-mail-domain.com.private.txt";
    selector = "mail";
}

Restart mailserver:

docker compose down
docker compose -f compose.deploy.yml up -d

DNS Records

MX Records:

domain.com. . 14400 IN MX 10 mail.domain.com.
mail.domain.com. . 14400 IN MX 10 MAIL_SERVER_IPV4

SPF Records:

domain.com. 3600 IN TXT "v=spf1 ip4:MAIL_SERVER_IPV4 -all"
mail.domain.com. 3600 IN TXT "v=spf1 ip4:MAIL_SERVER_IPV4 -all"

DMARC (TXT record):

_dmarc.mail.domain.com. 3600 IN TXT v=DMARC1; p=quarantine

DKIM (TXT record):

mail._domainkey.domain.com. 3600 IN TXT v=DKIM1;k=rsa;p=DKIM_PUBLIC_KEY

API

Update .env:

nano .env
DOMAINS=domain1.com,domain2.com

Restart api:

docker compose down
docker compose up -d

App

Update GitHub Actions env variables:

STAGING_VITE_DOMAINS=domain1.com,domain2.com
PROD_VITE_DOMAINS=domain1.com,domain2.com

Restore DB from backup

DB backup is stored locally on the host machine in the ${HOME}/backups directory.

Unpack backup

cd ${HOME}/backups
gpg -o backup.tar.gz -d backup-latest.tar.gz.gpg
tar -xvf backup.tar.gz

Restore DB

# Stop the containers
docker compose down

# Clone the volume
docker volume create email_db_clone
docker run --rm -v email_db:/from -v email_db_clone:/to alpine sh -c "cp -a /from/. /to/"

# Remove the original volume
docker volume rm email_db

# Recreate the original volume from backup
docker run -d --name restore -v email_db:/email_db alpine
docker cp /unpacked_volume_dir/. restore:/email_db
docker stop restore && docker rm restore

# Start the containers
docker compose up -d

Test

Run API tests:

go test ./... -v
go vet ./...
gosec ./...

Send test email:

docker exec -it mailserver sh
echo "Test email body" | mail -s "Test subject" example.alias@example.net

API Documentation

API docs:
http://localhost:3000/docs

Generate API docs:

cd api
swag init -g cmd/main.go

Tip

With Task, run task docs to generate API documentation.