Postfix

This role installs and configures Postfix as an SMTP relay for sending system emails through an external mail server.

ARA Ansible Bash Centreon DNS Debian Postfix SMTP

Postfix Role

Overview

This role installs and configures Postfix as an SMTP relay for sending system emails through an external mail server. It sets up SASL authentication, TLS encryption, header rewriting for proper sender display names, and configures the main Postfix configuration file. The role is designed for systems that need to send notification emails (like Centreon alerts) via a relay host such as Gmail, Office 365, or a dedicated SMTP server.

Purpose

  • SMTP Relay: Send system emails through external mail server
  • Centreon Notifications: Enable alert emails from monitoring system
  • SASL Authentication: Authenticate to relay with username/password
  • TLS Encryption: Secure email transmission
  • Header Rewriting: Set proper display name for sender
  • System Email: Enable mail command for scripts and services
  • Automated Configuration: Deploy consistent mail config across hosts

Requirements

  • Ansible 2.9 or higher
  • Target system: Debian/Ubuntu or FreeBSD
  • Root or sudo privileges
  • Internet connectivity (to install packages and send mail)
  • SMTP relay credentials (stored in Ansible Vault)
  • Relay host accessible from target system

What is an SMTP Relay?

SMTP relay forwards email from local system to external mail server:

Without relay:

System tries to send directly to recipient's mail server

Often blocked by ISP, firewalls, or spam filters

Email fails to deliver

With relay:

System → Postfix → SMTP Relay (Gmail/Office365) → Recipient

Authenticated, properly configured sender

Email delivered successfully

Common relay providers:

  • Gmail: smtp.gmail.com:587
  • Office 365: smtp.office365.com:587
  • SendGrid: smtp.sendgrid.net:587
  • Custom SMTP server

Role Variables

Required Variables

VariableRequiredDescription
postfix_smtp_hostYesSMTP relay hostname
postfix_smtp_portYesSMTP relay port
postfix_sender_emailYesSender email address
postfix_sender_passwordYesSMTP authentication password (in vault)
postfix_myhostnameYesSystem hostname for mail

Optional Variables

VariableDefaultDescription
postfix_sender_display_nameCentreon HomelabDisplay name in From field
postfix_smtp_use_tlsyesEnable TLS encryption
postfix_smtp_sasl_auth_enableyesEnable SASL authentication
postfix_smtp_sasl_security_optionsnoanonymousSASL security options
postfix_smtp_sasl_tls_security_optionsnoanonymousSASL TLS security options
postfix_config_path/etc/postfixPostfix config directory
postfix_password_maps_filesasl_passwdSASL password filename
postfix_header_checks_filesmtp_header_checksHeader checks filename

Variable Details

postfix_smtp_host

SMTP relay server hostname.

Examples:

postfix_smtp_host: smtp.gmail.com        # Gmail
postfix_smtp_host: smtp.office365.com    # Office 365
postfix_smtp_host: mail.example.com      # Custom server

postfix_smtp_port

SMTP relay server port.

Common ports:

  • 587: STARTTLS (recommended)
  • 465: SMTPS (SSL/TLS wrapper)
  • 25: Plain SMTP (usually blocked)

Recommended: 587 with TLS

postfix_sender_email

Email address used for authentication and as sender.

Examples:

postfix_sender_email: notifications@example.com
postfix_sender_email: admin@example.com

Note: Must match relay authentication account.

postfix_sender_password

Password for SMTP authentication.

IMPORTANT: Store in Ansible Vault

# In vault.yml
vault_postfix_sender_password: your_secure_password

# In playbook
postfix_sender_password: "{{ vault_postfix_sender_password }}"

Gmail: Use app password, not account password

postfix_sender_display_name

Human-readable name shown in email client.

Default: Centreon Homelab

Examples:

postfix_sender_display_name: "Server Alerts"
postfix_sender_display_name: "Homelab Monitoring"
postfix_sender_display_name: "IT Notifications"

Result: Email shows as:

From: "Homelab Monitoring" <notifications@example.com>

postfix_myhostname

Hostname used in SMTP HELO/EHLO and headers.

Examples:

postfix_myhostname: centreon.homelab.local
postfix_myhostname: "{{ ansible_fqdn }}"
postfix_myhostname: "{{ inventory_hostname }}"

Best practice: Use FQDN (fully qualified domain name)

Dependencies

No Ansible role dependencies, but requires:

  • Internet connectivity for package installation
  • SMTP relay account credentials
  • Network access to relay host (port 587/465)

Often used with:

  • deploy_centreon: Centreon monitoring system
  • rsyslog_configuration: Log forwarding
  • System services: Cron, monitoring tools

Example Playbook

Basic Gmail Relay

---
- name: Configure Postfix SMTP Relay
  hosts: centreon
  become: true

  vars:
    postfix_smtp_host: smtp.gmail.com
    postfix_smtp_port: 587
    postfix_sender_email: admin@example.com
    postfix_sender_password: "{{ vault_gmail_app_password }}"
    postfix_myhostname: centreon.homelab.local

  roles:
    - postfix

