Setting Postfix for outbound email via SMTP with local root delivery for cron reports

emailemail-bounceslocalpostfixsmtp

I recently had to diagnose a couple of servers running Postfix which emailed results of rsync cronjobs when they returned a non-OK value.

While Postfix was emailing the recipients on rsync failure, I noticed that the cronjob STDOUT was not being locally relayed correctly to the root mail. This is the old Ubuntu box running Postfix 2:

Dec  3 09:30:01 server01 postfix/pickup[10499]: B5A2B780C7F: uid=0 from=<root>
Dec  3 09:30:01 server01 postfix/cleanup[23133]: B5A2B780C7F: message-id=<20181205093001.B5A2B780C7F@server.fqdn.tld>
Dec  3 09:30:01 server01 postfix/qmgr[23780]: B5A2B780C7F: from=<root@server.fqdn.tld>, size=1969, nrcpt=1 (queue active)
Dec  3 09:30:02 server01 postfix/smtp[23135]: B5A2B780C7F: to=<root@localhost.fqdn.tld>, orig_to=<root>, relay=smtp.fqdn.tld[1.2.3.4]:25, delay=0.7, delays=0.26/0.01/0.02/0.42, dsn=2.6.0, status=sent (250 2.6.0 <20181205093001.B5A2B780C7F@server.fqdn.tld> [InternalId=244571470] Queued mail for delivery)
Dec  3 09:30:02 server01 postfix/qmgr[23780]: B5A2B780C7F: removed
Dec  3 10:00:06 server01 postfix/pickup[15878]: 5D0B8780C7F: uid=0 from=<root>
Dec  3 10:00:06 server01 postfix/cleanup[22344]: 5D0B8780C7F: message-id=<20181205100006.5D0B8780C7F@server.fqdn.tld>
Dec  3 10:00:06 server01 postfix/qmgr[23780]: 5D0B8780C7F: from=<root@server.fqdn.tld>, size=2198, nrcpt=1 (queue active)

The other server, a new CentOS build with Postfix 3, was logging errors slightly differently:

