Victor is a full stack software engineer who loves travelling and building things. Most recently created Ewolo, a cross-platform workout logger.

    Setup postfix on Ubuntu and send emails for failed cron jobs

    Recently, I learned that on linux cron comes with a very simple email notification setup, namely the MAILTO environment variable. In this article we will setup postfix to send email via an external smtp server and ask cron to send emails on failed jobs. This requires that we have a domain e.g. that we can use to send emails as.

    Smtp host

    To begin with, we will need an smtp host that lets us send emails. While one can use gmail, it requires a fair amount of hoop jumping to enable access for less secure apps and needs to constantly be used otherwise it is disabled automatically. I can recommend migadu for their barebones plan that lets one configure multiple domains and senders. For the purposes of this article, we only need 1 domain that we can send emails from. Once a smtp provider is configured and a sender username/password obtained, we can proceed.

    Note that if using migadu, it is important to setup a mailbox for the machine name that will be sending the emails as well as configuring subdomain wildcards sending. This is because on my machine atleast cron sends the emails as and with subdomain wildcards any email from/to gets put into the mailbox.

    Setup postfix
    Install: sudo apt install postfix mailutils configure the smtp relay in /etc/postfix/
    # TLS parameters
    smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
    smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
    smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
    myhostname =
    alias_maps = hash:/etc/aliases
    alias_database = hash:/etc/aliases
    myorigin = /etc/mailname
    mydestination = $myhostname,, localhost.localdomain, localhost
    mynetworks = [::ffff:]/104 [::1]/128
    mailbox_size_limit = 0
    recipient_delimiter = +
    inet_interfaces = all
    #default_transport = error
    relay_transport = error
    inet_protocols = ipv4
    relayhost = []:465
    smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
    smtp_sasl_security_options = noanonymous
    smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
    smtp_use_tls = yes
    # following 2 are required by migadu
    smtp_tls_wrappermode = yes
    smtp_tls_security_level = encrypt

    Note that most other smtp relays will require the relayhost to be []:587 with the tls wrapper mode and security level left at their defaults.

    Now configure the smtp password via /ec/postfix/sasl_passwd (only need one that matches the entry in relayhost):

    # Gmail: 
    # Mailgun: 
    # Amazon SES: 
    []:587 user:pass

    Hash the password: sudo postmap /etc/postfix/sasl_passwd and restart the service sudo service postfix restart.

    Test sending emails via echo "Hello world!" | mail -s "email test $(date +%s)" Note that mail takes a parameter -r that lets one change the sender address. To check for errors, see /var/log/mail.log. Fortunately, email is a very old system and smtp providers actually provide useful error messages when things don't work! Remember that the postfix service needs to be restarted on any change to the main configuration file.

    Most email providers generally overwrite the sender address based on the account that is used to log in, however migadu specifically requires that the correct sender address be used. Normally postfix simply uses user@hostname as the sender address so it might be required to rewrite it to something more legitimate:

    echo "user@hostname" | sudo tee -a /etc/postfix/generic 
    echo "smtp_generic_maps = hash:/etc/postfix/generic" | sudo tee -a /etc/postfix/
    sudo postmap /etc/postfix/generic
    sudo service postfix restart
    Cron alerts

    The last piece is to set the MAILTO variable at the start of the cron configuration and thereafter setup the jobs as the following which will send regular output to the specified file and email the output of any failure:
    # run every evening at 22:06
    6 22 * * * /home/user/bin/ > /home/user/cron-logs/backup.log

    If the automatic email is not sent out, one can also force output to be sent as email via: 2>&1 | mail -s "subject"

    Besides cron job notifications, we can now send emails programmatically from our system which is pretty cool :). Happy emailing!

    HackerNews submission / discussion

    Back to the article list.

    SmallData newsletter

    Subscribe to get articles as they are published direct to your inbox!