Office 365 Relay

---
- name: Configure Postfix with Office 365
  hosts: all
  become: true

  vars:
    postfix_smtp_host: smtp.office365.com
    postfix_smtp_port: 587
    postfix_sender_email: admin@example.com
    postfix_sender_password: "{{ vault_o365_password }}"
    postfix_myhostname: "{{ ansible_fqdn }}"
    postfix_sender_display_name: "Company Alerts"

  roles:
    - postfix

Custom SMTP Server

---
- name: Configure Postfix with Custom Relay
  hosts: servers
  become: true

  vars:
    postfix_smtp_host: mail.example.com
    postfix_smtp_port: 587
    postfix_sender_email: noreply@example.com
    postfix_sender_password: "{{ vault_smtp_password }}"
    postfix_myhostname: "{{ inventory_hostname }}.example.com"

  roles:
    - postfix

What This Role Does

  1. Install packages:

    • postfix: SMTP server/relay
    • postfix-pcre: Perl regex support (header rewriting)
    • s-nail: Mail command utility
    • cyrus-sasl-plain: SASL PLAIN authentication
  2. Configure SASL password:

    • Creates sasl_passwd with relay credentials
    • Format: [relay:port] user:password
    • Sets permissions: 0600 (root only)
    • Runs postmap to create hash database
  3. Configure header checks:

    • Creates smtp_header_checks for From rewriting
    • Rewrites centreon-engine emails with display name
    • Uses PCRE regex matching
  4. Configure main.cf:

    • Sets relay host and port
    • Enables TLS and SASL authentication
    • References password maps and header checks
    • Sets system hostname
  5. Restart Postfix:

    • Restarts service to apply changes
    • Enables Postfix on boot

Installed Packages

postfix

Main SMTP server and relay.

What it does:

  • Accepts local mail from system
  • Relays to external SMTP server
  • Handles queuing and retries

postfix-pcre

Perl Compatible Regular Expression support.

What it does:

  • Enables regex in header_checks
  • Allows complex pattern matching
  • Used for From header rewriting

s-nail

Mail command utility (formerly mailx).

What it does:

  • Provides mail command for scripts
  • Send email from command line
  • Used by cron, monitoring, scripts

Example:

echo "Test message" | mail -s "Test Subject" user@example.com

cyrus-sasl-plain

SASL PLAIN authentication mechanism.

What it does:

  • Enables username/password authentication
  • Required for SMTP relay authentication
  • Secure when used with TLS

Configuration Files

sasl_passwd

Location: /etc/postfix/sasl_passwd

Content:

[smtp.gmail.com]:587 admin@example.com:app_password_here

Permissions: 0600 (root only)

Hash database: Created by postmap sasl_passwd

  • Generates: sasl_passwd.db
  • Used by Postfix for authentication

smtp_header_checks

Location: /etc/postfix/smtp_header_checks

Content:

# Rewrite From header for centreon-engine emails
/^From:.*centreon-engine/ REPLACE From: "Centreon Homelab" <admin@example.com>

How it works:

  1. Match emails with centreon-engine in From header
  2. Replace entire From line with display name and email
  3. Other emails pass through unchanged

Why needed: Centreon sends emails as centreon-engine@localhost, which looks unprofessional and may trigger spam filters.

main.cf

Location: /etc/postfix/main.cf

Key settings:

myhostname = centreon.homelab.local
relayhost = [smtp.gmail.com]:587
smtp_use_tls = yes
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_tls_security_options = noanonymous
smtp_header_checks = pcre:/etc/postfix/smtp_header_checks

SASL Authentication

SASL (Simple Authentication and Security Layer) authenticates to relay server.

Authentication Flow

1. Client: EHLO
2. Server: 250-STARTTLS, 250-AUTH PLAIN LOGIN
3. Client: STARTTLS
4. [TLS negotiation]
5. Client: AUTH PLAIN [base64(user:pass)]
6. Server: 235 Authentication successful
7. Client: MAIL FROM, RCPT TO, DATA

SASL Options

noanonymous: Don’t allow anonymous authentication

  • Requires username/password
  • More secure

Other options:

  • noplaintext: Require encryption
  • nodictionary: Prevent dictionary attacks
  • noactive: Prevent active attacks

TLS Encryption

TLS (Transport Layer Security) encrypts SMTP connection.

STARTTLS vs SMTPS

STARTTLS (Port 587):

1. Connect on plain port
2. Send STARTTLS command
3. Upgrade to encrypted connection
4. Continue with SMTP

SMTPS (Port 465):

1. Connect with immediate TLS
2. Entire connection encrypted
3. No upgrade negotiation

Recommended: STARTTLS on port 587

Testing the Configuration

Test Postfix Config

# Check Postfix configuration syntax
postfix check

# Should output nothing if config is valid

Send Test Email

# Using mail command
echo "Test message body" | mail -s "Test Subject" recipient@example.com

# Using sendmail
echo -e "Subject: Test\n\nTest message" | sendmail recipient@example.com

Check Mail Queue

# View mail queue
mailq

