User:Paul/sandbox/Transactional mail server

From Wiki
Jump to navigation Jump to search

WARNING: This article is in a user sandbox, indicating it is a rough draft, and as such, is likely incomplete, contains buggy and insecure configurations, and is subject to substantial and frequent changes.

A transactional email is generated by many popular packages, typically for account registration confirmation, topic reply notifications, password retrieval, and other automated uses such as sending system notification messages to administrators. The emails will commonly be sent from an email address that is a non-functioning email account used exclusively for sending, such as

The PHP mail() function is typically the default method that PHP packages will use for sending transactional mail. This function will use the server's sendmail-compliant MTA to send the mail, thus necessitating a sendmail-compliant MTA to be installed. An MTA can be used to send mail directly from the server or can be configured to send mail through a smart host to reduce server and admin overhead.

Most of the popular PHP packages will include an option or have a plugin available to send transactional email through an SMTP server, eliminating the requirement to install any type of MTA for the purpose of supporting email generated by the package. However, without an MTA installed, system messages cannot be sent to the administrators.

Transactional email via MTA

Log in as root and install the necessary packages:

username@servername:~$ sudo -i
root@servername:~# aptitude install postfix opendkim opendkim-tools

Selected 'Internet site' during the postfix install.

Configure OpenDKIM

The opendkim package will add a DKIM signature to configured outbound emails. Receiving servers can compare this signature with the corresponding DNS DKIM record and verify messages as coming from an approved server and unaltered.

root@servername:~# mkdir -p /etc/opendkim/keys/
root@servername:~# opendkim-genkey -r -b 2048 -h sha256 -d -s selector -D /etc/opendkim/keys/

Replace selector as desired, as it is only used to identify the key the server will call. Many admins will simply use the date the key was created (e.g. '20140510') or, when multiple servers are being used, the server name (e.g. 'mta05'), though none of this is standardized or required - some simply use 'mail', or don't specify anything when running the command, leaving the selector of 'default'. The command creates two files, selector.private and selector.txt. The selector.private file contains the private key while selector.txt contains the basis for the DNS TXT record that will be created in a later step.

Note that the DKIM standard currently recommends a maximum key size of 2048 bits, so using a larger key size will likely cause the DKIM test to fail on many servers, while using a key smaller 1024 bits is not only not recommended, but has been demonstrated to be insecure.


Create the tables that opendkim will use:

root@servername:~# nano /etc/opendkim/KeyTable


Since this server is being configured to have one domain serve mail for multiple domains, only one private key is being used.


root@servername:~# nano /etc/opendkim/SigningTable



The second and third entries demonstrate how additional domains served by the mail server would be added to the signing table.


root@servername:~# nano /etc/opendkim/TrustedHosts

Configure opendkim.conf

Set permissions on the directory, archive the default opendkim.conf before creating a new one:

root@servername:~# chown -R opendkim:opendkim /etc/opendkim
root@servername:~# mv /etc/opendkim.conf /etc/original.opendkim.conf
root@servername:~# nano /etc/opendkim.conf

Add to the new file:

# This is a basic configuration that can easily be adapted to suit a standard
# installation. For more advanced options, see opendkim.conf(5) and/or
# /usr/share/doc/opendkim/examples/opendkim.conf.sample.

# Log to syslog
Syslog                  yes
# Required to use local socket with MTAs that access the socket as a non-
# privileged user (e.g. Postfix)
UMask                   002

# Commonly-used options
SubDomains              yes
AutoRestart             yes
Background              yes
Canonicalization        relaxed/relaxed
DNSTimeout              5
Mode                    sv
SignatureAlgorithm      rsa-sha256

# Additional OpenDKIM options

ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts
KeyTable                refile:/etc/opendkim/KeyTable
SigningTable            refile:/etc/opendkim/SigningTable
LogWhy                  Yes
PidFile                 /var/run/opendkim/
Socket                  local:/var/spool/postfix/opendkim/opendkim.sock
SyslogSuccess           Yes
TemporaryDirectory      /var/tmp
UserID                  opendkim:opendkim