Dec  3 22:02:48 server02 postfix/pickup[20144]: 9491960138: uid=0 from=<root>
Dec  3 22:02:48 server02 postfix/cleanup[26411]: 9491960138: message-id=<20181203220248.9491960138@server02.fqdn.tld>
Dec  3 22:02:48 server02 postfix/qmgr[21628]: 9491960138: from=<root@fqdn.tld>, size=2541, nrcpt=1 (queue active)
Dec  3 22:02:48 server02 postfix/cleanup[26411]: 98BF0600D6: message-id=<20181203220248.9491960138@server02.fqdn.tld>
Dec  3 22:02:48 server02 postfix/qmgr[21628]: 98BF0600D6: from=<root@fqdn.tld>, size=2689, nrcpt=1 (queue active)
Dec  3 22:02:48 server02 postfix/local[26414]: 9491960138: to=<root@localhost>, orig_to=<root>, relay=local, delay=167, delays=167/0.01/0/0, dsn=2.0.0, status=sent (forwarded as 98BF0600D6)
Dec  3 22:02:48 server02 postfix/qmgr[21628]: 9491960138: removed
Dec  3 22:02:48 server02 postfix/local[26414]: 98BF0600D6: to=<root@localhost>, orig_to=<root>, relay=local, delay=0.02, delays=0/0/0/0.01, dsn=5.4.6, status=bounced (mail forwarding loop for root@localhost)
Dec  3 22:02:48 server02 postfix/cleanup[26411]: 9D80F60139: message-id=<20181203220248.9D80F60139@server02.fqdn.tld>
Dec  3 22:02:48 server02 postfix/qmgr[21628]: 9D80F60139: from=<>, size=4684, nrcpt=1 (queue active)
Dec  3 22:02:48 server02 postfix/cleanup[26411]: 9E9ED6013A: message-id=<20181203220248.9D80F60139@server02.fqdn.tld>
Dec  3 22:02:48 server02 postfix/bounce[26416]: 98BF0600D6: sender non-delivery notification: 9D80F60139
Dec  3 22:02:48 server02 postfix/qmgr[21628]: 98BF0600D6: removed
Dec  3 22:02:48 server02 postfix/qmgr[21628]: 9E9ED6013A: from=<>, size=4832, nrcpt=1 (queue active)
Dec  3 22:02:48 server02 postfix/local[26415]: 9D80F60139: to=<root@localhost>, orig_to=<root@fqdn.tld>, relay=local, delay=0.01, delays=0/0/0/0, dsn=2.0.0, status=sent (forwarded as 9E9ED6013A)
Dec  3 22:02:48 server02 postfix/qmgr[21628]: 9D80F60139: removed
Dec  3 22:02:48 server02 postfix/local[26414]: 9E9ED6013A: to=<root@localhost>, orig_to=<root@fqdn.tld>, relay=local, delay=0.01, delays=0/0/0/0, dsn=5.4.6, status=bounced (mail forwarding loop for root@localhost)
Dec  3 22:02:48 server02 postfix/qmgr[21628]: 9E9ED6013A: removed
Dec  3 22:30:05 server02 postfix/pickup[20144]: C776360138: uid=0 from=<root>
Dec  3 22:30:05 server02 postfix/cleanup[10175]: C776360138: message-id=<20181203223005.C776360138@server02.fqdn.tld>
Dec  3 22:30:05 server02 postfix/qmgr[21628]: C776360138: from=<root@fqdn.tld>, size=2172, nrcpt=1 (queue active)
Dec  3 22:30:05 server02 postfix/cleanup[10175]: CBB5D600D6: message-id=<20181203223005.C776360138@server02.fqdn.tld>
Dec  3 22:30:05 server02 postfix/qmgr[21628]: CBB5D600D6: from=<root@fqdn.tld>, size=2320, nrcpt=1 (queue active)
Dec  3 22:30:05 server02 postfix/local[10178]: C776360138: to=<root@localhost>, orig_to=<root>, relay=local, delay=4.1, delays=4.1/0.01/0/0, dsn=2.0.0, status=sent (forwarded as CBB5D600D6)
Dec  3 22:30:05 server02 postfix/qmgr[21628]: C776360138: removed
Dec  3 22:30:05 server02 postfix/local[10178]: CBB5D600D6: to=<root@localhost>, orig_to=<root>, relay=local, delay=0.02, delays=0/0/0/0.01, dsn=5.4.6, status=bounced (mail forwarding loop for root@localhost)
Dec  3 22:30:05 server02 postfix/cleanup[10175]: D04C460139: message-id=<20181203223005.D04C460139@server02.fqdn.tld>
Dec  3 22:30:05 server02 postfix/qmgr[21628]: D04C460139: from=<>, size=4315, nrcpt=1 (queue active)
Dec  3 22:30:05 server02 postfix/cleanup[10175]: D14146013A: message-id=<20181203223005.D04C460139@server02.fqdn.tld>
Dec  3 22:30:05 server02 postfix/bounce[10180]: CBB5D600D6: sender non-delivery notification: D04C460139
Dec  3 22:30:05 server02 postfix/qmgr[21628]: CBB5D600D6: removed
Dec  3 22:30:05 server02 postfix/qmgr[21628]: D14146013A: from=<>, size=4463, nrcpt=1 (queue active)
Dec  3 22:30:05 server02 postfix/local[10179]: D04C460139: to=<root@localhost>, orig_to=<root@fqdn.tld>, relay=local, delay=0.01, delays=0/0/0/0, dsn=2.0.0, status=sent (forwarded as D14146013A)
Dec  3 22:30:05 server02 postfix/qmgr[21628]: D04C460139: removed
Dec  3 22:30:05 server02 postfix/local[10178]: D14146013A: to=<root@localhost>, orig_to=<root@fqdn.tld>, relay=local, delay=0.01, delays=0/0/0/0, dsn=5.4.6, status=bounced (mail forwarding loop for root@localhost)
Dec  3 22:30:05 server02 postfix/qmgr[21628]: D14146013A: removed

These Postfix installs were able to send emails via SMTP relay to users on the corporate domain. But how to fix the local root reports not being locally delivered?

Best Answer

