Skip to content

Custom Policies

Creating advanced custom filtering policies beyond the standard configuration.

Policy Architecture

Policy Types

Connection Policies: - IP-based restrictions - Geographic filtering - Rate limiting - Greylisting

Authentication Policies: - SASL authentication rules - Relay restrictions - Sender verification

Content Policies: - Header-based filtering - Body content scanning - Attachment restrictions - Size limits

Recipient Policies: - Per-domain rules - Per-user rules - Distribution list handling

Custom Policy Files

Policy File Structure

Main policy directory:

/etc/mailborder/custom/
├── policies/
│   ├── connection.cf
│   ├── content.cf
│   ├── recipient.cf
│   └── custom.cf
├── rules/
│   ├── rspamd/
│   └── spamassassin/
└── scripts/
    └── policy-helpers/

Creating Custom Policies

Example connection policy:

sudo tee /etc/mailborder/custom/policies/connection.cf << 'EOF'
# Custom connection policies

# Block specific networks
smtpd_client_restrictions =
    check_client_access cidr:/etc/mailborder/custom/blocked_networks.cidr,
    permit

# Rate limiting by IP
smtpd_client_connection_rate_limit = 10
smtpd_client_connection_count_limit = 5
smtpd_client_event_limit_exceptions =
    192.168.1.0/24,
    10.0.0.0/8

# Greylisting exceptions
smtpd_client_restrictions =
    check_client_access hash:/etc/mailborder/custom/greylist_whitelist,
    permit
EOF

Include in main configuration:

sudo nano /etc/postfix/main.cf

# Include custom policies
import_environment = MAIL_CONFIG=/etc/mailborder/custom/policies/connection.cf

Reload configuration:

sudo postfix reload

Advanced Content Filtering

Custom Rspamd Rules

Create custom rule file:

sudo mkdir -p /etc/rspamd/local.d
sudo tee /etc/rspamd/local.d/custom_content.conf << 'EOF'
# Detect internal document leakage
INTERNAL_DOCUMENT_LEAK {
    type = "composite";
    expression = "HAS_ATTACHMENT & CONTAINS_CONFIDENTIAL";
    score = 10.0;
    description = "Potential internal document leakage";
    group = "custom_policies";
}

HAS_ATTACHMENT {
    type = "header";
    header = "Content-Type";
    regexp = "/(multipart|application)\/(mixed|octet-stream)/i";
}

CONTAINS_CONFIDENTIAL {
    type = "content";
    regexp = "/(confidential|internal only|not for distribution)/i";
}

# Detect suspicious invoice emails
FAKE_INVOICE {
    type = "composite";
    expression = "INVOICE_SUBJECT & SUSPICIOUS_SENDER & HAS_LINK";
    score = 7.5;
    description = "Suspicious invoice email";
    group = "custom_policies";
}

INVOICE_SUBJECT {
    type = "header";
    header = "Subject";
    regexp = "/(invoice|payment|bill|receipt)/i";
}

SUSPICIOUS_SENDER {
    type = "from";
    map = "file:///etc/mailborder/custom/trusted_invoice_senders.map";
    regexp = true;
    inverse = true;
}

HAS_LINK {
    type = "urls";
    regexp = "/^https?:/i";
}

# Detect phishing keywords
PHISHING_KEYWORDS {
    type = "content";
    regexp = "/(verify your account|suspended|unusual activity|click here immediately)/i";
    score = 5.0;
    description = "Common phishing keywords";
    group = "custom_policies";
}

# Company-specific policy: Block competitor domains
COMPETITOR_DOMAIN {
    type = "from";
    map = "file:///etc/mailborder/custom/competitor_domains.map";
    score = 15.0;
    description = "Email from competitor domain";
    group = "custom_policies";
}
EOF

Create supporting map files:

# Trusted invoice senders
sudo tee /etc/mailborder/custom/trusted_invoice_senders.map << 'EOF'
/@accounting\.company\.com$/
/@billing\.company\.com$/
/@invoices\.company\.com$/
EOF

# Competitor domains
sudo tee /etc/mailborder/custom/competitor_domains.map << 'EOF'
/@competitor1\.com$/
/@competitor2\.net$/
/@rival-company\.com$/
EOF

Test rules:

sudo rspamadm configtest
sudo systemctl restart rspamd

Test with sample email:

rspamc < /path/to/test/email

Advanced SpamAssassin Rules

Create custom rule file:

