Postfix SMTP Submission Server

This page assumes familiarity with the terminology defined on the main Mail Server Page.

This page assumes you have configured your /etc/postfix/main.cf configuration file according to the Postfix MTA Server TLS Configuration instructions. This includes having an x.509 certificate. For submission services, it really should be a Certificate Authority signed certificate.

This page assumes you have configured your MTA client’s /etc/postfix/main.cf configuration file according to the Postfix MTA Client TLS Configuration instructions. This includes using a DNSSEC enforcing local resolver for the validation of DNS queries.

Some system administrators prefer to use a certificate authority signed ECDSA certificate with Submission, typically the same certificate they use with Dovecot. This allows them to use a self-signed RSA certificate for the MX server that does not need to be trusted by connecting e-mail clients. Instructions on how to set that up if you want to are on the Dovecot TLS Certificate Generation page.

Finally, this page assumes you have a working Dovecot server.

An Introduction to Submission

The Simple Mail Transfer Protocol (SMTP) is used by MX servers that receive messages on behalf of a mailbox domain. It is also used for relaying messages from users to completely different domains. The requirements for these two use cases is quite different.

With an MX server, authentication of the user sending the message is not performed. Encryption is encouraged but if you follow the RFC it is not required. The recipient should be restricted to mailbox domains the MX server is acting as a Mail Exchange MTA for. TCP Port 25 is the standardized port that must be used.

When an end user sends a message, authentication of the user sending the message should be performed, otherwise it risks being a hub for spammers. Encryption should be required, otherwise authentication information can easily be captured. The recipient mailbox domain is not relative, only the sender authentication matters. This use case is called submission.

These differences make it logical to use a different port for submission, even though SMTP is still used to accomplish it.

You can either use TCP Port 465 where encryption is required to even connect, or you can use TCP Port 587 where encryption is initiated with the STARTTLS command.

TCP Port 465 has an interesting history. Before TLS support officially came to SMTP, some system administrators started using it in combination with the program stunnel to tunnel SMTP over TLS. In early 1997 it become an official IANA standard port for that purpose. However that assignment was withdrawn at the end of 1998 with the introduction of STARTTLS to SMTP.

TLS could now be initiated on TLS Port 25, however the RFC required that MX servers continue to accept connections where encryption was not used, making Port 25 unsuitable for e-mail clients that needed to authenticate with a password.

TCP Port 25 became exclusively used for MTA to MTA communication where TLS was nice but not required. Attempts to user authenticate on TCP Port 25 are now usually dropped. TCP Port 587 became the port for users to use when using SMTP to send a message where authentication is required. Connections that do not initiate TLS via STARTTLS on Port 587 should be dropped.

Even though IANA dropped TCP Port 465 as an official port, many servers continued to require it and so most clients continued to support it. In January of 2018 Port 465 was brought back once again as an official sanctioned port in RFC 8314.

The primary difference between the two, Port 465 according to the specification requires encryption. The STARTTLS command is not used to initiate encryption, encryption is negotiated before the SMTP layer happens. The client attempts to establish a secure channel from the start or gives up. With Port 587 a secure connection is initiated when the client sends the STARTTLS command. Servers should refuse connections from clients that do not initiate it and clients should refuse to send login authentication if a secure channel has not been established, however a combination of a mis-configured server and client can result in authentication information being sent in plain text.

For that reason I personally prefer TCP Port 465 for message submission. In fact RFC 8314 deprecates Submission over Port 587 because it is not implicitly encrypted. When configured correctly, however, submission over Port 587 is just as safe.

Linux Firewall

If you are running the Linux firewall daemon (you probably should be), make sure to poke a hole in it for the submission port(s) you plan to use. For example, if you plan to allow submission on both ports:

[root@host ~]# /bin/firewall-cmd --zone=public --add-port=465/tcp --permanent
[root@host ~]# /bin/firewall-cmd --zone=public --add-port=587/tcp --permanent
[root@host ~]# /bin/firewall-cmd --reload

