MTA with Postfix - ionathanch/ionathanch.github.io GitHub Wiki
The examples below use domain.tld
as the server domain, mail
as an additional subdomain, and xxx.xxx.xxx.xxx
and xxxx:xxxx:xxxx:xxxx::1
as the IPv4 and IPv6 addresses. Other values meant to be substituted with real values are marked by {braces}
.
Type | Host | Value |
---|---|---|
A | xxx.xxx.xxx.xxx | |
AAAA | xxxx:xxxx:xxxx:xxxx::1 | |
MX | @ | mail.domain.tld |
TXT | @ | v=spf1 mx ~all |
TXT | _dmarc | v=DMARC1; p=none; pct=100 |
TXT | {selector}._domainkey | v=DKIM1; h=sha256; k=rsa; p={public key} |
- SPF: allow emails from addresses pointed at by domains in MX records
- DMARC: do nothing for failed DMARC checks
- DKIM: generated using OpenDKIM
See How-To Geek’s guide for details.
apt install opendkim opendkim-tools
- Add to
/etc/opendkim.conf
:Socket inet:8892@localhost # uncomment AutoRestart Yes AutoRestartRate 10/1h Canonicalization relaxed/simple SignatureAlgorithm rsa-sha256 # ed25519-sha256 not well supported ExternalIgnoreList refile:/etc/opendkim/trusted.hosts InternalHosts refile:/etc/opendkim/trusted.hosts KeyTable refile:/etc/opendkim/key.table SigningTable refile:/etc/opendkim/signing.table
- Create
/etc/opendkim/trusted.hosts
:127.0.0.1 localhost *.domain.tld xxx.xxx.xxx.xxx [xxxx:xxxx:xxxx:xxxx::]/64
- Create
/etc/opendkim/signing.table
:*@domain.tld {selector}._domainkey.domain.tld
- Create
/etc/opendkim/key.table
:{selector}._domainkey.domain.tld domain.tld:{selector}:/etc/opendkim/keys/{selector}.private
- Create
/etc/opendkim/keys/
and in that directory run:$ opendkim-genkey -d domain.tld -s {selector} $ chown opendkim:opendkim /etc/opendkim/keys/{selector}.private $ opendkim-testkey -d domain.tld -s {selector} -vvv
- Copy
/etc/opendkim/keys/mail.txt
to TXT record - Add to
/etc/postconf/main.cf
:milter_protocol = 2 milter_default_action = accept smtpd_milters = inet:localhost:8892 non_smtpd_milters = inet:localhost:8892
The server IPv6 address can be found using ip -6 addr show scope global
.
Configuration file /etc/postfix/main.cf
can be checked with postfix check
, edited with postconf -e {key}={value}
, and reloaded with postfix reload
. See Postfix Configuration Parameters for more.
...
mydomain = domain.tld # mail system domain name
myhostname = domain.tld # mail system hostname; default for $myorigin and other parameters
# mynetworks = xxx.xxx.xxx.xxx [xxxx:xxxx:xxxx:xxxx::]/64 127.0.0.0/8 [::1]/128 [fe80::]/64
# inet_interfaces = loopback-only # don't accept incoming mail
# inet_protocols = all # accept from ipv4 and ipv6
mailbox_size_limit = 0 # no limit
recipient_delimiter = + # mail for [email protected] goes to [email protected]
smtp_address_preference = ipv6 # prefer sending over IPv6 (make sure MX records and SPF include it!)
alias_map = hash:/etc/aliases
virtual_alias_map = hash:/etc/postfix/virtual
# reject if no A record, rDNS, MX record, or malformed domain
smtpd_sender_restrictions =
permit_mynetworks
permit_sasl_authenticated
reject_unknown_client_hostname
reject_unknown_reverse_client_hostname
reject_unknown_sender_domain
reject_non_fqdn_sender
# reject if hostname from HELO/EHLO is missing or wrong
smtpd_helo_required = yes
smtpd_helo_restrictions =
permit_mynetworks
permit_sasl_authenticated
reject_invalid_helo_hostname
reject_non_fqdn_helo_hostname
reject_unknown_helo_hostname
...
Test mail can be sent using mailutils
with mailx
, e.g.
mailx -a "From: Sender Name <[email protected]>" -s "Subject Line" "Recipient Name <[email protected]>"
(Virtual) aliases can be updated using postmap /etc/postfix/virtual
and postalias /etc/aliases
. See virtual(5) and aliases(5) syntax.
Configuration file /etc/postfix/master.cf
needs to have SMTPS and submission uncommented out to use ports 485 and 587.
...
submission inet n - y - - smtpd
# plus a bunch of -o options
smtps inet n - y - - smtpd
# plus a bunch of -o options
...
- Outbound ports 25 and 465 are blocked by default; request unblocking them through Limits.
- Inbound ports need to be allowed through the firewall at
https://console.hetzner.cloud/projects/{project}/firewalls/{server}/rules
.
$ ufw allow Postfix # port 25
$ ufw allow "Postfix SMTPS" # port 465
$ ufw allow "Postfix Submission" # port 587
$ ufw status verbose # check that ports are allowed
$ postfix status # get the Postfix process {PID}
$ netstat -tnlp | grep {PID} # check that Postfix is actually listening on the ports
-
certbot certonly --standalone -d mail.domain.tld
(webservers must not be up!) - Set in
/etc/postfix/main.cf
:tls_random_source = dev:/dev/urandom smtpd_use_tls = yes smtpd_tls_cert_file = /etc/letsencrypt/live/mail.domain.tld/fullchain.pem smtpd_tls_key_file = /etc/letsencrypt/live/mail.domain.tld/privkey.pem smtpd_tls_security_level = may smtp_use_tls = yes smtpd_tls_cert_file = /etc/letsencrypt/live/mail.domain.tld/fullchain.pem smtpd_tls_key_file = /etc/letsencrypt/live/mail.domain.tld/privkey.pem smtp_tls_security_level = may