sudo tee /etc/spamassassin/local_custom.cf << 'EOF'
# Custom SpamAssassin rules

# Detect executive impersonation
header   CEO_IMPERSONATION  From =~ /ceo@/i
describe CEO_IMPERSONATION  Possible CEO impersonation
score    CEO_IMPERSONATION  4.0

body     CEO_REQUEST       /urgent.*transfer.*funds/i
describe CEO_REQUEST       CEO-style urgent transfer request
score    CEO_REQUEST       3.0

# Combine for higher score
meta     EXECUTIVE_FRAUD   CEO_IMPERSONATION && CEO_REQUEST
describe EXECUTIVE_FRAUD   Executive impersonation fraud attempt
score    EXECUTIVE_FRAUD   8.0

# Block known malicious patterns
body     MALICIOUS_MACRO   /Document_\d{8}\.doc/
describe MALICIOUS_MACRO   Malicious macro document pattern
score    MALICIOUS_MACRO   6.0

# Detect credential phishing
uri      PHISHING_PORTAL   /login.*verify/i
describe PHISHING_PORTAL   Credential phishing portal
score    PHISHING_PORTAL   5.0

# Custom scoring for internal use
header   EXTERNAL_SENDER   X-Mailborder-External =~ /true/
describe EXTERNAL_SENDER   External sender
score    EXTERNAL_SENDER   0.5

header   NO_SPF            X-Mailborder-SPF =~ /none/
describe NO_SPF            No SPF record
score    NO_SPF            1.0

# Combination rules
meta     EXTERNAL_NO_AUTH  EXTERNAL_SENDER && NO_SPF && !DKIM_VALID
describe EXTERNAL_NO_AUTH  External sender with no authentication
score    EXTERNAL_NO_AUTH  3.0
EOF

sudo systemctl restart spamassassin

Test rules:

spamassassin --lint
echo "From: ceo@company.com\nSubject: Urgent transfer funds\n\nPlease transfer funds immediately." | \
  spamassassin -t

Scripted Policies

Policy Service Protocol

Create custom policy daemon:

sudo tee /usr/local/bin/mb-policy-daemon.py << 'EOF'
#!/usr/bin/env python3
import sys
import socket

def check_policy(request):
    """
    Custom policy logic
    Returns: 'DUNNO', 'OK', 'REJECT reason', 'DEFER_IF_PERMIT reason'
    """
    params = {}
    for line in request.split('\n'):
        if '=' in line:
            key, value = line.split('=', 1)
            params[key] = value

    # Example: Block emails from specific sender during business hours
    import datetime
    hour = datetime.datetime.now().hour
    sender = params.get('sender', '')

    if 9 <= hour <= 17 and 'spam' in sender:
        return 'REJECT Sender blocked during business hours'

    # Example: Require authentication for external senders
    if params.get('sasl_username', '') == '':
        client_address = params.get('client_address', '')
        if not client_address.startswith('192.168.'):
            return 'REJECT Authentication required'

    # Example: Rate limit per sender
    sender_count = get_sender_count(sender)  # Implement counting logic
    if sender_count > 100:
        return 'DEFER_IF_PERMIT Rate limit exceeded'

    return 'DUNNO'  # No action, continue processing

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('127.0.0.1', 10040))
    sock.listen(5)

    while True:
        conn, addr = sock.accept()
        request = ''

        while True:
            data = conn.recv(4096).decode('utf-8')
            if not data:
                break
            request += data
            if '\n\n' in request:
                break

        response = check_policy(request)
        conn.sendall(f'action={response}\n\n'.encode('utf-8'))
        conn.close()

if __name__ == '__main__':
    main()
EOF

sudo chmod +x /usr/local/bin/mb-policy-daemon.py

Create SystemD service:

sudo tee /etc/systemd/system/mb-policy-daemon.service << 'EOF'
[Unit]
Description=Mailborder Custom Policy Daemon
After=network.target

[Service]
Type=simple
User=mailborder
ExecStart=/usr/local/bin/mb-policy-daemon.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable mb-policy-daemon
sudo systemctl start mb-policy-daemon

Configure Postfix to use policy service:

sudo nano /etc/postfix/main.cf

smtpd_recipient_restrictions =
    permit_mynetworks,
    permit_sasl_authenticated,
    check_policy_service inet:127.0.0.1:10040,
    reject_unauth_destination

Test policy service:

sudo postfix reload
telnet localhost 10040

Type:

