I like digitalocean’s tutorials about setting up servers and VPS, which is usually easy to understand, and if not (like this Postfix tutorial), at least works!
I composed a tutorial about setting up sendmail. In that tutorial, you can see I’ve got a lot of trouble making sendmail work, so I think this time I should try Postfix, which is said to be more advanced than sendmail, and easier to use. But frankly speaking, I do not think the concepts in Postfix are easier to understand than sendmail. In fact, they use the same set of concepts. But with the guide of the digitalocean’s tutorial, the configuration work is indeed simpler than sendmail. The point is you need not understand the complex concepts involved in it. What you need to do is just to copy/paste the code provided in the tutorial and change the domain name to your real domain name.
Install postfix
1 |
yum install postfix |
This also installs the depending cyrus-sasl package.
1 |
yum install cyrus-imapd |
Configure Postfix
vi /etc/postfix/main.cf to use the following configuration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
maximal_queue_lifetime = 0 soft_bounce = no queue_directory = /var/spool/postfix command_directory = /usr/sbin daemon_directory = /usr/libexec/postfix mail_owner = postfix # The default_privs parameter specifies the default rights used by # the local delivery agent for delivery to external file or command. # These rights are used in the absence of a recipient user context. # DO NOT SPECIFY A PRIVILEGED USER OR THE POSTFIX OWNER. # #default_privs = nobody myhostname = mail.domainhostseotool.com mydomain = domainhostseotool.com mydestination = $myhostname,,$mydomain,localhost unknown_local_recipient_reject_code = 550 mynetworks_style = host mailbox_transport = lmtp:unix:/var/lib/imap/socket/lmtp local_destination_recipient_limit = 300 local_destination_concurrency_limit = 5 recipient_delimiter=+ virtual_alias_maps = hash:/etc/postfix/virtual header_checks = regexp:/etc/postfix/header_checks mime_header_checks = pcre:/etc/postfix/body_checks smtpd_banner = $myhostname debug_peer_level = 2 debugger_command = PATH=/bin:/usr/bin:/usr/bin:/usr/X11R6/bin xxgdb $daemon_directory/$process_name $process_id & sleep 5 sendmail_path = /usr/sbin/sendmail.postfix newaliases_path = /usr/bin/newaliases.postfix mailq_path = /usr/bin/mailq.postfix setgid_group = postdrop html_directory = no manpage_directory = /usr/share/man sample_directory = /usr/share/doc/postfix-2.3.3/samples readme_directory = /usr/share/doc/postfix-2.3.3/README_FILES smtpd_sasl_auth_enable = yes smtpd_sasl_application_name = smtpd smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, reject_invalid_hostname, reject_non_fqdn_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unknown_sender_domain, reject_unknown_recipient_domain, reject_unauth_pipelining, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net, reject_rbl_client dnsbl.njabl.org, reject_rbl_client dnsbl.sorbs.net, permit smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = broken_sasl_auth_clients = yes smtpd_helo_required = yes smtpd_milters = inet:127.0.0.1:8891 non_smtpd_milters = $smtpd_milters milter_default_action = accept milter_protocol = 2 smtpd_sasl_authenticated_header = yes |
Do not care much about the meaning of every parameter. Just replace domainhostseotool.com in the configuration file with your own domain name. Note the format of main.cf: this file is composed of logical lines which take the form of parameter=value. A logical line can include several physical lines. Every physical line that starts with whitespace continues the preceding logical line. So, in the above configuration, the debugger_command logical line consists of 3 physical lines and the smtpd_recipient_restrictions logical line consists of more physical lines. If you miss the whitespace at the beginning, you may encounter syntax errors.
Create Postmap
vi /etc/postfix/virtual to add an email:
admin@domainhostseotool.com admin\@domainhostseotool.com
1 2 3 |
postmap /etc/postfix/virtual touch /etc/postfix/body_checks |
Set up Cyrus
vi /etc/sasl2/smtpd.conf
After editing, the file should contain the following content:
1 2 3 |
pwcheck_method: auxprop auxprop_plugin: sasldb mech_list: PLAIN LOGIN CRAM-MD5 DIGEST-MD5 |
Postfix smtpd is linked against Cyrus SASL lib to use it to authenticate smtp client. The configuration file name “smtpd.conf” and its location: /etc/sasl2/ are not chosen at will. When you set smtpd_sasl_application_name to “smtpd” in main.cf, Postfix code will send “smtpd” to Cyrus SASL lib code at authentication. Cyrus SASL lib will then know the configuration file is smtpd.conf and it will try to find it in /etc/sasl2/. The configuration file tells Cyrus SASL lib how to do the authentication. It can communicate with an independent process(service) saslauthd to do the authentication. It can also use a plugin(like the above example) to do the authentication. The plugin is in the Cyrus SASL lib code and thus part of the smtpd process, no independent process is involved here. There are advantages and disadvantages of using the plugin mechanism compared to using saslauthd. The cost is apparently reduced by using an in-process plugin. But since smtpd is run by the user postfix, it can not access resources that need root privileges, while saslauthd is run by the user root and can then access sensitive files like /etc/shadow to do the authentication.
vi /etc/imapd.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
virtdomains: userid defaultdomain: domainhostseotool.com servername: domainhostseotool.com configdirectory: /var/lib/imap partition-default: /var/spool/imap admins: cyrus sievedir: /var/lib/imap/sieve sendmail: /usr/sbin/sendmail.postfix hashimapspool: true allowanonymouslogin: no allowplaintext: yes sasl_pwcheck_method: auxprop sasl_mech_list: CRAM-MD5 DIGEST-MD5 PLAIN tls_cert_file: /etc/pki/cyrus-imapd/cyrus-imapd.pem tls_key_file: /etc/pki/cyrus-imapd/cyrus-imapd.pem tls_ca_file: /etc/pki/tls/certs/ca-bundle.crt autocreatequota: -1 createonpost: yes autocreateinboxfolders: spam autosubscribeinboxfolders: spam |
This file has nothing to do with postfix but the configuration file for cyrus-imapd. Remember to replace domainhostseotool.com with your own domain name.
Start Postfix service
1 |
service postfix start |
using netstat -antp, you will see the process “master”(the control process of postfix) is listening on port 25.
Install a mail client to send emails
1 2 3 4 5 6 7 8 9 |
yum install mailx mail user@domain.com subject:yoursubject your email content . |
Enable SMTPS for postfix
Now you can send mails using the mail command. But the configurations above is far from perfect in real production environment. We’ll add more configuration to make a real email system. First, we will add the ssl support for postfix. By default, postfix listens on port 25 to receive emails from peer mta or email clients. The messages transported via port 25 are not encrypted and easy to be sniffed, even tampered. Some email clients can use STARTTLS command to enter encrypted communication mode via port 25. But old email client does not support STARTTLS. Here we use smtps to implement the encrypted communication. SMTPS uses port 465 to receive packets over SSL. To enable postfix for smtps, edit /etc/postfix/master.cf to un-comment the line:
1 |
smtps inet n - n - - smtpd |
restart postfix and you will find the process “master” is now listening on port 25 as well as port 465.
You can use openssl to connect to the server via port 465. But openssl will quit during the ssl handshaking phase, complaining “no peer certificate available”. You should modify the settings in /etc/postfix/main.cf to add TLS support:
1 2 3 4 5 6 7 8 9 10 11 12 |
smtpd_tls_security_level = may smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3 smtpd_tls_protocols = !SSLv2, !SSLv3 smtpd_tls_loglevel = 0 smtpd_tls_cert_file = /etc/postfix/smtps.crt smtpd_tls_key_file = /etc/postfix/smtps.key smtpd_tls_auth_only = no smtpd_tls_received_header = yes smtp_tls_security_level = may smtp_tls_mandatory_protocols = !SSLv2, !SSLv3 smtp_tls_protocols = !SSLv2, !SSLv3 smtp_tls_loglevel = 0 |
smtps.crt and smtps.key are the server certification and server key. You can generate the two files according to this guide. Alternatively, you can get the certificate and the key file through letsencrypt because you need a domain name to send emails and the domain name can be used to get the free ssl certificate. In CentOS7 and apache environment, you can get the files with the following steps:
- set up an http website for the domain
- enable EPEL repo:
1yum install <a class="external free" href="https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm">https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm</a> - install certbot:
1yum install certbot python2-certbot-apache - get a certificate for the domain(domainhostseotool.com and www.domainhostseotool.com)
1certbot certonly --apache
The certificate is in /etc/letsencrypt/live/domainhostseotool.com/fullchain.pem, and the key is in /etc/letsencrypt/live/domainhostseotool.com/privkey.pem. You need to modify main.cf to point to them. Note the suffix is pem, not .crt and .key, which does not matter.
However, after adding the ssl setting parameters, openssl still exits with the same error( “SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol”…). You should un-comment the following line in master.cf
1 |
-o smtpd_tls_wrappermode=yes |
Now, you should see the server certification during the handshaking phase in the openssl command, although it complains “unable to verify the first certificate” because the server certification is issued by myself, not a real CA. This is a good signal indicating the TLS settings for postfix are ok. The bad news is that openssl still quits after ssl handshaking.
Config SASL authentication
By checking the postfix log file:/var/log.maillog, you will see the following error messages:
1 2 |
warning: xsasl_cyrus_server_get_mechanism_list: no applicable SASL mechanisms fatal: no SASL authentication mechanisms |
This is because we’ve not installed any SASL authentication package although we’ve installed the cyrus-sasl package. For simplicity, here we only add one SASL authentication package: cyrus-sasl-plain
1 |
yum install cyrus-sasl-plain |
This time the openssl command does not exit and stops at the line:
1 |
220 mail.domainhostseotool.com |
Openssl waits for us to input commands. If you try to send an mail, you will fail after you input the “rcpt to:” command. The error is “Relay access denied”. This is caused by the smtpd_recipient_restrictions setting in main.cf. We do not allow email relay for unauthorized people. You need to complete the authentication before sending an email.
If you follow the instruction in the guide to submit your login credentials, you will get the error:
Error: authentication failed: authentication failure
Meanwhile, you will see the following errors in /var/log/maillog:
1 2 3 4 |
warning: SASL authentication problem: unable to open Berkeley db /etc/sasldb2: No such file or directory warning: SASL authentication failure: Password verification failed SASL plain authentication failed: authentication failure |
This is because we’ve not set up Cyrus correctly for authentication. Remember we specified the authentication method as “pwcheck_method: auxprop” in the “set up Cyrus” step? This authentication method uses a database file to store user accounts that are independent of the Linux system accounts. You need to create that database and add user accounts in that database. You can follow this guide to do this.
1 2 3 |
saslpasswd2 -c -u mail.domainhostseotool.com -a smtpauth admin chown postfix /etc/sasldb2 |
Now you should be able to complete the auth command and send emails in openssl.
Occasionally, you may forget the password for a user account. How to see the password of a user in /etc/sasldb2? Unfortunately, I can not figure out how to recover the password. /etc/sasldb2 is a binary file, something like /etc/shadow. You can not see the password in it. But I have a way to change the password. First, list the user account in /etc/sasldb2 using sasldblistusers2. The command’s output looks like:
admin@domainhostseotool.com: userPassword
But userPassword is not the real password for the user admin@domainhostseotool.com. To change the password, use “saslpasswd2 admin@domainhostseotool.com”
Please refer to the post for sasl management.
Receive emails using Cyrus-IMAP
At this point, you can send emails using the postfix system without a problem. However, as to receiving emails, there are more configurations to be done.
First, you should change the following line in main.cf
1 |
mydestination = $myhostname, localhost |
to
1 |
mydestination = $myhostname, $mydomain,localhost |
Otherwise, you will get the following error:
1 |
reject: RCPT from unknown[xx.xx.xx.xx]: 554 5.7.1 <admin@domianhostseotool.com>: Relay access denied; |
That is because according to smtpd_recipient_restrictions, only emails to xxx@mail.domainhostseotool.com are accepted, emails to xxx@domainhostseotool.com are rejected.
Even you change the “mydestination” variable, there is still an error:
1 |
to=<admin@domainhostseotool.com>, relay=none, delay=1109, delays=1109/0/0/0, dsn=4.4.1, status=deferred (connect to mail.domainhostseotool.com[/var/lib/imap/socket/lmtp]: No such file or directory) |
You should start the service cyrus-imapd:
1 |
service cyrus-imapd start |
Postfix will talk with this service to deliver received emails to mailbox.
cyrus-imapd will save the emails in /var/spool/imap(specified by the partition-default parameter in /etc/imapd.conf). Every email address has a directory under /var/spool/imap. Every email is saved as a file like 1., 2., 3.,…. Note that even there is no account in /etc/sasldb2, the emails postfix receives are still saved in /var/spool/imap, because for email destined to the server postfix controls, no authentication is required. But if you, as an email client, want to retrieve emails from the system using cyrus-imap, you will be asked to pass the authentication. In our example, cyrus-imapd uses /etc/sasldb2 for authentication(sasl_pwcheck_method: auxprop). Thus we need to add an account in /etc/sasdb2 to retrieve emails associated with that account. For example, if you want to get the emails to admin@domainhostseotool.com, you need to add a user named “admin@domainhostseotool.com” as follows:
1 |
saslpasswd2 admin@domainhostseotool.com |
If you use an email client such as outlook, you need to input the account information in the “receiving server’s account name” and “receiving server’s password”. The account name is “admin@domainhostseotool.com”, not “admin”.
Postfix management commands:
delete emails from message queue:
1 |
postsuper -d ALL |
1 |
postsuper -d ALL deferred |
Check emails in message queue:
1 2 |
postqueue -p mailq |