This is an attempt to clean up these notes:
References go there. This post is a summary.
0. Before we start
These notes were collected while setting up a brand new mail server, on a fresh install of Ubuntu 16.04 Server.
I assume the user is root.
1. Pick a subdomain (and domain) for your mail server
Typically this is mail (i.e. mail.mydomain.com), but it can be anything. What’s important is that you’re consistent.
mail.mydomain.com is often referred to as the FQDN (Fully Qualified Domain Name).
You will be using all 3 variants (mail, mydomain.com, mail.mydomain.com) depending on what you’re doing.
2. Postfix (MTA)
Postfix is an Mail Transfer Agent (MTA) used to route and deliver e-mail.
Postfix uses SMTP (Simple Mail Transfer Protocol). It listens for mail, and either delivers it to a local user, or relays it to an external address. It does not provide a way for users to view their local mailbox. To be able to view a mailbox, you need to use a piece of software like Dovecot to run an IMAP or POP3 server.
With Postfix installed, we have everything we need to send and receive e-mails (other tools make it easier though).
2a. Before we start
We need to edit the host files. By default, the machine doesn’t know what domain to send e-mails from.
cat /etc/hostname # /etc/hostname should be a one line file like this: myservername
cat /etc/hosts # /etc/hosts should look something like this: 127.0.1.1 mydomain.com myservername 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters
More than likely, the first line will be missing the domain part (mydomain.com). Adjust it accordingly.
# Change the hosts file nano /etc/hosts # Reboot reboot now
This sets the e-mail address emails from users send from (i.e. [email protected]).
2b. Install Postfix and MailUtils
# The mailutils package has postfix and a few more tools (mail) apt-get install mailutils # We're saving ourselves a bunch of trouble by installing this # instead of just the postfix package
Done. You now have a mailbox in /var/mail/root
Here are some useful commands you may want to reference.
# View Root's Email cat /var/mail/root # Edit Config File nano /etc/postfix/main.cf # There are a few other config files in this folder (master.cf, etc) # Restart Postfix service postfix restart # Send a mail from the current user (root, etc) echo "text" | mail -s "subject" [email protected] # View Logs cat /var/log/syslog # system log, some messages cat /var/log/mail.log # mail log, more message cat /var/log/mail.err # mail errors tail -n 20 /var/log/syslog # view last 20 lines of syslog # Update Aliases nano /etc/aliases newaliases # Required! Generates /etc/aliases.db # Update Virtual Aliases (optional) nano /etc/postfix/virtual postmap /etc/postfix/virtual # Required! Generates virtual.db
2c. Configuring Postfix
3. PTR (Pointer Records, i.e. Reverse DNS lookups)
PTR’s are used to convert an IP address in to a domain name.
PTR’s are set by your webhost (specifically, whomever owns/allocated your public IP address).
It should be set your mail server’s FQDN.
dig mail.mydomain.com # should return the IP address # using that same IP address dig -x 220.127.116.11 # should return mail.mydomain.com
4. SPF (Sender Policy Framework)
SPF Records are used to say what IPs are allowed to send mail on behalf of a domain.
Add them as TXT records to your DNS (Cloudflare, etc).
Record Name Value TXT mail v=spf1 +ip4:18.104.22.168/24 ~all TXT mydomain.com v=spf1 include:mail.mydomain.com ~all
You may also notice your DNS supports SPF records. These are optional, and set to the exact same values. SPF records were obsoleted, as AFAIK everybody used TXT records instead, and SPF was simply unable to get enough support.
The 2nd case (mydomain.com) makes reference to the FQDN. When configuring a separate domain to use your mail server, you only need a version of the 2nd line pointing to your mail server (unless you also want to get mail from mail.otherdomain.com). Mail servers will recursively follow “include:’s” until they find an SPF record with an IP (though I’ve seen it suggested you should keep recursion depth low for maximum compatibility).
“~all” means softfail on SPF failures (i.e. don’t fail). To fail on SPF failures, use “-all“.
To check that records are correctly set, dig them.
dig mail.mydomain.com txt dig mydomain.com txt
* * *
When setting up a mail relay server, the IP address of the sender will change to the relay itself. Thus, the SPF check will now fail. If using “~all” this fine, but may not be ideal long term.
To correct this, the relay needs to rewrite the sender. SRS should be used for this (discussed later). SRS rewrites the sender in such a way that the origin domain is included, as well as the new (your) domain. The new (your) domain becomes the part after the @ sign, and thus, when doing an SPF check, now passes since your IP address now matches the sender domain’s SPF record.
5. DMARC (Domain Message Authentication Reporting & Conformance)
DMARC records do a few things. Most importantly, they tell other mail servers where to send reports.
These reports can be very helpful for debugging (huzzah).
Record Name Value TXT _dmarc v=DMARC1; p=none; rua=mailto:[email protected]
Reports are XML files sent daily by all the big e-mail providers.
If it’s working correctly, you ([email protected]) will get e-mails. 🙂
If you’re monitoring incoming mail (/var/mail/root), they tend to come delivered as BASE64 encoded ZIP files.
# Hack. Figure out how long the latest report is. tail -n 20 /var/mail/root # Adjust the above line until all you have is whitespace and lines of BASE64 data. # Once you've figured it out, you can compose a line like this. tail -n 12 /var/mail/root | base64 --decode > out.zip unzip out.zip # View the output like so: cat google.com!mydomain.com!1474156800!1474243199.xml # In Google's case, numbers are the start/end times as Unix timestamps.
Reports look something like this.
<?xml version="1.0" encoding="UTF-8" ?> <feedback> <report_metadata> <org_name>google.com</org_name> <email>[email protected]</email> <extra_contact_info>https://support.google.com/a/answer/2466580</extra_contact_info> <report_id>14815660973286397553</report_id> <date_range> <begin>1474156800</begin> <end>1474243199</end> </date_range> </report_metadata> <policy_published> <domain>mydomain.com</domain> <adkim>r</adkim> <aspf>r</aspf> <p>none</p> <sp>none</sp> <pct>100</pct> </policy_published> <record> <row> <source_ip>22.214.171.124</source_ip> <count>15</count> <policy_evaluated> <disposition>none</disposition> <dkim>pass</dkim> <spf>pass</spf> </policy_evaluated> </row> <identifiers> <header_from>mail.mydomain.com</header_from> </identifiers> <auth_results> <spf> <domain>mail.mydomain.com</domain> <result>pass</result> </spf> </auth_results> </record> </feedback>
The data in the later half of the report tends to be most useful. Telling you if DKIM and SPF tests pass.
DMARC is not only used for error reporting, but it tells the client what to do upon failure.
The “p=none” tells the client to take no special actions. Alternatively, “p=quarantine” or “p=reject” can be used to take action upon failure (send to spam, reject outright).
It’s good practice to begin with “p=none“. Once you have some reports under your belt, you can begin to quarantine or reject messages. This can be done gradually. More details can be found in the references below:
6. DKIM (DomainKeys Identified Mail)
DKIM is used to uniquely identify a domain using a public+private key pair as a signature. This is NOT encryption.
Together with SPF, mail is validated using the sender’s IP address (SPF), and by confirming their signature (DKIM). DMARC then says what to do about failures (though SPF does too), and who to report them to.
6a. Installing DKIM tools
apt-get install opendkim opendkim-tools
6b. Generating the DKIM signature and permissions!
Debian/Ubuntu has a standard folder for this: /etc/dkimkeys/
What’s special about this folder is that it’s owned by opendkim:opendkim. Don’t forget to set permissions!
cd /etc/dkimkeys/ # Generate Keys (-s subdomain -d domain.com) opendkim-genkey -s mail -d mydomain.com # This generates 2 files: # mail.private (the private key) # mail.txt (the DNS record) # Set File Permissions chmod 600 mail.private chown opendkim:opendkim mail.private
6c. DKIM DNS Settings
The “opendkim-genkey” command above generated a 2nd file, mail.txt.
cat mail.txt # mail.txt looks like this (edited for readability) mail._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=LALALA_SOME_REALLY_LONG_STRING" )
We want what’s inside the quotes (both sets). Edit that together on one line, removing quotes, like so:
v=DKIM1; k=rsa; p=LALALA_SOME_REALLY_LONG_STRING
Now you can paste that in to your DNS control panel.
Create a TXT record named mail._domainkey, and paste the edited line above.
6d. Configuring OpenDKIM
Edit the config file.
The default file is fine, but could use a few tweaks.
# Log to syslog Syslog yes SyslogSuccess yes #LogWhy yes # Only if debugging "why" # Required to use local socket with MTAs that access the socket as a non- # privileged user (e.g. Postfix) UMask 002 # Sign for example.com with key in /etc/dkimkeys/dkim.key using # selector '2007' (e.g. 2007._domainkey.example.com) Domain mydomain.com KeyFile /etc/dkimkeys/mail.private Selector mail
Now comes the weird stuff.
* * *
On a stock Ubuntu install, Postfix is (mostly) run in a chroot jail. As far as Postfix is concerned, the “/” folder is “/var/spool/postfix/“. It cannot access anything outside this folder.
Therefor, the simplest way to use OpenDKIM with Postfix is with a TCP socket, but a Unix domain socket is much better.
Furthermore, the simplest way to use a Unix domain socket is as follows. Run the following commands:
# Make a directory inside the chroot jail for our socket mkdir -p /var/spool/postfix/var/run/opendkim # Set permissions chown opendkim:opendkim /var/spool/postfix/var/run/opendkim # Add user "postfix" to "opendkim" group adduser postfix opendkim
Next edit the defaults file.
Add this to the end of the file:
Finally, restart the OpenDKIM service.
service opendkim restart
Again, that’s the easy way (it saves a lot of headaches). See the notes for the hard way (binding).
6e. Configuring Postfix for DKIM
Add these lines to the end of your “/etc/postfix/main.cf” file:
# DKIM settings milter_protocol = 2 milter_default_action = accept smtpd_milters = unix:/var/run/opendkim/opendkim.sock non_smtpd_milters = unix:/var/run/opendkim/opendkim.sock
Again, since Postfix is inside the chroot jail, the paths above neglect the “/var/spool/postfix” folder.
service postfix restart
7. TLS (Transport Layer Security, i.e. Encryption)
8. SRS (Sender Rewriting Scheme)
SRS is used to fix the sender, so forwarded e-mails pass the SPF (i.e. sender’s IP address) test.
How this works can be a little confusing, but essentially this happens:
SPF checks look at what follows the @ sign in the sender address. It takes that domain, checks the matching TXT SPF record, and if the IP address of the sender and SPF record match, it succeeds. So SRS is rewriting the sender’s email to be from you (the forwarder’s) domain, thus letting the SPF check pass.
To setup, install PostSRSD:
apt-get install postsrsd
Add these lines to the end of your “/etc/postfix/main.cf” file:
# PostSRSd settings sender_canonical_maps = tcp:localhost:10001 sender_canonical_classes = envelope_sender recipient_canonical_maps = tcp:localhost:10002 recipient_canonical_classes= envelope_recipient,header_recipient
- Reference: https://seasonofcode.com/posts/setting-up-dkim-and-srs-in-postfix.html
X. Aliases and Virtual Aliases
X. Adding Domains
X. Dovecot (IMAP and POP3)
X. Send-only Users
Things to Update
Most of the settings are fine and don’t need to be touched.
That said, some things should/need to be updated from time to time.
- When your Domain or IP address changes, update the PTR and SPF records.
- You shouldn’t need to, but if you need to refresh the sender identity (DKIM), be sure to update your _ file, and the mail._domainkey DNS record. Otherwise, depending on your DMARC/DKIM/SPF settings, mail delivery will begin to fail.
- When your SSL certificate expires, you’ll need to go to your server and update your TLS. Otherwise, you lose encryption! In theory mail is still deliverable, but w/o encryption is bad.