Simple Authentication and Security Layer

To avoid your submission server from becoming a spam relay, some type of user authentication is needed. Client x.509 certificates is probably the most secure but is also the most complex and is beyond the scope of this document. Pop before Send is another popular method but can be fooled. SASL is what most systems tend to use. Postfix currently has support for two different SASL libraries: cyrus-sasl and dovecot-sasl.

When I am offering IMAP services through Dovecot anyway, I find it simpler to use dovecot-sasl though I have used the other in the past and it works well too. These instructions are for dovecot-sasl as the SASL library. These instructions also assume your submission server is running on the same physical server as your dovecot server. It is possible to configure dovecot-sasl over TCP though I would advise researching security concerns first, I suspect stunnel needs to be used to do it securely.

To be honest, I have only administered systems with fewer than 100 users, and on such small servers, there is not need to have the submission server on a physically different host than the dovecot server. If you have more than 100 users and want the physical servers different, feel free to charge them all a one time $10.00 fee so you can pay me to do the research on securing dovecot-sasl auth over a TCP network and write it up for you.

Dovecot SASL Configuration

What we need to do is have dovecot create a UNIX socket for Postfix to communicate with. This is done in the file /etc/dovecot/conf.d/10-master.conf. Find the section that has:

service auth {
... several lines ...
}

Inside that section, there is a by default commented out section:

  # Postfix smtp-auth
  #unix_listener /var/spool/postfix/private/auth {
  #  mode = 0666
  #}

Change it to look like the following:

  # Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }

Now, edit the file /etc/dovecot/conf.d/10-auth.conf. Find the line that reads:

auth_mechanisms = plain

That probably is sufficient for most clients, but for some clients, you will need to make sure it reads:

auth_mechanisms = plain login

Restart the Dovecot daemon. After restarting Dovecot, it should have created the special socket file /var/spool/postfix/private/auth that Postfix can use for SASL authentication through Dovecot.

Postfix SASL Authentication

The basic SASL directives for Postfix need to be put into the /etc/postfix/main.cf file. LibreLAMP has no defaults in that file since SASL really only needs to be configured when Postfix is being used for submission, and even then it is only one of several different mechanisms for user authentication.

This is the basics of what needs to be added to the /etc/postfix/main.cf file. I usually add them after the end of the TLS client configuration.

# SASL Options
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = no
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $myhostname

Here is what those options mean:

smtpd_sasl_type
There are two possible SASL libraries you can use with Postfix, dovecot or cyrus. The instructions here are for dovecot so that is what it is set to.
smtpd_sasl_path
With Dovecot running on the same server and configured to create the UNIX socket file as previously described, this should be set to the socket file relative to the Postfix queue directory (/var/spool/postfix). The path to the socket relative to that directory is private/auth.
smtpd_sasl_auth_enable
It may seem counter intuitive, but this needs to be set to no.
The /etc/postfix/main.cf configures Postfix in the generic sense. We only want SASL authentication in the specific context of submission, so it should be turned off here and will be turned when submission is configured.
smtpd_sasl_security_options
This should be configured to specifically forbid anonymous authentication, which is done with the noanonymous directive.
smtpd_sasl_local_domain
This sets the SASL authentication realm. I generally set it to $myhostname which is defined earlier in the main.cf file.

For other possible options you may want to set, see the SASL_README file.

After making any changes, make sure to reload Postfix to activate them:

[root@host ~]# postfix reload

Master Process Configuration

The file for configuring submission, as well as a few other features, is located at /etc/postfix/master.cf. If you have a previously modified this file, the LibreLAMP default will be installed as /etc/postfix/master.cf.rpmnew and you may need to migrate some settings.

Official documentation for the configuration file can be read via man 5 master.

The man 5 page describes ignored lines as lines that either begin with a # as the first non-whitespace character, lines that only include whitespace characters, and empty lines.

