๐ง Mail Server Setup with Postfix on AlmaLinux: Email Independence
Tired of paying $10/month per email address? ๐ธ I was too! When our companyโs email bill hit $500/month for 50 users, I said โenough!โ and built our own mail server. Now we have unlimited email addresses, perfect deliverability, and total control. Today Iโm showing you how to set up a professional mail server with Postfix on AlmaLinux. Say goodbye to Gmailโs limitations and hello to email freedom! ๐
๐ค Why Run Your Own Mail Server?
Yes, itโs challenging, but the rewards are huge! Hereโs why:
- ๐ฐ Cost Savings - Unlimited emails for free
- ๐ Complete Privacy - Your emails, your server
- ๐ฏ Custom Domains - Unlimited [email protected]
- ๐ No Limits - Unlimited storage and attachments
- ๐ง Full Control - Custom filters and rules
- ๐ Data Sovereignty - Know where your data lives
True story: We migrated from Google Workspace and saved $6,000/year. Plus, no more โstorage fullโ messages! ๐ช
๐ฏ What You Need
Before we conquer email, ensure you have:
- โ AlmaLinux server with public IP
- โ Domain name with DNS control
- โ Clean IP (not blacklisted)
- โ Port 25 open (check with ISP!)
- โ 60 minutes to master email
- โ Patience (email is complex! โ)
๐ Step 1: DNS and Prerequisites
Email needs proper DNS records!
Configure DNS Records
# Add these DNS records for your domain:
# MX Record (Mail Exchanger)
@ IN MX 10 mail.example.com.
# A Record for mail server
mail IN A YOUR_SERVER_IP
# SPF Record (Sender Policy Framework)
@ IN TXT "v=spf1 mx a ip4:YOUR_SERVER_IP ~all"
# PTR Record (Reverse DNS) - Contact your ISP
YOUR_SERVER_IP.in-addr.arpa. IN PTR mail.example.com.
# DMARC Record
_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
# Placeholder for DKIM (we'll generate this later)
mail._domainkey IN TXT "v=DKIM1; k=rsa; p=..."
Check DNS Configuration
# Verify MX record
dig MX example.com
# Check A record
dig A mail.example.com
# Verify reverse DNS
dig -x YOUR_SERVER_IP
# Test SPF record
dig TXT example.com
Set Hostname
# Set proper hostname
sudo hostnamectl set-hostname mail.example.com
# Update /etc/hosts
sudo nano /etc/hosts
127.0.0.1 localhost
YOUR_SERVER_IP mail.example.com mail
# Verify
hostname -f # Should show mail.example.com
๐ง Step 2: Install and Configure Postfix
Letโs get Postfix running!
Install Postfix and Tools
# Remove sendmail if installed
sudo dnf remove -y sendmail
# Install Postfix and related packages
sudo dnf install -y postfix postfix-mysql dovecot dovecot-mysql
# Install additional tools
sudo dnf install -y mailx opendkim opendkim-tools spamassassin
# Enable services
sudo systemctl enable --now postfix dovecot
Basic Postfix Configuration
# Backup original config
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.backup
# Edit main configuration
sudo nano /etc/postfix/main.cf
# Basic settings
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = ipv4
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
# Network settings
mynetworks = 127.0.0.0/8, 192.168.0.0/24
relay_domains = $mydestination
# Mailbox settings
home_mailbox = Maildir/
mailbox_command =
# Message size limit (50MB)
message_size_limit = 52428800
# Recipient limits
smtpd_recipient_limit = 100
smtpd_recipient_overshoot_limit = 200
# Queue settings
maximal_queue_lifetime = 5d
bounce_queue_lifetime = 5d
# TLS/SSL Configuration
smtpd_use_tls = yes
smtpd_tls_cert_file = /etc/pki/tls/certs/mail.example.com.crt
smtpd_tls_key_file = /etc/pki/tls/private/mail.example.com.key
smtpd_tls_security_level = may
smtpd_tls_protocols = !SSLv2, !SSLv3
smtp_tls_security_level = may
# SMTP Authentication
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $mydomain
broken_sasl_auth_clients = yes
# Restrictions
smtpd_relay_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
defer_unauth_destination
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
reject_rbl_client zen.spamhaus.org,
reject_rbl_client bl.spamcop.net
smtpd_sender_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_non_fqdn_sender,
reject_unknown_sender_domain
# Virtual domains (for multiple domains)
virtual_mailbox_domains = example.com, example.org
virtual_mailbox_base = /var/mail/vhosts
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_minimum_uid = 100
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_alias_maps = hash:/etc/postfix/virtual
Configure Master Process
# Edit master.cf
sudo nano /etc/postfix/master.cf
# Enable submission port (587)
submission inet n - n - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_reject_unlisted_recipient=no
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
# Enable SMTPS (465)
smtps inet n - n - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_reject_unlisted_recipient=no
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
๐ Step 3: Configure Dovecot (IMAP/POP3)
Let users retrieve their email!
Configure Dovecot
# Main configuration
sudo nano /etc/dovecot/dovecot.conf
protocols = imap pop3 lmtp
listen = *, ::
# Mail location
sudo nano /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:~/Maildir
namespace inbox {
inbox = yes
}
# Authentication
sudo nano /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = plain login
# SQL authentication (optional)
#!include auth-sql.conf.ext
# System authentication
!include auth-system.conf.ext
# Master users
sudo nano /etc/dovecot/conf.d/10-master.conf
service imap-login {
inet_listener imap {
port = 143
}
inet_listener imaps {
port = 993
ssl = yes
}
}
service pop3-login {
inet_listener pop3 {
port = 110
}
inet_listener pop3s {
port = 995
ssl = yes
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
unix_listener auth-userdb {
mode = 0666
user = vmail
group = vmail
}
user = dovecot
}
# SSL Configuration
sudo nano /etc/dovecot/conf.d/10-ssl.conf
ssl = required
ssl_cert = </etc/pki/tls/certs/mail.example.com.crt
ssl_key = </etc/pki/tls/private/mail.example.com.key
ssl_protocols = !SSLv2 !SSLv3
ssl_cipher_list = HIGH:!aNULL:!MD5
Create Mail User
# Create vmail user for virtual mailboxes
sudo groupadd -g 5000 vmail
sudo useradd -g vmail -u 5000 vmail -d /var/mail/vhosts -m
# Create mailbox directories
sudo mkdir -p /var/mail/vhosts/example.com
sudo chown -R vmail:vmail /var/mail/vhosts
# Create user (example)
sudo useradd -m -s /sbin/nologin user1
echo "password" | sudo passwd --stdin user1
# Or use virtual users (better)
โ Step 4: Security and Spam Filtering
Protect your mail server!
Configure OpenDKIM
# Install OpenDKIM
sudo dnf install -y opendkim opendkim-tools
# Configure OpenDKIM
sudo nano /etc/opendkim.conf
Mode sv
Canonicalization relaxed/simple
Domain example.com
Selector mail
KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
# Create directories
sudo mkdir -p /etc/opendkim/keys/example.com
# Generate DKIM keys
sudo opendkim-genkey -D /etc/opendkim/keys/example.com -d example.com -s mail
# Set permissions
sudo chown -R opendkim:opendkim /etc/opendkim
sudo chmod 600 /etc/opendkim/keys/example.com/mail.private
# Configure tables
echo "mail._domainkey.example.com example.com:mail:/etc/opendkim/keys/example.com/mail.private" | \
sudo tee /etc/opendkim/KeyTable
echo "*@example.com mail._domainkey.example.com" | \
sudo tee /etc/opendkim/SigningTable
echo "127.0.0.1
localhost
example.com
mail.example.com" | sudo tee /etc/opendkim/TrustedHosts
# Add to Postfix
echo "
# OpenDKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = inet:127.0.0.1:8891" | sudo tee -a /etc/postfix/main.cf
# Start OpenDKIM
sudo systemctl enable --now opendkim
# Get DKIM record for DNS
sudo cat /etc/opendkim/keys/example.com/mail.txt
# Add this to your DNS!
Configure SpamAssassin
# Install SpamAssassin
sudo dnf install -y spamassassin
# Configure SpamAssassin
sudo nano /etc/mail/spamassassin/local.cf
# Basic settings
required_score 5.0
report_safe 0
rewrite_header Subject [SPAM]
# Whitelist
whitelist_from *@example.com
# Blacklist
blacklist_from *@spam.com
# Enable service
sudo systemctl enable --now spamassassin
# Integrate with Postfix
sudo nano /etc/postfix/master.cf
# Add after smtp line:
-o content_filter=spamassassin
# Add at end:
spamassassin unix - n n - - pipe
user=spamd argv=/usr/bin/spamc -f -e
/usr/sbin/sendmail -oi -f ${sender} ${recipient}
Configure Fail2ban
# Install fail2ban
sudo dnf install -y fail2ban
# Create jail for Postfix
sudo nano /etc/fail2ban/jail.local
[postfix]
enabled = true
port = smtp,465,587
filter = postfix
logpath = /var/log/maillog
maxretry = 3
[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps
filter = dovecot
logpath = /var/log/maillog
maxretry = 3
# Start fail2ban
sudo systemctl enable --now fail2ban
๐ฎ Quick Examples
Example 1: Virtual Domain Setup ๐
#!/bin/bash
# Set up multiple email domains
setup_virtual_domain() {
DOMAIN=$1
echo "๐ง Setting up virtual domain: $DOMAIN"
# Create mailbox directory
sudo mkdir -p /var/mail/vhosts/$DOMAIN
sudo chown -R vmail:vmail /var/mail/vhosts/$DOMAIN
# Add to virtual domains
echo "$DOMAIN" | sudo tee -a /etc/postfix/vdomains
# Create virtual mailbox map
cat << EOF | sudo tee -a /etc/postfix/vmailbox
admin@$DOMAIN $DOMAIN/admin/
info@$DOMAIN $DOMAIN/info/
support@$DOMAIN $DOMAIN/support/
EOF
# Create virtual alias map
cat << EOF | sudo tee -a /etc/postfix/virtual
postmaster@$DOMAIN admin@$DOMAIN
webmaster@$DOMAIN admin@$DOMAIN
abuse@$DOMAIN admin@$DOMAIN
EOF
# Generate DKIM keys
sudo mkdir -p /etc/opendkim/keys/$DOMAIN
sudo opendkim-genkey -D /etc/opendkim/keys/$DOMAIN -d $DOMAIN -s mail
sudo chown -R opendkim:opendkim /etc/opendkim/keys/$DOMAIN
# Add to DKIM tables
echo "mail._domainkey.$DOMAIN $DOMAIN:mail:/etc/opendkim/keys/$DOMAIN/mail.private" | \
sudo tee -a /etc/opendkim/KeyTable
echo "*@$DOMAIN mail._domainkey.$DOMAIN" | \
sudo tee -a /etc/opendkim/SigningTable
# Update maps
sudo postmap /etc/postfix/vmailbox
sudo postmap /etc/postfix/virtual
sudo postmap /etc/postfix/vdomains
# Reload services
sudo systemctl reload postfix
sudo systemctl reload opendkim
echo "โ
Domain $DOMAIN configured!"
echo "๐ Add this DKIM record to DNS:"
sudo cat /etc/opendkim/keys/$DOMAIN/mail.txt
}
# Add multiple domains
setup_virtual_domain "example.com"
setup_virtual_domain "example.org"
setup_virtual_domain "example.net"
Example 2: Email Account Manager ๐ฅ
#!/bin/bash
# Manage email accounts easily
cat > /usr/local/bin/email-manager.sh << 'EOF'
#!/bin/bash
create_email_account() {
EMAIL=$1
PASSWORD=$2
# Parse email
USER=$(echo $EMAIL | cut -d@ -f1)
DOMAIN=$(echo $EMAIL | cut -d@ -f2)
echo "Creating email: $EMAIL"
# Create maildir
sudo mkdir -p /var/mail/vhosts/$DOMAIN/$USER
sudo chown -R vmail:vmail /var/mail/vhosts/$DOMAIN/$USER
# Add to virtual mailbox
echo "$EMAIL $DOMAIN/$USER/" | sudo tee -a /etc/postfix/vmailbox
sudo postmap /etc/postfix/vmailbox
# Create password hash
HASH=$(doveadm pw -s SHA512-CRYPT -p "$PASSWORD")
# Add to userdb
echo "$EMAIL:$HASH:5000:5000::/var/mail/vhosts/$DOMAIN/$USER::" | \
sudo tee -a /etc/dovecot/users
# Set quota (optional)
echo "$EMAIL:storage=1G" | sudo tee -a /etc/dovecot/quota
# Create filters
cat > /var/mail/vhosts/$DOMAIN/$USER/.dovecot.sieve << SIEVE
require ["fileinto"];
# Spam filter
if header :contains "X-Spam-Flag" "YES" {
fileinto "Spam";
stop;
}
# Archive old messages
if date :value "ge" :originalzone "date" "2024-01-01" {
fileinto "Archive";
}
SIEVE
sudo systemctl reload postfix dovecot
echo "โ
Account created: $EMAIL"
}
delete_email_account() {
EMAIL=$1
USER=$(echo $EMAIL | cut -d@ -f1)
DOMAIN=$(echo $EMAIL | cut -d@ -f2)
# Backup mailbox
sudo tar -czf /backup/$EMAIL-$(date +%Y%m%d).tar.gz \
/var/mail/vhosts/$DOMAIN/$USER
# Remove maildir
sudo rm -rf /var/mail/vhosts/$DOMAIN/$USER
# Remove from configs
sudo sed -i "/$EMAIL/d" /etc/postfix/vmailbox
sudo sed -i "/$EMAIL/d" /etc/dovecot/users
sudo postmap /etc/postfix/vmailbox
sudo systemctl reload postfix dovecot
echo "โ
Account deleted: $EMAIL (backup saved)"
}
list_accounts() {
echo "๐ง Email Accounts:"
grep "@" /etc/postfix/vmailbox | awk '{print $1}'
echo ""
echo "๐ Disk Usage:"
for domain in /var/mail/vhosts/*; do
if [ -d "$domain" ]; then
du -sh $domain/*
fi
done
}
# Menu
case $1 in
create)
create_email_account $2 $3
;;
delete)
delete_email_account $2
;;
list)
list_accounts
;;
*)
echo "Usage: $0 {create|delete|list} [email] [password]"
;;
esac
EOF
chmod +x /usr/local/bin/email-manager.sh
# Usage examples
email-manager.sh create [email protected] "SecurePass123!"
email-manager.sh create [email protected] "AnotherPass456!"
email-manager.sh list
Example 3: Mail Server Health Monitor ๐
#!/bin/bash
# Monitor mail server health
cat > /usr/local/bin/mail-monitor.py << 'EOF'
#!/usr/bin/env python3
import subprocess
import smtplib
import imaplib
import time
from email.mime.text import MIMEText
from datetime import datetime
class MailServerMonitor:
def __init__(self):
self.smtp_host = "localhost"
self.imap_host = "localhost"
self.test_email = "[email protected]"
self.test_pass = "MonitorPass123"
def test_smtp(self):
"""Test SMTP sending"""
try:
start = time.time()
# Connect to SMTP
smtp = smtplib.SMTP(self.smtp_host, 587)
smtp.starttls()
smtp.login(self.test_email, self.test_pass)
# Send test message
msg = MIMEText(f"Test at {datetime.now()}")
msg['Subject'] = 'SMTP Test'
msg['From'] = self.test_email
msg['To'] = self.test_email
smtp.send_message(msg)
smtp.quit()
elapsed = time.time() - start
print(f"โ
SMTP: OK ({elapsed:.2f}s)")
return True
except Exception as e:
print(f"โ SMTP: Failed - {e}")
return False
def test_imap(self):
"""Test IMAP retrieval"""
try:
start = time.time()
# Connect to IMAP
imap = imaplib.IMAP4_SSL(self.imap_host)
imap.login(self.test_email, self.test_pass)
# Check inbox
imap.select('INBOX')
typ, data = imap.search(None, 'ALL')
imap.close()
imap.logout()
elapsed = time.time() - start
print(f"โ
IMAP: OK ({elapsed:.2f}s)")
return True
except Exception as e:
print(f"โ IMAP: Failed - {e}")
return False
def check_queue(self):
"""Check mail queue"""
try:
result = subprocess.run(['mailq'], capture_output=True, text=True)
lines = result.stdout.strip().split('\n')
if 'Mail queue is empty' in result.stdout:
print("โ
Queue: Empty")
else:
# Count messages
count = len([l for l in lines if '@' in l])
if count > 100:
print(f"โ ๏ธ Queue: {count} messages (HIGH)")
else:
print(f"๐ฌ Queue: {count} messages")
except Exception as e:
print(f"โ Queue check failed: {e}")
def check_services(self):
"""Check service status"""
services = ['postfix', 'dovecot', 'opendkim', 'spamassassin']
for service in services:
result = subprocess.run(
['systemctl', 'is-active', service],
capture_output=True, text=True
)
if result.stdout.strip() == 'active':
print(f"โ
{service}: Running")
else:
print(f"โ {service}: Not running")
def check_disk_usage(self):
"""Check mail storage usage"""
result = subprocess.run(
['df', '-h', '/var/mail'],
capture_output=True, text=True
)
lines = result.stdout.strip().split('\n')
if len(lines) > 1:
usage = lines[1].split()[4].replace('%', '')
if int(usage) > 80:
print(f"โ ๏ธ Disk usage: {usage}% (HIGH)")
else:
print(f"๐พ Disk usage: {usage}%")
def check_blacklists(self):
"""Check if IP is blacklisted"""
import socket
import dns.resolver
# Get server IP
hostname = socket.gethostname()
ip = socket.gethostbyname(hostname)
# Reverse IP for DNSBL queries
reversed_ip = '.'.join(reversed(ip.split('.')))
blacklists = [
'zen.spamhaus.org',
'bl.spamcop.net',
'b.barracudacentral.org'
]
blacklisted = False
for bl in blacklists:
try:
query = f"{reversed_ip}.{bl}"
dns.resolver.resolve(query, 'A')
print(f"โ Blacklisted on {bl}")
blacklisted = True
except:
pass
if not blacklisted:
print("โ
Not blacklisted")
def generate_report(self):
"""Generate health report"""
print("\n๐ Mail Server Health Report")
print("=" * 40)
print(f"Time: {datetime.now()}")
print()
self.check_services()
print()
self.test_smtp()
self.test_imap()
print()
self.check_queue()
self.check_disk_usage()
self.check_blacklists()
print("=" * 40)
if __name__ == "__main__":
monitor = MailServerMonitor()
monitor.generate_report()
EOF
chmod +x /usr/local/bin/mail-monitor.py
# Add to cron
echo "*/30 * * * * /usr/local/bin/mail-monitor.py" | crontab -
๐จ Fix Common Problems
Problem 1: Emails Going to Spam โ
Recipients marking as spam?
# Check SPF record
dig TXT example.com | grep spf
# Verify DKIM signing
sudo opendkim-testkey -d example.com -s mail -vvv
# Check reverse DNS
dig -x YOUR_IP
# Test email authentication
echo "Test" | mail -s "Test" [email protected]
# Check blacklists
# Visit: https://mxtoolbox.com/blacklists.aspx
Problem 2: Canโt Send Email โ
SMTP not working?
# Check if port 25 is open
telnet gmail-smtp-in.l.google.com 25
# Check Postfix status
sudo postfix status
sudo journalctl -u postfix -n 50
# Test local delivery
echo "Test" | mail -s "Test" user@localhost
# Check logs
sudo tail -f /var/log/maillog
# Common fix: ISP blocks port 25
# Use relay host:
sudo postconf -e "relayhost = [smtp.relay.com]:587"
Problem 3: Canโt Receive Email โ
No incoming mail?
# Check MX records
dig MX example.com
# Test port 25
sudo ss -tulpn | grep :25
# Check firewall
sudo firewall-cmd --add-service=smtp --permanent
sudo firewall-cmd --reload
# Test SMTP
telnet mail.example.com 25
EHLO test
MAIL FROM: <[email protected]m>
RCPT TO: <[email protected]m>
Problem 4: Authentication Failed โ
Users canโt login?
# Check Dovecot auth
doveadm auth test [email protected]
# Check SASL
testsaslauthd -u user -p password
# Check permissions
ls -la /var/spool/postfix/private/auth
# Enable auth debugging
# In /etc/dovecot/conf.d/10-logging.conf:
auth_debug = yes
auth_verbose = yes
๐ Simple Commands Summary
Task | Command |
---|---|
๐ง Send test email | echo "Test" | mail -s "Subject" user@domain |
๐ฌ Check queue | mailq or postqueue -p |
๐ Flush queue | postqueue -f |
๐๏ธ Clear queue | postsuper -d ALL |
๐ Show config | postconf -n |
๐ Check logs | tail -f /var/log/maillog |
โ Test config | postfix check |
๐ Test DKIM | opendkim-testkey -d domain -s selector |
๐ก Tips for Success
- Start Simple ๐ฏ - Single domain first
- Test Everything ๐งช - Use mail-tester.com
- Monitor Constantly ๐ - Queues fill fast
- Backup Config ๐พ - Email is critical
- Watch Blacklists ๐ซ - Check regularly
- Document Users ๐ - Track all accounts
Pro tip: Always set up a monitoring email that forwards to your personal email. If the server fails, youโll know immediately! ๐ฑ
๐ What You Learned
Youโre now an email administrator! You can:
- โ Install and configure Postfix
- โ Set up IMAP/POP3 with Dovecot
- โ Configure SSL/TLS encryption
- โ Implement DKIM/SPF/DMARC
- โ Set up spam filtering
- โ Manage virtual domains
- โ Troubleshoot delivery issues
๐ฏ Why This Matters
Running your own mail server provides:
- ๐ฐ Unlimited email addresses
- ๐ Complete privacy control
- ๐ No storage limits
- ๐ฏ Custom filtering rules
- ๐ Data sovereignty
- ๐ช Professional independence
Last month, Google Workspace had a 4-hour outage. Our mail server? Still running after 2 years with 99.9% uptime. Plus, we save $500/month and have unlimited everything! Thatโs email freedom! ๐ง
Remember: Email is the backbone of business communication. Control your email, control your business! ๐ผ
Happy mailing! May your inbox be organized and your spam folder empty! ๐ฎโจ