# Clone and set up Mailcow on a fresh Ubuntu/Debian VPS
-weight: 500;">git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized # Generate the config — it'll ask for your mail hostname
./generate_config.sh # Fire it up
-weight: 500;">docker compose pull
-weight: 500;">docker compose up -d
# Clone and set up Mailcow on a fresh Ubuntu/Debian VPS
-weight: 500;">git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized # Generate the config — it'll ask for your mail hostname
./generate_config.sh # Fire it up
-weight: 500;">docker compose pull
-weight: 500;">docker compose up -d
# Clone and set up Mailcow on a fresh Ubuntu/Debian VPS
-weight: 500;">git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized # Generate the config — it'll ask for your mail hostname
./generate_config.sh # Fire it up
-weight: 500;">docker compose pull
-weight: 500;">docker compose up -d
; MX record — tells the world where to deliver mail for your domain
example.com. IN MX 10 mail.example.com. ; A record — points your mail hostname to your server IP
mail.example.com. IN A 203.0.113.42 ; SPF record — declares which servers can send mail for your domain
example.com. IN TXT "v=spf1 mx a -all" ; DMARC record — tells receivers what to do with mail that fails checks
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
; MX record — tells the world where to deliver mail for your domain
example.com. IN MX 10 mail.example.com. ; A record — points your mail hostname to your server IP
mail.example.com. IN A 203.0.113.42 ; SPF record — declares which servers can send mail for your domain
example.com. IN TXT "v=spf1 mx a -all" ; DMARC record — tells receivers what to do with mail that fails checks
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
; MX record — tells the world where to deliver mail for your domain
example.com. IN MX 10 mail.example.com. ; A record — points your mail hostname to your server IP
mail.example.com. IN A 203.0.113.42 ; SPF record — declares which servers can send mail for your domain
example.com. IN TXT "v=spf1 mx a -all" ; DMARC record — tells receivers what to do with mail that fails checks
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
# Verify your PTR record is set correctly
dig -x 203.0.113.42 +short
# Should return: mail.example.com.
# Verify your PTR record is set correctly
dig -x 203.0.113.42 +short
# Should return: mail.example.com.
# Verify your PTR record is set correctly
dig -x 203.0.113.42 +short
# Should return: mail.example.com.
# If using Mailcow/Docker
-weight: 500;">docker compose logs --tail=100 postfix-mailcow # Look for lines like these:
# -weight: 500;">status=deferred (host gmail-smtp-in.l.google.com said: 421 try again later)
# -weight: 500;">status=bounced (550 5.7.1 rejected by recipient domain)
# If using Mailcow/Docker
-weight: 500;">docker compose logs --tail=100 postfix-mailcow # Look for lines like these:
# -weight: 500;">status=deferred (host gmail-smtp-in.l.google.com said: 421 try again later)
# -weight: 500;">status=bounced (550 5.7.1 rejected by recipient domain)
# If using Mailcow/Docker
-weight: 500;">docker compose logs --tail=100 postfix-mailcow # Look for lines like these:
# -weight: 500;">status=deferred (host gmail-smtp-in.l.google.com said: 421 try again later)
# -weight: 500;">status=bounced (550 5.7.1 rejected by recipient domain)
#!/bin/bash
DOMAIN="example.com"
MAIL_HOST="mail.${DOMAIN}" echo "=== Checking MX ==="
dig MX $DOMAIN +short echo "=== Checking SPF ==="
dig TXT $DOMAIN +short | grep spf echo "=== Checking DKIM ==="
# Replace 'dkim' with your actual DKIM selector
dig TXT dkim._domainkey.${DOMAIN} +short echo "=== Checking DMARC ==="
dig TXT _dmarc.${DOMAIN} +short echo "=== Checking PTR ==="
SERVER_IP=$(dig A $MAIL_HOST +short)
dig -x $SERVER_IP +short echo "=== Checking TLS on port 587 ==="
openssl s_client -starttls smtp -connect ${MAIL_HOST}:587 < /dev/null 2>&1 | grep "Verify return code"
#!/bin/bash
DOMAIN="example.com"
MAIL_HOST="mail.${DOMAIN}" echo "=== Checking MX ==="
dig MX $DOMAIN +short echo "=== Checking SPF ==="
dig TXT $DOMAIN +short | grep spf echo "=== Checking DKIM ==="
# Replace 'dkim' with your actual DKIM selector
dig TXT dkim._domainkey.${DOMAIN} +short echo "=== Checking DMARC ==="
dig TXT _dmarc.${DOMAIN} +short echo "=== Checking PTR ==="
SERVER_IP=$(dig A $MAIL_HOST +short)
dig -x $SERVER_IP +short echo "=== Checking TLS on port 587 ==="
openssl s_client -starttls smtp -connect ${MAIL_HOST}:587 < /dev/null 2>&1 | grep "Verify return code"
#!/bin/bash
DOMAIN="example.com"
MAIL_HOST="mail.${DOMAIN}" echo "=== Checking MX ==="
dig MX $DOMAIN +short echo "=== Checking SPF ==="
dig TXT $DOMAIN +short | grep spf echo "=== Checking DKIM ==="
# Replace 'dkim' with your actual DKIM selector
dig TXT dkim._domainkey.${DOMAIN} +short echo "=== Checking DMARC ==="
dig TXT _dmarc.${DOMAIN} +short echo "=== Checking PTR ==="
SERVER_IP=$(dig A $MAIL_HOST +short)
dig -x $SERVER_IP +short echo "=== Checking TLS on port 587 ==="
openssl s_client -starttls smtp -connect ${MAIL_HOST}:587 < /dev/null 2>&1 | grep "Verify return code"
# Simple backup script for Mailcow
#!/bin/bash
BACKUP_DIR="/opt/mailcow-backups"
cd /opt/mailcow-dockerized # Mailcow includes a backup helper
./helper-scripts/backup_and_restore.sh backup all --delete-days 7
# Simple backup script for Mailcow
#!/bin/bash
BACKUP_DIR="/opt/mailcow-backups"
cd /opt/mailcow-dockerized # Mailcow includes a backup helper
./helper-scripts/backup_and_restore.sh backup all --delete-days 7
# Simple backup script for Mailcow
#!/bin/bash
BACKUP_DIR="/opt/mailcow-backups"
cd /opt/mailcow-dockerized # Mailcow includes a backup helper
./helper-scripts/backup_and_restore.sh backup all --delete-days 7 - Your IP address needs a clean reputation
- You need proper DNS records (SPF, DKIM, DMARC)
- Reverse DNS (PTR record) must match your mail server hostname
- Your VPS provider needs to allow outbound port 25
- You need TLS configured correctly - "421 try again later" — Your IP reputation is too new. Send a few emails to yourself first, mark them as "not spam," and wait a day or two. Warming up is real.
- "550 rejected" — Check your SPF and DKIM. Use mail-tester.com to get a detailed score breakdown.
- Emails land in spam — Usually a DMARC or DKIM alignment issue. Make sure your From: domain matches the domain in your DKIM signature. - Set up automated daily backups of your mail directory and database
- Monitor disk space — mailboxes grow faster than you think
- Keep your server updated — Postfix and Dovecot vulnerabilities are high-value targets
- Use fail2ban or similar to block brute-force login attempts - Do self-host if: You're running infrastructure for a small team, you value data ownership, or you're a homelab enthusiast who enjoys this stuff
- Don't self-host if: You're sending high-volume transactional email (use a dedicated sending -weight: 500;">service), you can't commit to monitoring, or you don't have a static IP