(In these examples, I've anonymised hostnames and changed external domains to fqdn.tld).

Prerequisites:

On both servers,

  • /etc/aliases already contained a root: root entry
  • /etc/postfix/virtual contained root root@localhost and
  • /etc/postfix/generic already contained sending aliases for the machines (e.g., root@server02.fqdn.tld server02@fqdn.tld

The aliases, virtual and generic files require a postmap after any changes as Postfix uses the hashed db version when running.

The original Postfix config:

relayhost = smtp.fqdn.tld
myhostname = server01.fqdn.tld
mydomain = fqdn.tld
myorigin = $myhostname
mydestination = $myhostname localhost.$myhostname localhost
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination

mynetworks_style = host
inet_interfaces = loopback-only
mydestination = $myhostname, localhost.$mydomain, $mydomain, fqdn.tld, fqdn2.tld
alias_maps = hash:/etc/aliases
virtual_alias_maps = hash:/etc/postfix/virtual
smtp_generic_maps = hash:/etc/postfix/generic

While this meant the box was able to send mail to recipients in the corporate domain, all local emails to the root mailbox (/var/spool/mail/root) weren't making it.

I spotted an early mistake in the myorigin and mydestination values (they were too explicit, and also mentioned external domains, which may have been confusing local delivery attempts) so I revised those. I also cleaned up the other options.

This is the working config I settled on for the Postfix 2.7 box, with a few comments for other useful stuff (like explicitly defining IPv4/IPv6 interfaces, or disabling Postfix 3 backward configuration compatibility. Happily, the Postfix 3.3 box also works with the same config.

relayhost = smtp.fqdn.tld
myhostname = server01.fqdn.tld
mydomain = fqdn.tld
myorigin = $myhostname
mydestination = $myhostname, localhost.$mydomain, localhost
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination

mynetworks_style = host
# host makes the mynetworks unnecessary - defining mynetworks overrides mynetworks_style
#mynetworks = 127.0.0.0/8, 1.2.3.4/32
# http://www.postfix.org/BASIC_CONFIGURATION_README.html

inet_interfaces = loopback-only
#inet_interfaces = 127.0.0.1, 1.2.3.4,
# ::1
# https://serverfault.com/questions/452350/how-to-completely-disable-ipv6-for-loopback-interface-on-rhel-5-6

alias_maps = hash:/etc/aliases
virtual_alias_maps = hash:/etc/postfix/virtual
smtp_generic_maps = hash:/etc/postfix/generic

# compatibility_level disables postfix 2 backward compatibility in Postfix 3.
# http://www.postfix.org/postconf.5.html#compatibility_level
#compatibility_level = 2

On the Postfix 3 box, I ended up using the same fundamental config, but with the compatibility_level = 2 variable uncommented.

There are some differences of interpretation in certain variables, and changes to default behaviours of others, particularly things like mynetworks_style. Setting the networks is important to avoid the machine becoming an unwitting open relay.

Setting the [mydestination][1] variable correctly is important - it tells the machine what domains it will locally deliver for instead of relaying to another machine via SMTP. (See Postfix Basic Configuration for examples.)

If you want to check it's working, tail your mail log:

tail -fn 100 /var/log/maillog (or mail.log on some machines)

For all cron reports, you should now see something like

Dec  4 14:04:50 server01 postfix/pickup[25672]: 1B2566011A: uid=0 from=<root>
Dec  4 14:04:50 server01 postfix/cleanup[19854]: 1B2566011A: message-id=<20181205140450.1B2566011A@server01.fqdn.tld>
Dec  4 14:04:50 server01 postfix/qmgr[29434]: 1B2566011A: from=<root@server01.fqdn.tld>, size=2320, nrcpt=1 (queue active)
Dec  4 14:04:50 server01 postfix/local[19859]: 1B2566011A: to=<root@server01.fqdn.tld>, orig_to=<root>, relay=local, delay=289, delays=289/0.01/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
Dec  4 14:04:50 server01 postfix/qmgr[29434]: 1B2566011A: removed

The relay=local and status=sent (delivered) is key, instead of status=bounced or any references to an SMTP server (e.g. relay=smtp.fqdn.tld[1.2.3.4]:25). Local reports to the root mailbox from things like cron outputs should always be locally delivered (local relay).

Once set up correctly, I recommend using mutt (apt-get install mutt / yum install mutt) to check the root mailbox: mutt -f /var/spool/mail/root.