request=smtpd_access_policy
protocol_state=RCPT
protocol_name=ESMTP
client_address=203.0.113.5
client_name=unknown
sender=spam@example.com
recipient=user@yourdomain.com
sasl_username=

Press Enter twice to see response.

Domain-Specific Policies

Per-Domain Filtering

Create domain policy file:

sudo tee /etc/mailborder/custom/domain_policies.cf << 'EOF'
# Domain-specific policies

# Strict filtering for executives
/^ceo@company\.com$/     FILTER smtp:[127.0.0.1]:10050
/^cfo@company\.com$/     FILTER smtp:[127.0.0.1]:10050

# Relaxed filtering for partners
/^.*@partner1\.com$/     FILTER smtp:[127.0.0.1]:10051
/^.*@partner2\.com$/     FILTER smtp:[127.0.0.1]:10051

# Quarantine-only for testing
/^.*@test\.company\.com$/ FILTER smtp:[127.0.0.1]:10052
EOF

postmap /etc/mailborder/custom/domain_policies.cf

Configure Postfix:

sudo nano /etc/postfix/main.cf

recipient_bcc_maps = regexp:/etc/mailborder/custom/domain_policies.cf

Executive Protection Policy

Enhanced filtering for executives:

sudo tee /etc/mailborder/custom/policies/executive.cf << 'EOF'
# Executive protection policy

# Stricter spam threshold
spam_threshold_executive = 3.0  # vs 5.0 standard

# Block all external executables
attachment_extensions_blocked = exe,com,bat,cmd,scr,vbs,js,jar,zip

# Require authentication for external senders
require_spf = pass
require_dkim = pass
require_dmarc = pass

# Enhanced phishing detection
check_url_reputation = strict
check_sender_reputation = strict

# Alert on suspicious patterns
alert_on_keyword = urgent,wire transfer,verify account,suspended

# Quarantine questionable emails instead of rejecting
action_suspicious = quarantine
action_threshold = 2.0
EOF

Implement in Rspamd:

sudo tee /etc/rspamd/local.d/settings.conf << 'EOF'
executive {
    priority = high;
    rcpt = ["ceo@company.com", "cfo@company.com"];

    apply {
        actions {
            reject = 3.0;      # Stricter than default 15.0
            add_header = 2.0;  # Stricter than default 6.0
            greylist = 1.0;
        }

        symbols {
            PHISHING_KEYWORDS.weight = 8.0;  # Increase weight
            EXECUTIVE_FRAUD.weight = 10.0;
        }
    }
}
EOF

sudo systemctl restart rspamd

Time-Based Policies

Business Hours Filtering

Create time-based policy script:

sudo tee /usr/local/bin/mb-time-policy.sh << 'EOF'
#!/bin/bash

HOUR=$(date +%H)
DAY=$(date +%u)  # 1=Monday, 7=Sunday

# Business hours: Mon-Fri 9am-5pm
if [ $DAY -le 5 ] && [ $HOUR -ge 9 ] && [ $HOUR -lt 17 ]; then
    echo "business_hours"
else
    echo "after_hours"
fi
EOF

sudo chmod +x /usr/local/bin/mb-time-policy.sh

Implement in Rspamd:

sudo tee /etc/rspamd/local.d/time_policy.conf << 'EOF'
AFTER_HOURS_EXTERNAL {
    type = "composite";
    expression = "TIME_AFTER_HOURS & EXTERNAL_SENDER";
    score = 2.0;
    description = "External email received after hours";
    group = "custom_policies";
}

TIME_AFTER_HOURS {
    type = "lua";
    script = [[
        return function(task)
            local hour = tonumber(os.date("%H"))
            local day = tonumber(os.date("%w"))

            if day == 0 or day == 6 then
                return true  -- Weekend
            end

            if hour < 9 or hour >= 17 then
                return true  -- After hours
            end

            return false
        end
    ]];
}
EOF

sudo systemctl restart rspamd

Geographic Policies

Regional Filtering

Block specific countries except for partners:

sudo tee /etc/mailborder/custom/geo_policy.cf << 'EOF'
# Geographic policies

# High-risk countries (higher spam score)
high_risk_countries = CN,RU,NG,BR,IN

# Blocked countries (reject)
blocked_countries = KP,IR

# Trusted partners (whitelist by country + domain)
trusted_partners = UK:partner-uk.com,DE:partner-de.com

# Scoring
score_high_risk = 3.0
score_medium_risk = 1.5
score_low_risk = 0.5
EOF

Implement in custom script:

sudo tee /usr/local/bin/mb-geo-policy.py << 'EOF'
#!/usr/bin/env python3
import sys
import maxminddb

def check_ip(ip_address):
    reader = maxminddb.open_database('/var/lib/mailborder/geoip/GeoLite2-Country.mmdb')
    result = reader.get(ip_address)
    reader.close()

    if result:
        country = result.get('country', {}).get('iso_code', '')

        # Block list
        if country in ['KP', 'IR']:
            return 'REJECT Country blocked'

        # High risk list
        if country in ['CN', 'RU', 'NG', 'BR', 'IN']:
            return 'PREPEND X-Mailborder-Risk: high'

    return 'DUNNO'

if __name__ == '__main__':
    ip = sys.argv[1] if len(sys.argv) > 1 else '8.8.8.8'
    print(check_policy(ip))
EOF

sudo chmod +x /usr/local/bin/mb-geo-policy.py

Attachment Policies

Advanced Attachment Filtering

Create attachment policy:

sudo tee /etc/mailborder/custom/attachment_policy.cf << 'EOF'
# Attachment policies

# Block dangerous extensions
blocked_extensions = exe,com,bat,cmd,scr,pif,vbs,js,jar,msi,dll

# Size limits by type
max_size_executable = 0          # Block all
max_size_archive = 10485760      # 10MB
max_size_document = 52428800     # 50MB
max_size_image = 10485760        # 10MB

# Scan archives
scan_zip = yes
scan_rar = yes
scan_7z = yes
max_archive_depth = 3

# Document macro detection
block_office_macros = yes
allow_signed_macros = yes

# Quarantine suspicious attachments
action_suspicious_attachment = quarantine
action_blocked_extension = reject
EOF

Implement in ClamAV:

sudo tee -a /etc/clamav/clamd.conf << 'EOF'
# Custom attachment policies
ArchiveBlockEncrypted yes
AlertBrokenExecutables yes
AlertExceedsMax yes
MaxScanSize 100M
MaxFileSize 50M
MaxRecursion 5
MaxFiles 1000
EOF

sudo systemctl restart clamd@scan

Machine Learning Policies

Bayesian Learning Integration

Train Bayes filter:

# Train on spam corpus
sudo sa-learn --spam /var/spool/mailborder/spam-corpus/

# Train on ham corpus
sudo sa-learn --ham /var/spool/mailborder/ham-corpus/

# Check statistics
sudo sa-learn --dump magic

Auto-learning configuration:

sudo tee -a /etc/spamassassin/local.cf << 'EOF'
# Bayesian auto-learning
bayes_auto_learn 1
bayes_auto_learn_threshold_nonspam -0.1
bayes_auto_learn_threshold_spam 6.0
bayes_auto_learn_on_error 1

# Increase Bayes weight for custom policy
score BAYES_99 4.5
score BAYES_95 3.5
score BAYES_80 2.5
EOF

sudo systemctl restart spamassassin

Policy Testing

Test Custom Policies

Create test email:

cat > /tmp/test-email.eml << 'EOF'
From: test@example.com
To: admin@yourdomain.com
Subject: Test Policy Email

This is a test email to verify custom policies.
Keyword: urgent
Keyword: verify account
EOF

Test with Rspamd:

rspamc < /tmp/test-email.eml

Test with SpamAssassin:

spamassassin -t < /tmp/test-email.eml

Test policy daemon:

echo -e "sender=spam@test.com\n\n" | nc localhost 10040

Policy Documentation

Document all custom policies:

sudo tee /etc/mailborder/custom/README.md << 'EOF'
# Custom Mailborder Policies

## Active Policies

### Executive Protection
- File: `policies/executive.cf`
- Purpose: Enhanced filtering for executive accounts
- Threshold: 3.0 (vs 5.0 standard)

### Geographic Filtering
- File: `geo_policy.cf`
- Purpose: Block/score based on country
- High-risk: CN, RU, NG, BR, IN
- Blocked: KP, IR

### Time-Based Filtering
- File: `time_policy.conf`
- Purpose: Additional scrutiny for after-hours emails
- Business hours: Mon-Fri 9am-5pm

### Content Policies
- File: `custom_content.conf`
- Purpose: Detect internal document leakage, fake invoices
- Rules: INTERNAL_DOCUMENT_LEAK, FAKE_INVOICE

## Maintenance

Last updated: 2025-11-12
Review schedule: Quarterly
Contact: admin@company.com
EOF

See Also