# Should show either empty queue or queued messages

View Mail Logs

# Debian/Ubuntu
tail -f /var/log/mail.log

# FreeBSD
tail -f /var/log/maillog

# Look for:
# - "status=sent" (successful)
# - "authentication failed" (auth problem)
# - "connection timed out" (network problem)

Test SMTP Connection

# Test connection to relay
telnet smtp.gmail.com 587

# Should see:
# 220 smtp.gmail.com ESMTP

# Type: EHLO test
# Should see: 250-STARTTLS

Security Considerations

  • Vault Credentials: Store passwords in Ansible Vault
  • File Permissions: sasl_passwd is 0600 (root only)
  • TLS Required: Always use TLS for authentication
  • App Passwords: Use app passwords for Gmail (not account password)
  • Relay Authentication: SASL prevents open relay abuse
  • Header Rewriting: Verify sender address authorized by relay
  • Network Security: Ensure firewall allows outbound 587/465
  • Log Monitoring: Watch for authentication failures

Gmail-Specific Configuration

Enable App Passwords

  1. Enable 2FA on Google account

  2. Generate app password:

    • Google Account → Security
    • 2-Step Verification → App passwords
    • Select “Mail” and device
    • Copy 16-character password
  3. Use app password in Ansible Vault:

vault_postfix_sender_password: "abcd efgh ijkl mnop"

Gmail Rate Limits

Limits:

  • 500 emails per day (free accounts)
  • 2,000 emails per day (Google Workspace)
  • 100 recipients per message

For homelab: Limits are typically sufficient

Office 365 Configuration

Enable SMTP Authentication

  1. Admin Center → Users → Active users
  2. Select user → Mail → Manage email apps
  3. Enable Authenticated SMTP

Conditional Access

May need to:

  • Allow legacy authentication for SMTP
  • Create app password (if MFA enabled)
  • Add sender to SPF/DKIM records (for best deliverability)

Troubleshooting

Authentication failed

Log shows:

status=deferred (SASL authentication failed)

Causes:

  • Wrong username/password
  • App password not enabled (Gmail)
  • SMTP auth disabled (Office 365)

Solutions:

  • Verify credentials in vault
  • Enable app password (Gmail)
  • Enable SMTP auth (Office 365)
  • Test credentials manually:
# Test authentication
swaks --to test@example.com \
  --from admin@example.com \
  --server smtp.gmail.com:587 \
  --auth LOGIN \
  --auth-user admin@example.com \
  --auth-password "your_password" \
  --tls

Connection timeout

Log shows:

connect to smtp.gmail.com[...]:587: Connection timed out

Causes:

  • Firewall blocking outbound SMTP
  • ISP blocking port 587
  • Network connectivity issue

Solutions:

# Test connectivity
telnet smtp.gmail.com 587
nc -zv smtp.gmail.com 587

# Check firewall rules
iptables -L OUTPUT

TLS handshake failed

Log shows:

TLS library problem

Causes:

  • Outdated CA certificates
  • TLS version mismatch

Solutions:

# Update CA certificates
apt update && apt install ca-certificates  # Debian/Ubuntu
pkg install ca_root_nss                    # FreeBSD

Emails in queue

Check queue:

mailq

Flush queue (retry delivery):

postqueue -f

Delete stuck messages:

# Delete all in queue
postsuper -d ALL

# Delete specific message
postsuper -d <queue-id>

Wrong sender name

Issue: Email shows wrong From name

Check header checks:

cat /etc/postfix/smtp_header_checks

Test regex:

# Create test file
echo "From: centreon-engine@localhost" > /tmp/test

# Test header_checks
postmap -q "From: centreon-engine@localhost" pcre:/etc/postfix/smtp_header_checks

Reload Postfix:

postfix reload

Tags

This role does not define any tags. Use playbook-level tags if needed:

- hosts: all
  roles:
    - postfix
  tags:
    - postfix
    - mail
    - smtp
    - notifications

Notes

  • Role runs on target system (not localhost)
  • become: true required for package installation and config
  • Postfix service enabled and started automatically
  • SASL password file hashed with postmap
  • Header checks use PCRE regex (requires postfix-pcre)
  • Configuration applied with Postfix restart
  • Compatible with Debian/Ubuntu and FreeBSD

Best Practices

  1. Use Vault: Always store passwords in Ansible Vault
  2. App Passwords: Use app passwords for Gmail (not main password)
  3. TLS Required: Always enable TLS for authentication security
  4. Test First: Test relay credentials manually before deploying
  5. Monitor Logs: Watch mail logs after deployment
  6. Queue Monitoring: Set up alerts for stuck mail queue
  7. Rate Limits: Be aware of relay provider limits
  8. SPF/DKIM: Configure DNS records for better deliverability
  9. Backup Config: Store Postfix config in version control
  10. Regular Updates: Keep Postfix and SASL libraries updated

This role is often used with:

  • deploy_centreon: Centreon monitoring (needs email alerts)
  • rsyslog_configuration: System logging
  • System services: Any service sending notifications

License

MIT

Author

Created for homelab infrastructure management.