# Always oversign From (sign using actual From and a null From to prevent
# malicious signatures header fields (From and/or others) between the signer
# and the verifier.  From is oversigned by default in the Debian package
# because it is often the identity key used by reputation systems and thus
# somewhat security sensitive.
OversignHeaders         From

Though most of the settings are fairly self-explanatory, it is a good idea to become familiar with the various settings to reduce the time spent troubleshooting why other mail servers are failing DKIM checks on mail sent from the server. One particular setting to note is SubDomains (everything after the @ symbol in an email address) being set to no. The above configuration has SubDomains set to yest as many popular PHP packages will default send email from the domain for which they are configured (e.g.,

Create the directory for the domain socket specified in opendkim.conf, make the postfix user a member of the opendkim group so it can edit opendkim.sock, and restart the service:

root@servername:~# mkdir /var/spool/postfix/opendkim
root@servername:~# chown opendkim:root /var/spool/postfix/opendkim
root@servername:~# service opendkim restart

Configure postfix

Following the below steps will configure postfix exclusively for sending and will reject email not coming from one of the loopback addresses. Additionally, ufw has not been configured to permit inbound connections commonly monitored by postfix, so attempts to send mail to the server will fail to at least these two considerations.


The file is the primary configuration file for Postfix, and it is enormous. Archive the original version, then create a new one:

root@servername:~# mv /etc/postfix/ /etc/postfix/
root@servername:~# nano /etc/postfix/

Add the following:

# See /usr/share/postfix/ for a commented, more complete version

# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# See -- default to 2 on
# fresh installs.
compatibility_level = 2

# TLS parameters
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_security_level = may
smtp_tls_note_starttls_offer = yes

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

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 =
relayhost =
mynetworks = [::ffff:]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces =, [::1]
inet_protocols = all

non_smtpd_milters = unix:opendkim/opendkim.sock
smtpd_milters = unix:opendkim/opendkim.sock


Another important and huge configuration file is Make an archive of the original version and make a new one:

root@servername:~# mv /etc/postfix/ /etc/postfix/
root@servername:~# nano /etc/postfix/

Add to the file:

# Postfix master process configuration file.  For details on the format
# of the file, see the master(5) manual page (command: "man 5 master" or
# on-line:
# Do not forget to execute "postfix reload" after editing this file.
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (no)    (never) (100)
# ==========================================================================
smtp      inet  n       -       y       -       -       smtpd
#smtp      inet  n       -       y       -       1       postscreen
#smtpd     pass  -       -       y       -       -       smtpd
#dnsblog   unix  -       -       y       -       0       dnsblog
#tlsproxy  unix  -       -       y       -       0       tlsproxy
#submission inet n       -       y       -       -       smtpd
#  -o syslog_name=postfix/submission
#  -o smtpd_tls_security_level=encrypt
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_tls_auth_only=yes
#  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
#  -o smtpd_recipient_restrictions=
#  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
#smtps     inet  n       -       y       -       -       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_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
#  -o smtpd_recipient_restrictions=
#  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
#628       inet  n       -       y       -       -       qmqpd
pickup    unix  n       -       y       60      1       pickup
cleanup   unix  n       -       y       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
#qmgr     unix  n       -       n       300     1       oqmgr
tlsmgr    unix  -       -       y       1000?   1       tlsmgr
rewrite   unix  -       -       y       -       -       trivial-rewrite
bounce    unix  -       -       y       -       0       bounce
defer     unix  -       -       y       -       0       bounce
trace     unix  -       -       y       -       0       bounce
verify    unix  -       -       y       -       1       verify
flush     unix  n       -       y       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       y       -       -       smtp
relay     unix  -       -       y       -       -       smtp
        -o syslog_name=postfix/$service_name
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq     unix  n       -       y       -       -       showq
error     unix  -       -       y       -       -       error
retry     unix  -       -       y       -       -       error
discard   unix  -       -       y       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       y       -       -       lmtp
anvil     unix  -       -       y       -       1       anvil
scache    unix  -       -       y       -       1       scache
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
# Many of the following services use the Postfix pipe(8) delivery
# agent.  See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in maildrop_destination_recipient_limit=1
#maildrop  unix  -       n       n       -       -       pipe
#  flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# ====================================================================
# Recent Cyrus versions can use the existing "lmtp" entry.
# Specify in cyrus.conf:
#   lmtp    cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
# Specify in one or more of the following:
#  mailbox_transport = lmtp:inet:localhost
#  virtual_transport = lmtp:inet:localhost
# ====================================================================
# Cyrus 2.1.5 (Amos Gouaux)
# Also specify in cyrus_destination_recipient_limit=1
#cyrus     unix  -       n       n       -       -       pipe
#  user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
# ====================================================================
# Old example of delivery via Cyrus.
#old-cyrus unix  -       n       n       -       -       pipe
#  flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
# ====================================================================
# See the Postfix UUCP_README file for configuration details.
#uucp      unix  -       n       n       -       -       pipe
#  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# Other external delivery methods.
#ifmail    unix  -       n       n       -       -       pipe
#  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
#bsmtp     unix  -       n       n       -       -       pipe
#  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
#scalemail-backend unix  -       n       n       -       2       pipe
#  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
#mailman   unix  -       n       n       -       -       pipe
#  flags=FR user=list argv=/usr/lib/mailman/bin/
#  ${nexthop} ${user}

SMTP mail server

This simple solution is most useful when delivering mail in small batches, but can create issues with large quantities of mail being sent at one time. When using this option it is best to choose a service that is intended to be used for sending transactional email. Most free email services (Gmail, Yahoo!, Hotmail, etc.) are not friendly to this type of usage and will often suspend accounts being used in this fashion. A better option is to use a service such as SendGrid or Mailgun. SendGrid offers up to 12,000 free emails per month while Mailgun offers 10,000 free emails per month, except for Rackspace customers, who get 50,000 free emails per month.


Nullmailer is a lightweight sendmail compliant MTA for sending emails to smart hosts. Since the version in the Ubuntu 12.04 repositories is very outdated and doesn't support modern encryption, a back-port may be used instead:

username@servername:~$ sudo add-apt-repository ppa:unpm/nullmailer-backport
username@servername:~$ sudo aptitude update && sudo aptitude install nullmailer

Installing the PPA for Nullmailer from the repository requires confirmation that insecure software may be installed. An explanation on how the PPA was configured is in the Create Back-port for PPA article.

Although the installer includes a guide that will automatically create the configuration files, it is better to go through each file after installation and verify it has been configured properly.


username@servername:~$ sudo nano /etc/nullmailer/adminaddr

The adminaddr file tells Nullmailer where to send failures and errors, so enter the appropriate email address in this file.


username@servername:~$ sudo nano /etc/nullmailer/defaultdomain

Enter the default domain that Nullmailer will use to send emails from when no other domain is specified.


username@servername:~$ sudo nano /etc/nullmailer/me

This configuration file is not very well documented. Some online sources state to use \$, but others report better experiences with \


username@servername:~$ sudo nano /etc/nullmailer/remotes

This is the file that contains login information for the the smart host and should be completed based on the configuration settings of the service being used.

Sendgrid smtp --port=587 --starttls --user=sendgridusername --pass=sendgridpassword
Mailgun smtp --port=587 --starttls --pass=mailgunpassword
username@servername:~$ sudo service nullmailer reload

External links

A Mailserver on Ubuntu 12.04: Postfix, Dovecot, MySQL | Ex Ratione

How to send one billion email messages per month

Postfix SOHO README standalone server