A logical line is a non-ignored line where the first character is non-whitespace text.

A non-ignored line that begins with whitespace text is a continuation of the previous logical line. In practice, the first non-whitespace characters in these continuation lines are the switch -o followed by a space and then a parameter that is being defined in context of the logical line.

Each logical line consists of 8 fields. Please see the man 5 page for specific information about each field, but the first field is the service and the eighth field is the command + args field. It is typically the + args when they exist that are often placed on a separate line as a continuation.

The most commonly used arguments when any are used are one or more -o name=value pair. When there is more than one, usually each one is put on its own line. Spaces are not allowed in the name=value pair. If the value needs a space, you can use a , instead or define a variable in /etc/postfix/main.cf that contains the value with the spaces, and then refer to the variable in the /etc/postfix/master.cf file.

Submission via Port 465 (secured by SMTPS)

Submission on this port is often referred to as SMTPS to indicate it always uses TLS. In the default LibreLAMP /etc/postfix/master.cf file it initially looks like this:

#smtps     inet  n       -       n       -       -       smtpd
#  -o syslog_name=postfix/smtps
#  -o smtpd_tls_wrappermode=yes
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_tls_auth_only=yes
#  -o smtpd_tls_exclude_ciphers=$smtpd_tls_exclude_paranoid
#  -o cleanup_service_name=sub_cleanup
#  -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

It is unlikely you will need to un-comment all of the optional arguments. To use Port 465 for submission obviously you will need to un-comment the logical line that starts with #smtps. The arguments I usually un-comment:

# -o syslog_name=postfix/smtps
This defines how log entries that result in the /var/log/maillog file are distinguished from other processes that add to that log file.
# -o smtpd_tls_wrappermode=yes
This you definitely should un-comment for this service. Otherwise it will not attempt to negotiate a TLS session and clients will not be able to connect. This is needed specifically because STARTTLS is not used with Port 465.
# -o smtpd_sasl_auth_enable=yes
This is needed to turn on SASL authentication.
# -o smtpd_tls_auth_only=yes
This needs to be un-commented so that connections that do not authenticate are rejected.
# -o smtpd_tls_exclude_ciphers=$smtpd_tls_exclude_paranoid
It is optional to un-comment this. What it does is make the ciphers that can be used to connect to Port 465 more restrictive than the default SMTPD ciphers.
The value $smtpd_tls_exclude_paranoid is defined in the default LibreLAMP /etc/postfix/main.cf file. It restricts the ciphers to a handful of very high quality TLS 1.2+ ciphers that use ECDHE key exchange.
# -o cleanup_service_name=sub_cleanup
It is optional to un-comment this. It defines the cleanup_service_name to the sub_cleanup (short for Submission Cleanup) service, also defined in the /etc/postfix/master.cf file, that removes the Received: header.
When a Mail User Agent submits an e-mail to the submission service to be sent, normally there is a Received header added that includes the IP address and host name the client connected from. This is a privacy breach that can be dangerous as it can leak information about the geographical location of the user. Removing the header when messages enter through submission is the prudent thing to do, most users have no clue that information is often divulged when they send an e-mail.
That header is often removed in corporate environments so that network infrastructure is not revealed, but an even more serious concern are things like victims of domestic abuse that are attempting to escape their abuser. It would be bad for their geographical location to be revealed because an e-mail they sent to someone was intercepted and the headers examined, headers that are not encrypted by end to end e-mail encryption technology because they are not part of the message itself.

That is the list I normally un-comment for submission on Port 465. Your own needs may dictate un-commenting and possibly redefining other options.

Remember to activate any changes, run the command

[root@host ~]# postfix reload

Submission via Port 587 (secured by STARTTLS)

Even before Port 465 was officially brought back into service, every mail client I personally used supported submission over Port 465. However there may be some that do not. If you have users with mail clients that do not support SMTPS submission on Port 465, you will need to enable STARTTLS submission on Port 587 for them. In the default LibreLAMP /etc/postfix/master.cf file it initially looks like this:

#submission inet n       -       n       -       -       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_tls_exclude_ciphers=$smtpd_tls_exclude_paranoid
#  -o cleanup_service_name=sub_cleanup
#  -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

It is unlikely you will need to un-comment all of the optional arguments. To use Port 587 for submission obviously you will need to un-comment the logical line that starts with #submission. The arguments I usually un-comment:

# -o syslog_name=postfix/submission
This defines how log entries that result in the /var/log/maillog file are distinguished from other processes that add to that log file.
# -o smtpd_tls_security_level=encrypt
This is critical to un-comment if you offer submission on Port 587. The default behavior is Opportunistic TLS and will allow mis-configured clients to transmit authentication data in plain text. This tells Postfix to reject connections that do not upgrade to TLS.
# -o smtpd_sasl_auth_enable=yes
This is needed to turn on SASL authentication.
# -o smtpd_tls_auth_only=yes
This needs to be un-commented so that connections that do not authenticate are rejected.
# -o smtpd_tls_exclude_ciphers=$smtpd_tls_exclude_paranoid
It is optional to un-comment this. What it does is make the ciphers that can be used to connect to Port 465 more restrictive than the default SMTPD ciphers.
The value $smtpd_tls_exclude_paranoid is defined in the default LibreLAMP /etc/postfix/main.cf file. It restricts the ciphers to a handful of very high quality TLS 1.2+ ciphers that use ECDHE key exchange.
# -o cleanup_service_name=sub_cleanup
It is optional to un-comment this. It defines the cleanup_service_name to the sub_cleanup (short for Submission Cleanup) service, also defined in the /etc/postfix/master.cf file, that removes the Received: header.
When a Mail User Agent submits an e-mail to the submission service to be sent, normally there is a Received header added that includes the IP address and host name the client connected from. This is a privacy breach that can be dangerous as it can leak information about the geographical location of the user. Removing the header when messages enter through submission is the prudent thing to do, most users have no clue that information is often divulged when they send an e-mail.
That header is often removed in corporate environments so that network infrastructure is not revealed, but an even more serious concern are things like victims of domestic abuse that are attempting to escape their abuser. It would be bad for their geographical location to be revealed because an e-mail they sent to someone was intercepted and the headers examined, headers that are not encrypted by end to end e-mail encryption technology because they are not part of the message itself.

That is the list I normally un-comment for submission on Port 587. Your own needs may dictate un-commenting and possibly redefining other options.

Remember to activate any changes, run the command

[root@host ~]# postfix reload

MTA Client Considerations

When an e-mail client connects to the Submission server, those messages then need to be relayed to an MX server that serves the mailbox domain for the envelope address. Your Postfix daemon becomes an MTA client to do this.

Please do your part in making sure that connection is secure. If your submission server directly connects to those MX servers, please implement STARTTLS Everywhere. I have an RPM for CentOS 7 at that link that makes it easy.


These MX servers have a responsibility to their users to label potential spam. You can reduce the odds mail from your users is labeled as spam.

Your submission server should add a DKIM signature so that spam filters can verify the e-mail message went through a legitimate MTA authorized to relay e-mail on behalf of your mailbox domain.

Traditionally these signatures use a 1024-bit RSA key for this purpose. Please do not, 1024-bit RSA is difficult to crack but it can be cracked in under a year by an attacker with resources, allowing them to fraudulently sign messages that appear to be legitimately from your domain.

Use a 2048-bit RSA key.

For your the SPF record for your mailbox domain, make sure the host name of the MTA client which does connect to MX servers is listed in the policy. Otherwise many MX servers will flag the mail as potential spam.

Make sure the host name used in the SPF record matches the reverse DNS for the IP address (both IPv4 and IPv6). Your hosting provider should provide a control panel that allows you to configure the reverse DNS.