E-Mail Forward
- Overview
- VPS
- Secure VPS on your-domain.org
- Apache install (enable) on your-domain.org
- DNS Registrar (your-domain.org)
- certbot - Certificate Management for Let's Encrypt
- Apache (disable)
- postfix - E-Mail Transport Agent
- Proxy Postfix using Transport Maps for Incoming Mails on your-domain.org
- Proxy Postfix Relay for SMTP Outgoing Mails
- Clients Mail User Agents (MUA)
- Debug
- Configuring SPF Policy Agent
- Setting up DKIM
- Testing Email Score and Placement
- What is DMARC?
Overview
The following diagrams are what this document will accomplish. The challenge is to obtain and keep a good reputation that other E-Mail handlers around the world will accept. Otherwise your messages will be dumped in the trash can (SPAM) or sent back to you (bounced).
It is a combination of:
- IP Address Reputation
- DNS assignment of an E-Mail name to that IP Address
- Certificates for Authentication and Encryption
- Login protection against Open Spam Relays
A VPS (Virtual Private Server) is a way to obtain a good IP address reputation, and it will stay the same number over time. There are many to choose from, some already have bad reputations and constant streams of hackers knocking on the network, while others have a good reputation and just a few random hackers on your doorstep. Choose wisely!
- MUA - Mail User Agent; Thunderbird, Evolution - Read, send, user interface
- MDA - Mail Delivery Agent; Dovecot - File and organize mail, authorize user accounts
- MTA - Mail Transport Agent; Postfix - Move messsages from one network stop to another
Outgoing: Relay from Inside Home
graph TD; Home_E-Mail.MUA-->Home_Postfix.MTA; Home_Postfix.MTA-->VPS_Postfix.MTA; VPS_Postfix.MTA-->Internet;
Outgoing: Relay from Outside Home
graph TD; Mobile_E-Mail.MUA-->VPS_Postfix.MTA; VPS_Postfix.MTA<-->VPS_Dovecot.MDA; VPS_Dovecot.MDA<-->VPS_Linux; VPS_Postfix.MTA-->Internet;
Incoming: Transport from Internet
graph TD; Internet-->VPS_Postfix.MTA; VPS_Postfix.MTA-->Home_Postfix.MTA; Home_Postfix.MTA-->Home_Dovecot.MDA; Home_Dovecot.MDA<-->Home_Linux; Home_Dovecot.MDA-->Home_E-Mail.MUA;
This document will use:
- your-domain.org : The E-Mail relay we are setting up in this document (VPS_Postfix)
- your-domain.com : The E-Mail server set up in the prior document (Home_Postfix)
Recommendation:
- Bring up a host on a VPS somewhere, and use the Setup Server instructions to secure it.
- Get a domain name and certificate set up and working.
- Install postfix/dovecot combo and relay to your main E-Mail host. Test sending out mail too.
- Install and configure SPF Policy Agent. Test it and make sure all is well.
- Install and configure OpenDKIM to sign your E-Mails. Ensure it works good.
VPS
Create a VPS Cloud Server, less than $10 month for 1GB RAM, 30GB Disk, 1 CPU, 2TB Bandwidth month.
Criteria:
- IP address reputation. May have to test drive to determine IP address. Lookup tools:
- Working control panel. Check online reviews, or test drive. Make sure every button works. Extra points if they allow firewall changes and creating a PTR record.
- Current OS release. Check references below.
- Support availability and response agreements. Test creating a support ticket. Check references below.
- Low cost, check references below.
- https://cloud.ionos.com/servers/vps#packages
- https://www.hostwinds.com/vps/unmanaged-linux
- https://www.inmotionhosting.com/cloud-vps
- https://www.kamatera.com/Products/201/Cloud_Servers
Secure VPS on your-domain.org
Change your root password IMMEDIATELY. Hackers know the algorithm and expliot it from creation time to change time.
Change the ssh port from 22 (File: /etc/ssh/sshd_config). Hackers know that port and constantly attack it.
Check Network
Click on this heading, then refer to these instructions, then come back here with the Back Arrow on the Browser:
Update Package Repository
Click on this heading, then refer to these instructions, then come back here with the Back Arrow on the Browser:
Create New User(s)
The Linux mail user can be <name>@example.com, to keep things clear.
Click on this heading, then refer to these instructions, then come back here with the Back Arrow on the Browser:
Set Host and Domain
Click on this heading, then refer to these instructions, then come back here with the Back Arrow on the Browser:
Set Date and Time
Click on this heading, then refer to these instructions, then come back here with the Back Arrow on the Browser:
Monitor crack attempts
Install firewall and fail2ban on your-domain.org
Be sure the system firewall is installed and also the "Block Bad Actors" firewall.sh script.
Click on this heading, then refer to these instructions, then come back here with the Back Arrow on the Browser:
Add rules for E-Mail smtp and smtps.
- Debian:
$ sudo apt-get install fail2ban mailutils
- RedHat:
$ sudo dnf install fail2ban mailx
Make sure firewall rules open port smtp(25) and smtps(465):
- Debian
$ sudo ufw allow 25
$ sudo ufw allow 465
$ sudo ufw status numbered
To Action From
-- ------ ----
[ 1] 22 ALLOW IN Anywhere
[ 2] 25 ALLOW IN Anywhere
[ 3] 465 ALLOW IN Anywhere
[ 4] 22 (v6) ALLOW IN Anywhere (v6)
[ 5] 25 (v6) ALLOW IN Anywhere (v6)
- RedHat
$ sudo firewall-cmd --add-service=smtp
success
$ sudo firewall-cmd --add-service=smtps
success
$ sudo firewall-cmd --list-services
smtp smtps ssh
$ firewall-cmd --runtime-to-permanent
success
$ firewall-cmd --reload
success
Configure fail2ban
Click on this heading, then refer to these instructions, then come back here with the Back Arrow on the Browser:
Secure postfix
File: /etc/fail2ban/jail.d/postfix.local
[postfix]
enabled = true
maxretry = 3
bantime = 1d
port = smtp,465,submission
[postfix-sasl]
enabled = true
maxretry = 3
bantime = 1d
port = smtp,465,submission,imap,imaps,pop3,pop3s
File: /etc/fail2ban/jail.d/dovecot.local
[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps,submission,465,sieve
logpath = /var/log/maillog
findtime = 1200
bantime = 1d
Secure ssh
File: /etc/fail2ban/jail.d/sshd.local
[sshd]
port = XXXX
enabled = true
maxretry = 3
bantime = 1d
Log Monitors on your-domain.org
Install Logwatch
Click on this heading, then refer to these instructions, then come back here with the Back Arrow on the Browser:
Install Logcheck:
Click on this heading, then refer to these instructions, then come back here with the Back Arrow on the Browser:
LogWatcher
Create
Put this script in the /root directory, and install the dependencies listed.
#!/bin/bash
##############################################################################
#
# File: logwatcher.sh
#
# Purpose: Watch for interesting new things in log files and e-mail them
#
# Dependencies:
# * Debian:
# apt-get install git clang zlib1g-dev
# * RedHat:
# dnf install git clang zlib-devel
#
# git clone https://github.com/mbucc/retail
#
# Author Date Description
# ---------- -------- --------------------------------------------------------
# D. Cohoon Feb-2023 Created
##############################################################################
MAILTO=root
DIR=/root
OS=$(/usr/bin/hostnamectl|/usr/bin/grep 'Operating System'|/usr/bin/cut -d: -f2|/usr/bin/awk '{print $1}')
cd ${DIR}
#--------------
log_check () {
OFFSET=${1}
LOGFILE=${2}
FILTER=${3}
OUTPUT=$(/usr/bin/mktemp)
/root/retail/retail -o ${OFFSET} ${LOGFILE} | ${FILTER} >${OUTPUT}
if [ -s ${OUTPUT} ]; then
/bin/cat ${OUTPUT} | /usr/bin/mail -s "Logwatcher.sh: ${OFFSET}" ${MAILTO} 2>/dev/null
fi
rm -rf ${OUTPUT}
}
#
#--------------
case ${OS} in
AlmaLinux)
FAIL2BAN_LOG=/var/log/fail2ban.log
POSTFIX_LOG=/var/log/maillog
AUTH_LOG=/var/log/secure
;;
Ubuntu|Debian)
FAIL2BAN_LOG=/var/log/fail2ban.log
POSTFIX_LOG=/var/log/syslog
AUTH_LOG=/var/log/auth.log
;;
esac
# Offset Log File Filter
# -------- --------------------- -------------------------
log_check .fail2ban "${FAIL2BAN_LOG}" ${DIR}/filter_fail2ban.sh
#
log_check .postfix "${POSTFIX_LOG}" ${DIR}/filter_postfix.sh
#
log_check .sshd "${AUTH_LOG}" ${DIR}/filter_ssh.sh
#
log_check .dovecot "${AUTH_LOG}" ${DIR}/filter_dovecot.sh
Schedule
# cat /etc/cron.d/logwatcher
# /etc/cron.d/logwatcher: crontab entries for the logwatcher.sh script
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
@reboot root /root/logwatcher.sh
2 * * * * root /root/logwatcher.sh
# EOF
Filters
File: filter_fail2ban.sh
/usr/bin/grep "Ban"
File: filter_postfix.sh
/usr/bin/grep "postfix"|/usr/bin/grep 'disconnect from unknown'
File: filter_ssh.sh
/usr/bin/grep "ssh" | /usr/bin/egrep "Failed|invalid format"
File: filter_dovecot.sh
/usr/bin/grep "dovecot" | /usr/bin/grep "authentication failure"
Make the Scripts Executable
$ chmod 755 *.sh
Reference:
- Watch - System Alerts
Apache install (enable) on your-domain.org
Click on this heading, then refer to these instructions, then come back here with the Back Arrow on the Browser:
Test it on http://<domain.name>
Add SSL
- Debian
$ sudo ufw allow 443/tcp
- RedHat
$ sudo firewall-cmd --add-service=https
success
$ sudo firewall-cmd --list-services
http https smtp smtps ssh
$ sudo firewall-cmd --runtime-to-permanent
success
$ sudo firewall-cmd --reload
success
Change the default landing page to blank
File: /var/www/html/index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<div class="main_page">
</div>
</body>
</html>
DNS Registrar (your-domain.org)
Register name.
https://godaddy.com https://www.namecheap.com/ https://www.domain.com/
DNS Updates
Create Advanced DNS records, using IP Address of VPS server:
HOST
Type Host Value TTL
---------- ----------- ------------------- ----
A Record @ <IP Address> Auto
A Record mail <IP Address> Auto
TXT Record @ v=spf1 mx -all Auto
Type Host Value Priority TTL
---------- ----------- ------------------- -------- ----
MX Record @ <Domain Name> 10 Auto
Lookup status via dig -t <Type> <Domain>
$ dig -t a +short <Domain Name>
123.123.123.123
$ dig -t mx +short <Domain Name>
10 <Domain Name>.
To install dig:
$ sudo apt-get install dnsutils
$ sudo dnf install bind-utils
Create PTR Record
Using the Control Panel on the VPS, update the PTR record. If they do not allow this, create a support ticket, they will do it then, just trying to limit spammers.
Test your PTR record. Using the IP Address, it should show your domain, proving you have control over the IP Address.
dig -x 1.2.3.4
;; ANSWER SECTION:
1.2.3.4.in-addr.arpa. 86400 IN PTR mail.<Domain Name>.
certbot - Certificate Management for Let's Encrypt
To create and maintain LetsEncrypt certificates using Apache web server
Install
$ sudo systemctl unmask apache2
$ sudo systemctl enable apache2
$ sudo systemctl start apache2
$ sudo apt-get install certbot
$ sudo apt-get install python3-certbot-apache
$ sudo systemctl unmask httpd
$ sudo systemctl enable httpd
$ sudo systemctl start httpd
$ sudo dnf install certbot
$ sudo dnf install python3-certbot-apache
$ sudo certbot plugins
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* apache
Description: Apache Web Server plugin
Interfaces: IAuthenticator, IInstaller, IPlugin
Entry point: apache = certbot_apache._internal.entrypoint:ENTRYPOINT
* standalone
Description: Spin up a temporary webserver
Interfaces: IAuthenticator, IPlugin
Entry point: standalone = certbot._internal.plugins.standalone:Authenticator
* webroot
Description: Place files in webroot directory
Interfaces: IAuthenticator, IPlugin
Entry point: webroot = certbot._internal.plugins.webroot:Authenticator
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Configure
Be sure to get certificates for the domain and all subdomains (hosts)
$ certbot --apache -d your-domain.org -d mail.your-domain.org
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator apache, Installer apache
Enter email address (used for urgent renewal and security notices)
(Enter 'c' to cancel): you@your-domain.org
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must
agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
Account registered.
No names were found in your configuration files. Please enter in your domain
name(s) (comma and/or space separated) (Enter 'c' to cancel): your-domain.org
Requesting a certificate for your-domain.org
Performing the following challenges:
http-01 challenge for your-domain.org
Enabled Apache rewrite module
Waiting for verification...
Cleaning up challenges
Created an SSL vhost at /etc/apache2/sites-available/000-default-le-ssl.conf
Enabled Apache socache_shmcb module
Enabled Apache ssl module
Deploying Certificate to VirtualHost /etc/apache2/sites-available/000-default-le-ssl.conf
Enabling available site: /etc/apache2/sites-available/000-default-le-ssl.conf
Enabled Apache rewrite module
Redirecting vhost in /etc/apache2/sites-enabled/000-default.conf to ssl vhost in /etc/apache2/sites-available/000-default-le-ssl.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://your-domain.org
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Subscribe to the EFF mailing list (email: you@your-domain.org).
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/your-domain.org/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/your-domain.org/privkey.pem
Your certificate will expire on 2023-05-08. To obtain a new or
tweaked version of this certificate in the future, simply run
certbot again with the "certonly" option. To non-interactively
renew *all* of your certificates, run "certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Apache (disable)
Apache is not needed, so disable it to reduce threat footprint.
$ sudo systemctl stop apache2
$ sudo systemctl disable apache2
$ sudo systemctl mask apache2
$ sudo ufw status numbered
# -> ufw delete <n> for ports 80 & 443
$ sudo systemctl stop httpd
$ sudo systemctl disable httpd
$ sudo systemctl mask httpd
$ sudo firewall-cmd --remove-service=https
success
$ sudo firewall-cmd --list-services
http smtp smtps ssh
$ sudo firewall-cmd --remove-service=http
success
$ sudo firewall-cmd --list-services
smtp smtps ssh
$ sudo firewall-cmd --runtime-to-permanent
success
When the Let's Encrypt Certificate expires, you will need to enable it again and open up ports.
postfix - E-Mail Transport Agent
Install postfix MTA and remove exim4, if it is installed. Postfix is more mature and full-featured.
TLS http://www.postfix.org/TLS_README.html
Install on your-domain.org
$ sudo apt-get remove exim4-base
$ sudo apt-get install postfix
$ sudo dnf remove exim
$ sudo dnf install postfix
Configure on your-domain.org
- smtp -> outgoing mail
- smtpd <- incoming mail (daemon)
Complete main.cf file contents
~
mydomain = your-domain.org
myorigin = $mydomain
#myorigin = /etc/mailname
~
File main.cf
#.........................................................................
#
# * smtpd <- incoming mail (daemon)
#
smtpd_tls_cert_file = /etc/letsencrypt/live/your-domain.org/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/your-domain.org/privkey.pem
smtpd_use_tls = yes
smtpd_tls_security_level=may
smtpd_tls_auth_only = yes
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
#
# Enforce TLSv1.3 or TLSv1.2
# smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
# smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
# smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
# smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
#
# Sending relays allowed only if:
# -> you are on mynetworks
# -> you are logged in
# all others are deferred (temp error 4.x.x),
# like a permanent failure that won't go away
# until 1) added to mynetworks, or 2) sasl authenticated
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
# Sending sasl auth from Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
# I am a relay to the world
relayhost =
#.........................................................................
#
# * smtp -> outgoing mail
#
smtp_tls_CApath=/etc/ssl/certs
smtp_tls_security_level=may
smtp_tls_loglevel = 1
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
# Receiving transport table specifies a mapping from email addresses to
# message delivery transports and next-hop destinations.
# (relay forwarding back out)
transport_maps = hash:/etc/postfix/transport
relay_domains = your-domain.com
# .org host
myhostname = mail.your-domain.org
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
# Accept final destination mail for mail.your-domain.org, your-domain.org, or locals
mydestination = $myhostname, your-domain.org, localhost.your-domain.org, localhost
#.........................................................................
# Allow my host and the .com host to send (relay out)
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 5.6.7.8
inet_interfaces = all
inet_protocols = ipv4
# Message restrictions
mailbox_size_limit = 0
message_size_limit = 52428800
header_size_limit = 4096000
recipient_delimiter = +
#compatibility_level = 2
Complete relay contents of master.cf
No spaces between = sign
File: master.cf
~
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (no) (never) (100)
# ==========================================================================
smtp inet n - y - - smtpd
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o milter_macro_daemon_name=ORIGINATING
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
# The preceeding 4 lines require SSL login for relay to internet (.com -> .org -> internet)
# need cert for mail.your-domain.org, your-domain.org;
# and sasl_passwd for mail.your-domain.org unix login on www.your-domain.com
~
:wq
Reload Config
$ sudo postfix reload
Definitions of master fields
-
service
This refers to the name in /etc/services and matches a name to a port number.
-
type
Internet or pipe. Internet is a network communication, while pipe is a special file on disk that echos input as output used for local communication only.
-
private
Access to some components is restricted to the Postfix system itself. This column is marked with a y for private access (the default) or an n for public access. inet components must be marked n for public access, since network sockets are necessarily available to other processes.
-
unpriv
Postfix components run with the least amount of privilege required to accomplish their tasks. They set their identity to that of the unprivileged account specified by the mail_owner parameter. The default installation uses postfix. The default value of y for this column indicates that the service runs under the normal unprivileged account. Services that require root privileges are marked with n.
-
chroot
Many components can be chrooted for additional security. The chroot location is specified in the queue_directory parameter in main.cf. The default is for a service to run in a chroot environment; however, the normal installation marks all components with an n so they are not chrooted when they run. Chrooting a service adds a level of complexity that you should thoroughly understand before taking advantage of the added security. See Section 4.8 later in the chapter for more information on running Postfix services in a chroot environment.
-
wakeup
Some components require a wake-up timer to kick them into action at the specified interval. The pickup daemon is one example. At its default setting of 60 seconds, the master daemon wakes it up every minute to see if any new messages have arrived in the maildrop queue. The other services that require a wake-up are the qmgr and flush daemons. A question mark character (?) can be added at the end of the time to indicate that a wake-up event should be sent only if the component is being used. A 0 for the time interval indicates that no wake-up is required. The default is 0, since only the three components mentioned require a wake-up. The values as they are set in the Postfix distribution should work for almost all situations. Other services should not have wakeup enabled.
-
maxproc
Limits the number of processes that can be invoked simultaneously. If unspecified here, the value comes from the parameter default_process_limit in main.cf, which is set to 100 by default. A setting of 0 means no process limit. You may want to adjust maxproc settings if you run Postfix on a system with limited resources or you want to optimize different aspects of the system.
-
command
The actual command used to execute a service is listed in the final column. The command is specified with no path information, because it is expected to be in the Postfix daemon directory specified by the daemon_directory parameter in main.cf. By default the directory is /usr/libexec/postfix. All of the Postfix commands can be specified with one or more -v options to turn on increasingly more verbose logging information, which can be helpful if you must troubleshoot a problem. You can also enable information for a debugging program with the -D option. See the DEBUG_README file that comes with the Postfix distribution for more information on debugging if necessary.
Proxy Postfix using Transport Maps for Incoming Mails on your-domain.org
A postfix transport(5) table allows one domain to transfer incoming SMTP messages to another domain. For instance the .org domain will transfer all .com messages to the .com domain automatically.
Repeated postfix file contents from above to clarify this is for transporting from .org to .com
Configure
File: /etc/postfix/main.cf:
~
transport_maps = hash:/etc/postfix/transport
~
Set postfix to accept mails for the .com addresse.
Repeated postfix file contents from above to clarify this is for transporting from .org to .com
File: /etc/postfix/main.cf:
~
relay_domains = example.com
~
Transport Definitions
Create a transport table to redirect all mail for one domain as well as mail for "user@mydomain.org" to another domain. You can also specify another port, to bypass port 25 restrictions.
File: /etc/postfix/transport
example.com smtp:[example.com]:10025
user@mydomain.org smtp:[example.com]:10025
Make it a database
Create a postmap database from the flat ascii file.
$ sudo postmap /etc/postfix/transport
Reload Config
Finally, reload the postfix configuration files.
$ sudo postfix reload
Reference:
- https://serverfault.com/questions/67134/proxy-mail-to-different-smtp-server-with-postfix
- http://www.postfix.org/postconf.5.html#permit_auth_destination
- http://www.postfix.org/transport.5.html
Proxy Postfix Relay for SMTP Outgoing Mails
To send mails from a non-standard port, use a .com domain to relay to a .org domain, with the .org relay set to = (basically null) and the .com relay = ...org.
Change MX records in no-ip.com from mail1.no-ip.com to mail.your-domain.org
Log into noip.com, go to DNS and select *.your-domain.com
. At the bottom of the page you can change the mail1.no-ip.com record to mail.your-domain.org.
Don't forget to save and lookup the new value using dig -t MX your-domain.com
.
Change TXT spf record in no-ip.com from noip, to:
For your-domain.com domain:
Type | Host | Value | Priority | TTL |
---|---|---|---|---|
MX Record | @ | your-domain.org | 10 | Auto |
TXT Record | @ | v=spf1 mx a include:your-domain.org ~all | Auto |
SPF tools: https://www.dynu.com/en-US/NetworkTools/SPFGenerator# https://mxtoolbox.com/spf.aspx
- Try not to add more than required, you might create a potential infinite loop. 8
On the DNS for .com, create a TXT record like this
"v=spf1 mx a include:<Domain of .org> ~all"
Basically is says "In the DNS TXT record for email destination you@your-domain.com, validate the MX IP Address of DNS record for domain your-domain.com" for ~all; When an SPF record includes ~all (softfail qualifier), receiving servers typically accept messages from senders that aren't in your SPF record, but mark them as suspicious.
Reference: http://www.open-spf.org/FAQ/Common_mistakes/#list-domains
Test e-mail results from google:
~
ARC-Authentication-Results: i=1; mx.google.com;
spf=pass (google.com: domain of you@your-domain.com designates 1.2.3.4 as permitted sender) smtp.mailfrom=you@your-domain.com
Received: from mail.your-domain.org (mail.your-domain.org. [1.2.3.4])
by mx.google.com with ESMTPS id o6-20020a0dcc06000000b005363cf948basi2222119ywd.61.2023.02.25.05.45.43
for <you.name@gmail.com>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Sat, 25 Feb 2023 05:45:44 -0800 (PST)
Received-SPF: pass (google.com: domain of you@your-domain.com designates 1.2.3.4 as permitted sender) client-ip=1.2.3.4;
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of you@your-domain.com designates 1.2.3.4 as permitted sender) smtp.mailfrom=you@your-domain.com
Received: from www.your-domain.com (unknown [5.6.7.8])
by mail.your-domain.org (Postfix) with ESMTPSA id 9071FD3C93
for <you.name@gmail.com>; Sat, 25 Feb 2023 13:45:43 +0000 (UTC)
~
Change your-domain.com postfix/main.cf relay to your-domain.org
File: /etc/postfix/main.cf
relayhost = [mail.your-domain.org]:465
Add your-domain.org unix login on host your-domain.com
File: /etc/postfix/sasl/sasl_passwd
[mail.your-domain.org]:465 you:********
Create a postfix DB from flat file
$ sudo postmap /etc/postfix/sasl/sasl_passwd
Enable TLS on your-domain.org
TLS requires certificate(s) and SASL login verification.
The logon verification is done by Docevot using the userdb setting pam[1], while the postfix SASL verification uses a unix pipe /var/spool/postfix/private/auth to talk to Dovecot.
The encryption is enabled by Let's Encrypt certificates (one for the domain, another for each subdomain), over the smtps (post 465) network socket to the client. The master.cf file -o settings override the main.cf settings, ensuring a connection is only accepted if:
- TLS certificate is working and accepted by both parties, on port 465
- SASL logon passes, using postfix -> Dovecot -> pam login.
OR
- The incoming IP address is part of mynetwork, on port 25
Plugable Authentication Module (PAM) is the Linux login method for users
Two Steps:
- install dovecot
$ sudo apt-get install dovecot-core
$ sudo dnf install dovecot
Add login
to dovecot auth
File: /etc/dovecot/conf.d/10-auth.conf
~
auth_mechanisms = plain login
~
:wq
Set the certificates to letsencrypt, require ssl and prefer server of the ciphers
File: /etc/dovecot/conf.d/10-ssl.conf
~
ssl = required
~
ssl_cert = </etc/letsencrypt/live/your-domain.org/fullchain.pem
ssl_key = </etc/letsencrypt/live/your-domain.org/privkey.pem
~
# Comment out default certs
~
ssl_prefer_server_ciphers = yes
~
:wq
Set up a local unix pipe for dovecot and postfix to communicate this authorization data, under the service_auth set of brackets.
File: /etc/dovecot/conf.d/10-master.conf
~
unix_listener /var/spool/postfix/private/auth {
group = postfix
mode = 0660
user = postfix
}
~
:wq
- Set the receiving certificates in Postfix, require TLS using Dovecot.
Repeated postfix file contents from above to clarify this is for relaying TLS on .org to the Internet
File: /etc/postfix/main.cf
~
#smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
#smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_cert_file = /etc/letsencrypt/live/your-domain.org/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/your-domain.org/privkey.pem
smtpd_use_tls = yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_security_level=may
~
# sasl auth from Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
~
:wq
Repeated postfix file contents from above to clarify this is for relaying TLS on .org to the Internet
File: /etc/postfix/master.cf
~
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (no) (never) (100)
# ==========================================================================
smtp inet n - y - - smtpd
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o milter_macro_daemon_name=ORIGINATING
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
# The preceeding 4 lines require SSL login for relay to internet (.com -> .org -> internet)
# need cert for mail.your-domain.org, your-domain.org;
# and sasl_passwd for mail.your-domain.org unix login on www.your-domain.com
~
:wq
- Make sure port 465 (smtps) is opened by Postfix
Open on localhost
# nmap -sT -O localhost
Starting Nmap 7.70 ( https://nmap.org ) at 2023-02-19 16:46 EST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00019s latency).
Other addresses for localhost (not scanned): ::1
Not shown: 992 closed ports
PORT STATE SERVICE
22/tcp open ssh <-
25/tcp open smtp <-
80/tcp open http <-
110/tcp open pop3
143/tcp open imap
443/tcp open https <-
465/tcp open smtps <-
993/tcp open imaps
995/tcp open pop3s
RedHat 9 /etc/services shows port 465 as urd, so I switched the urd and alias smtps.
# grep smtps /etc/services
smtps 465/tcp urd # URL Rendesvous Directory for SSM / SMTP over SSL (TLS)
Now ss looks better:
# ss -ltap
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:ssh 0.0.0.0:* users:(("sshd",pid=1314,fd=3))
LISTEN 0 100 0.0.0.0:smtp 0.0.0.0:* users:(("master",pid=23736,fd=13))
LISTEN 0 100 0.0.0.0:imaps 0.0.0.0:* users:(("dovecot",pid=23599,fd=41))
LISTEN 0 100 0.0.0.0:pop3s 0.0.0.0:* users:(("dovecot",pid=23599,fd=23))
LISTEN 0 100 0.0.0.0:pop3 0.0.0.0:* users:(("dovecot",pid=23599,fd=21))
LISTEN 0 100 0.0.0.0:imap 0.0.0.0:* users:(("dovecot",pid=23599,fd=39))
LISTEN 0 100 0.0.0.0:smtps 0.0.0.0:* users:(("master",pid=23736,fd=17))
ESTAB 0 52 1.2.3.4:ssh 5.6.7.8:44958 users:(("sshd",pid=2402,fd=4),("sshd",pid=2278,fd=4))
LISTEN 0 128 [::]:ssh [::]:* users:(("sshd",pid=1314,fd=4))
LISTEN 0 100 [::]:imaps [::]:* users:(("dovecot",pid=23599,fd=42))
LISTEN 0 100 [::]:pop3s [::]:* users:(("dovecot",pid=23599,fd=24))
LISTEN 0 100 [::]:pop3 [::]:* users:(("dovecot",pid=23599,fd=22))
LISTEN 0 100 [::]:imap [::]:* users:(("dovecot",pid=23599,fd=40))
Open to internet
$ sudo firewall-cmd --list-services
http https smtp smtps ssh
Clients Mail User Agents (MUA)
These are the programs where a human interface resides, and where everybody reads, sends, deletes, and manages their E-Mail. Names such as: Thunderbird, Evolution, Mutt, Gmail, Outlook, etc.
-
Mail Transport Agents (MTA) only connect here. Do not connect your MUA to this port!
-
SMTP (port 25): This is an restricted relay port, defined on host example.org and controlled by the /etc/postfix/master.cf smtp definition. Only addresses in $mydestination will be accepted, and nothing else will be relayed in. The transport definition will forward to it's list of addresses/domains. After a client is authenticated, it will be allowed to relay out on port 25. Process master, forked from postfix, performs this responsibility.
- -o smtpd_relay_restrictions=permit_sasl_authenticated,reject: means that only authenticated connections can relay out
-
-
Client (MUA) connect here to SEND mail only
-
SMTPS (port 465): This is defined on host example.org, and is always an encrypted port, controlled by the /etc/postfix/master.cf smtps definition. All authentications occur here. Process master, forked from postfix, performs this responsibility.
-
-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject: means that only $mynetworks or authenticated connections can submit messages to be sent. MUA will connect using this rule.
-
Authentication is done using /etc/dovecot/conf.d/10-auth.conf auth_mechanism=login definition, over unix pipe unix_listener /var/spool/postfix/private/auth declared in file /etc/dovecot/conf.d/10-master.conf. Linux PAM verification occurs using file /etc/pam.d/dovecot and passdb{driver=pam} in file /etc/dovecot/conf.d/auth-system.conf.ext.
-
-
Unix pipe for postfix to dovecot authenication of clients.
$ sudo ls -l /var/spool/postfix/private/auth
srw-rw---- 1 postfix postfix 0 Feb 10 10:21 /var/spool/postfix/private/auth
-
Client (MUA) connect here to READ/MANAGE mail only
-
IMAPS (port 993): This is defined on the example.com host Dovecot installation, file /etc/dovecot/conf.d/10-master.conf, section service imap_listener imaps. Process imap, forked from dovecot, performs this responsibility.
-
Authentication is done using /etc/dovecot/conf.d/10-auth.conf auth_mechanism=plain definition, over unix_listener auth_userdb declared in file /etc/dovecot/conf.d/10-master.conf. Linux PAM verification occurs using file /etc/pam.d/dovecot and passdb{driver=pam} in file /etc/dovecot/conf.d/auth-system.conf.ext.
-
Port 587, aka: submission, is purposely ommited because it is a partial encryption called STARTTLS. This is deemed un-secure and not recommended.
MUA Connection Definitions
Read Mail
- Server: mail.example.com
- User: <linux user defined on the E-Mail .com host>
- Password: <linux user password defined on the E-Mail .com host>
- SSL: ON
- Port: 993
Send Mail
- Server: smtp.example.org
- User: <linux user defined above on the E-Mail .org host>
- Password: <linux user password defined above on the E-Mail .org host>
- SSL: ON
- Port: 465
Debug
If mail queues up to send/resend, you can check and clear to queue
List mail queue
mailq
Look at message
postcat -vq DCE2182DEA
Flush queue
postsuper -d ALL deferred
or
postqueue -f
Cache files (send/receive) are in data_directory (/var/lib/postfix) as Berkley Databasees
Install a Mail User Agent for ssh
mutt is a nice local mail reader, for times when the network mail may not work, at least the local mail will.
$ sudo apt-get install mutt
$ sudo dnf install mutt
Install a nice ssh capable log reader
I like lnav. Just run lnav
and by default it will read the syslog. Or run lnav /var/log/mail.log
.
$ sudo apt-get install lnav
$ sudo dnf install lnav
Install a package marking tool
Debian only: apt-clone will create a nice bundle of all your current packages. Save this off in case you have to re-build your server.
$ sudo apt-get install apt-clone
Certificate Expiration Check
Run this every week/day in cron /root/cert_expire.sh 2
to E-Mail you reminders before it expires.
File: ~/cert_expire.sh
#!/bin/bash
# ----------------------------------------------------------------------
#
# File: cert_expire.sh
#
# Purpose: See what the expiration date is for Let's Encrypt Certificate
#
#
# s_client : The s_client command implements a generic SSL/TLS client
# which connects to a remote host using SSL/TLS.
# -servername $DOM : Set the TLS SNI (Server Name Indication) extension
# in the ClientHello message to the given value.
# -connect $DOM:$PORT : This specifies the host ($DOM) and optional
# port ($PORT) to connect to.
# x509 : Run certificate display and signing utility.
# -noout : Prevents output of the encoded version of the certificate.
# -dates : Prints out the start and expiry dates of a TLS or SSL certificate.
#
# Don Cohoon - Jan 2023
# ----------------------------------------------------------------------
#
#
if [ $# -gt 0 ]; then
A=${1}
else
/usr/bin/echo "1) E-Mail"
/usr/bin/echo "2) File"
/usr/bin/echo "3) Web"
/usr/bin/echo "4) Local"
read A
fi
case ${A}
in
1)
/usr/bin/echo "REMINDER: Restart postfix and dovecot to enable new certs"
/usr/bin/echo "=> E-Mail Certificate: CTRL-C to exit"
#/usr/bin/openssl s_client -connect mail.your-domain.org:25 -starttls smtp 2>/dev/null|/usr/bin/openssl x509 -noout -dates
/usr/bin/openssl s_client -connect mail.your-domain.org:465 2>/dev/null|/usr/bin/openssl x509 -noout -dates
;;
2)
/usr/bin/echo "=> File Certificate"
sudo /usr/bin/openssl x509 -enddate -noout -in /etc/letsencrypt/live/your-domain.org/fullchain.pem
;;
3)
/usr/bin/echo "REMINDER: Restart apache2 and nginx to enable new certs"
/usr/bin/echo "=> www.your-domain.org Certificate: CTRL-C to exit"
/usr/bin/openssl s_client -servername your-domain.org -connect www.your-domain.org:443 2>/dev/null | /usr/bin/openssl x509 -noout -dates
;;
4)
/usr/bin/echo "REMINDER: Restart apache2 and nginx to enable new certs"
/usr/bin/echo "=> Local Web Certificate: CTRL-C to exit"
/usr/bin/openssl s_client -connect localhost:443 | /usr/bin/openssl x509 -noout -dates
;;
esac
Configuring SPF Policy Agent
We also need to tell our Postfix SMTP server to check for SPF record of incoming emails. This doesn’t help ensure outgoing email delivery but help with detecting forged incoming emails.
Install required packages:
- Debian
sudo apt install postfix-policyd-spf-python
- RedHat
sudo dnf install pypolicyd-spf
Test SPF
If you know the sender, recipient, and client_address, you can test them before turning SPF on in postfix.
Must have blank line as last input for policyd-spf
# Python Site Packages = /usr/lib/python3.9/site-packages/
# Source = /usr/lib/python3.9/site-packages/spf_engine/*
/usr/libexec/postfix/policyd-spf <<EOF
request=smtpd_access_policy
protocol_state=RCPT
protocol_name=SMTP
helo_name=ccpub6
queue_id=hv8rp02v1sso
instance=12345.6789
sender=foo
recipient=bar
client_address=1.2.3.4
client_name=bubba
EOF
Configure SPF
Add the following lines at the end of the file, which tells Postfix to start the SPF policy daemon when it’s starting itself.
- Debian
File: /etc/postfix/master.cf
policyd-spf unix - n n - 0 spawn
user=policyd-spf argv=/usr/bin/policyd-spf
- Redhat
File: /etc/postfix/master.cf
policyd-spf unix - n n - 0 spawn
user=nobody argv=/usr/libexec/postfix/policyd-spf
Append the following lines at the end of the file. The first line specifies the Postfix policy agent timeout setting. The following lines will impose a restriction on incoming emails by rejecting unauthorized email and checking SPF record.
File: /etc/postfix/main.cf
policyd-spf_time_limit = 3600
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf
Restart Postfix.
sudo systemctl restart postfix
Next time, when you receive an email from a domain that has an SPF record, you can see the SPF check results in the raw email header. The following header indicates the sender sent the email from an authorized host.
Received-SPF: Pass (sender SPF authorized).
Debug SPF
Config file, debug setting:
File: /etc/python-policyd-spf/policyd-spf.conf
~
# level 1 is default
debugLevel = 5
~
:wq
man policyd-spf.conf
check_policy_service Unix pipe:
File: /var/spool/postfix/private/policyd-spf
srw-rw-rw-. 1 postfix postfix 0 Feb 25 14:37 /var/spool/postfix/private/policyd-spf
Block Domains and E-Mail Addresses using Postfix access
The following example uses an indexed file, so that the order of table entries does not matter.
File: /etc/postfix/main.cf:
smtpd_client_restrictions =
check_client_access hash:/etc/postfix/access
The example permits access by the client at address 1.2.3.4 but rejects all other clients in 1.2.3.0/24.
File: /etc/postfix/access:
1.2.3 REJECT
1.2.3.4 OK
aol.com REJECT
Create hash map of ascii file, and restart postfix
$ sudo postmap /etc/postfix/access
$ sudo systemctl restart postfix
Reference:
- http://www.open-spf.org/FAQ/Common_receiver_mistakes/
- https://www.mankier.com/5/policyd-spf.conf
- http://www.postfix.org/access.5.html
Setting up DKIM
OpenDKIM is an open source implementation of the DKIM (Domain Keys Identified Mail) sender authentication system proposed by the E-mail Signing Technology Group (ESTG), now standardized by the IETF (RFC6376). It also includes implementations of the RFC5617) Vouch By Reference (VBR, RFC5518) proposed standard and the experimental Authorized Third Party Signatures protocol (ATPS, RFC6541).
Install OpenDKIM
- Debian
sudo apt install opendkim opendkim-tools
- RedHat
# enable the CodeReady Linux Builder repository. You already have access to it; you just need to enable it.
dnf config-manager --set-enabled crb
# install the EPEL RPM
dnf install epel-release epel-next-release
# install
sudo dnf install opendkim opendkim-tools
Configure OpenDKIM
Add user postfix to group opendkim.
sudo gpasswd -a postfix opendkim
Check OpenDKIM main configuration file for Syslog, Logwhy.
Logwhy will generate more detailed logs for debugging.
File: /etc/opendkim.conf
Syslog yes
Logwhy yes
Set Canonicalization used when signing messages. The recognized values are relaxed and simple as defined by the DKIM specification. The default is simple. The value may include two different canonicalizations separated by a slash ("/") character, in which case the first will be applied to the header and the second to the body.
Set operating Modes. The string is a concatenation of characters that indicate which mode(s) of operation are desired. Valid modes are s (signer) and v (verifier). The default is sv except in test mode (see the opendkim(8) man page) in which case the default is v. When signing mode is enabled, one of the following combinations must also be set: (a) Domain, KeyFile, Selector, no KeyTable, no SigningTable; (b) KeyTable, SigningTable, no Domain, no KeyFile, no Selector; (c) KeyTable, SetupPolicyScript, no Domain, no KeyFile, no Selector.
File: /etc/opendkim.conf
Canonicalization relaxed/simple
Mode sv
- Do not set Domain or SubDomains, they are not required because we will use SigningTable.
- Do not set Selector, it is not required because we will use SigningTable.
- Do not set KeyFile, it is not required because we will use KeyTable.
Add restart definitions to the end of the file.
-
AutoRestart (Boolean): Automatically re-start on failures. Use with caution; if the filter fails instantly after it starts, this can cause a tight fork(2) loop.
-
AutoRestartCount (integer): Sets the maximum automatic restart count. After this number of automatic restarts, the filter will give up and terminate. A value of 0 implies no limit; this is the default.
-
AutoRestartRate (string): Sets the maximum automatic restart rate. If the filter begins restarting faster than the rate defined here, it will give up and terminate. This is a string of the form n/t[u] where n is an integer limiting the count of restarts in the given interval and t[u] defines the time interval through which the rate is calculated; t is an integer and u defines the units thus represented ("s" or "S" for seconds, the default; "m" or "M" for minutes; "h" or "H" for hours; "d" or "D" for days). For example, a value of "10/1h" limits the restarts to 10 in one hour. There is no default, meaning restart rate is not limited.
File: /etc/opendkim.conf
AutoRestart yes
AutoRestartCount 10
AutoRestartRate 10/1H
Reference: http://www.opendkim.org/opendkim.conf.5.html
Map Domains to Keys
The next two configuration items will create maps for E-Mail Domains in the From: header, to keys used to sign messages.
-
KeyTable (dataset): Gives the location of a file mapping key names to signing keys. If present, overrides any KeyFile setting in the configuration file. The data set named here maps each key name to three values: (a) the name of the domain to use in the signature’s "d=" value; (b) the name of the selector to use in the signature’s "s=" value; and (c) either a private key or a path to a file containing a private key. If the first value consists solely of a percent sign ("%") character, it will be replaced by the apparent domain of the sender when generating a signature. If the third value starts with a slash ("/") character, or "./" or "../", then it is presumed to refer to a file from which the private key should be read, otherwise it is itself a PEM-encoded private key or a base64-encoded DER private key; a "%" in the third value in this case will be replaced by the apparent domain name of the sender. The SigningTable (see below) is used to select records from this table to be used to add signatures based on the message sender.
-
SigningTable (dataset): Defines a table used to select one or more signatures to apply to a message based on the address found in the From: header field. Keys in this table vary depending on the type of table used; values in this data set should include one field that contains a name found in the KeyTable (see above) that identifies which key should be used in generating the signature, and an optional second field naming the signer of the message that will be included in the "i=" tag in the generated signature. Note that the "i=" value will not be included in the signature if it conflicts with the signing domain (the "d=" value).
-
If the first field contains only a "%" character, it will be replaced by the domain found in the From: header field. Similarly, within the optional second field, any "%" character will be replaced by the domain found in the From: header field.
-
If this table specifies a regular expression file ("refile"), then the keys are wildcard patterns that are matched against the address found in the From: header field. Entries are checked in the order in which they appear in the file.
-
For all other database types, the full user@host is checked first, then simply host, then user@.domain (with all superdomains checked in sequence, so "foo.example.com" would first check "user@foo.example.com", then "user@.example.com", then "user@.com"), then .domain, then user@*, and finally *.
-
In any case, only the first match is applied, unless MultipleSignatures is enabled in which case all matches are applied.
-
File: /etc/opendkim.conf
KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
KeyTable need "refile:"? (wildcards not allowed)
Hosts to ignore when verifying signatures
Identifies a set of "external" hosts that may send mail through the server as one of the signing domains without credentials as such. This has the effect of suppressing the "external host (hostname) tried to send mail as (domain)" log messages. Entries in the data set should be of the same form as those of the PeerList option below. The set is empty by default.
File: /etc/opendkim.conf
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
A set of internal hosts whose mail should be signed
Identifies a set internal hosts whose mail should be signed rather than verified. Entries in this data set follow the same form as those of the PeerList option below. If not specified, the default of "127.0.0.1" is applied. Naturally, providing a value here overrides the default, so if mail from 127.0.0.1 should be signed, the list provided here should include that address explicitly.
File: /etc/opendkim.conf
InternalHosts refile:/etc/opendkim/TrustedHosts
Save and close the file.
Create Signing Table, Key Table and Trusted Hosts File
Check directory structure for OpenDKIM
$ sudo ls -lR /etc/opendkim*
-rw-r--r-- 1 root root 5346 Mar 2 11:15 /etc/opendkim.conf
/etc/opendkim:
total 12
drwx--x--- 2 opendkim opendkim 6 Feb 24 2022 keys
-rw-r----- 1 opendkim opendkim 339 Feb 24 2022 KeyTable
-rw-r----- 1 opendkim opendkim 1221 Feb 24 2022 SigningTable
-rw-r----- 1 opendkim opendkim 378 Feb 24 2022 TrustedHosts
/etc/opendkim/keys:
total 0
If not the same, change the owner from root to opendkim and make sure only opendkim user can read and write to the keys directory.
sudo chown -R opendkim:opendkim /etc/opendkim
sudo chmod go-rw /etc/opendkim/keys
Create the signing table
Add two lines to the file.
The first line tells OpenDKIM that if a sender on your server is using a @your-domain.com address, then it should be signed with the private key identified by default._domainkey.your-domain.com.
The second line tells that your sub-domains will be signed by the private key also.
File: /etc/opendkim/SigningTable
*@your-domain.com default._domainkey.your-domain.com
*@*.your-domain.com default._domainkey.your-domain.com
Save and close the file.
Create the key table
Add the following line, defining the location of the private key.
File: /etc/opendkim/KeyTable
default._domainkey.your-domain.com your-domain.com:default:/etc/opendkim/keys/your-domain.com/default.private
Save and close the file.
Create the trusted hosts file
Tell OpenDKIM if an email is from localhost or the same domain, then only sign the email, and not perform DKIM verification.
File: /etc/opendkim/TrustedHosts
127.0.0.1
localhost
.your-domain.com
Save and close the file.
Do not add an asterisk to the domain name like this: *.your-domain.com. Put only a dot before the domain name.
Generate Private/Public Keypair
DKIM is used to sign outgoing messages and verify incoming messages, so we need to generate a private key for signing and a public key for remote verifier. Only the public key will be published in DNS.
Create a separate folder for the domain.
sudo mkdir /etc/opendkim/keys/your-domain.com
Generate keys using opendkim-genkey tool.
You should rotate in new keys every once and a while for protection against private key leaks. Allow seven days before deleting the old keys for existing E-Mails to be delivered.
sudo opendkim-genkey -b 2048 -d your-domain.com -D /etc/opendkim/keys/your-domain.com -s default -v
opendkim-genkey: generating private key
opendkim-genkey: private key written to default.private
opendkim-genkey: extracting public key
opendkim-genkey: DNS TXT record written to default.txt
The above command will create 2048 bits keys. -d (domain) specifies the domain. -D (directory) specifies the directory where the keys will be stored and we use default as the selector (-s), also known as the name. Once the command is executed, the private key will be written to default.private file and the public key will be written to default.txt file.
Ensure opendkim is the owner of the private key.
sudo chown opendkim:opendkim /etc/opendkim/keys/your-domain.com/default.private
Also change the permission, so only the opendkim user has read and write access to the file.
sudo chmod 600 /etc/opendkim/keys/your-domain.com/default.private
Publish Your Public Key in DNS Records
Display the public key
sudo cat /etc/opendkim/keys/your-domain.com/default.txt
default._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAutisB7xnL1B1j88Er2VsEd6WuwifqSThKEcrnlkhnsVhs/UkCd2lHL+dZwivjbfH+4RXIP0LK9shGokPwaA2MHNH3GgAuWZ/Wb6ZrZwqDlmHy+H6Q0/cLsB2Py2HFthq1JUhHW31ZOIqa4qOn2suBntQdizGExHsuMMb1nJpu0lgFJLU848qPQO76QMTcC/TyssiCjLXXSQEsS"
"Kx0UmeODJ43NKAAS0OqkGBD2UE7/SW54bVpESK32lTIfzk91OdW+zDMzX6myToJtEE9WgOkgD2evSTp02dhKBBRkQvGJ0SF7el34e/smeS+XvodjjOvP2f3qW5cLvrCRByIkFzRwIDAQAB" ) ; ----- DKIM key default for your-domain.com
The string after the p parameter is the public key, it spans two lines in the cat output because the limit per line is 256 characters. It really should be one big long string with no quotes.
In your DNS manager,
- create a TXT record,
- enter default._domainkey in the name field.
- Copy everything between the parentheses and paste it into the value field of the DNS record. Delete all double quotes and white spaces in the value field. Join all the lines into one line.
For Example; look at a recent google e-mail:
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20210112; t=1677769129;
h=to:list-unsubscribe:user-agent:mime-version:subject:message-id:from
:date:dkim-signature:dkim-signature:delivered-to:x-gm-message-state
:from:to:cc:subject:date:message-id:reply-to;
bh=V22zSr/CKU90o7uszazuWVoXgsouLolWaiMhbqvqG8Y=;
b=FUH9YP2CWhupcc6eU3hVYigxSWJ2fVJHF1F3DrkJoMb1K3hf9O7vrTWDxqNIOvGmPS
6sCsgvynVtQ+cccVgzc6vZLBYDg3XBdQF6u2hxiMIAAkyPGVUUrYpj/OreMj1WkGDkG0
9yVxpp0UuIK8uyrfswX9zBWT/QORjQ4Lfh3KCbzaLX8DbfWoc3P907Ebc8cfvVGDu2wX
oNBeYjEXb4sywHcVmuUNdg//O78sAY5CnSVZ3Gc/41/pFtNHdCCjQAWSQ/W/Czfsy2TY
Ovuebwb71h3VlUpqDIqkaIMZ5rF9pWxqeQgHkIs8Ktgd8CnAhqnk77ZXWk0SR9Q8hkuQ
+BQw==
The s and d tags are used to look up the DKIM record. s is the selector while d is the domain.
s=20210112 d=1e100.net
Together they form the DNS lookup string:
20210112._domainkey.1e100.net
$ dig +short txt 20210112._domainkey.1e100.net
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8Sabq+yC2d91PkWTEkjdH2AsaH31YzVJ8PKlQy2GZ9u8vtqfQM88nACYwWAbCQvLwUfCz7hbF/PyM3K/SPlDSk0HqKq89AQjv60br0pK90vWFmzt04ioNcf4QoiJjnnTWD6h5gOM" "ATz4WfdwCrQ9MRF0SjDHteEVeHCK4WKsWKdPshaSLiVfZxiGLv4SZkWye7Zh5iM66MUvYAr3x151AyCQroTNfJY9RN9RK2ZqLdcoulg7S/XMbnzY7EW0P8nPj2jqvMp0bcr13tOzBRnysYiQIu3cjrtyLNfAZobK6tlmy737vkVH27D0rsUrcABrFqvVox61h61JssaRYcwRpwIDAQAB"
Your key lookup should look like:
$ dig +short txt default._domainkey.your-domain.com
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAutisB7xnL1B1j88Er2VsEd6WuwifqSThKEcrnlkhnsVhs/UkCd2lHL+dZwivjbfH+4RXIP0LK9shGokPwaA2MHNH3GgAuWZ/Wb6ZrZwqDlmHy+H6Q0/cLsB2Py2HFthq1JUhHW31ZOIqa4qOn2suBntQdizGExHsuMMb1nJpu0lgFJLU848qPQO76QMTcC/TyssiCjLXXSQEsS" "Kx0UmeODJ43NKAAS0OqkGBD2UE7/SW54bVpESK32lTIfzk91OdW+zDMzX6myToJtEE9WgOkgD2evSTp02dhKBBRkQvGJ0SF7el34e/smeS+XvodjjOvP2f3qW5cLvrCRByIkFzRwIDAQAB"
Reference: https://www.cloudflare.com/learning/dns/dns-records/dns-dkim-record/
Test DKIM Key
Test your key.
sudo opendkim-testkey -d your-domain.com -s default -vvv
You should see Key OK in the output.
opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: checking key 'default._domainkey.your-domain.com'
opendkim-testkey: key secure
opendkim-testkey: key OK
Your DKIM record will take some time to propagate to the Internet.
To check, go to https://www.dmarcanalyzer.com/dkim/dkim-check/, use default as the selector your domain name to check DKIM record propagation.
Connect Postfix to OpenDKIM
Postfix can talk to OpenDKIM via a Unix socket file. It is a good idea to put it where all the other postfix socket files are.
Create the directory OpenDKIM for a socket file and limit is to the opendkim user and postfix group.
$sudo mkdir /var/spool/postfix/opendkim
$sudo chown opendkim:postfix /var/spool/postfix/opendkim
Set Socket to local
File: /etc/opendkim.conf
Socket local:/var/spool/postfix/opendkim/opendkim.sock
Change the default file as well (if it exists):
Add openDKIM to Postfix main.cf
milter is a modifier filter
File: /etc/postfix/main.cf
# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters
Restart opendkim and postfix service
$ sudo systemctl restart opendkim postfix
SPF and DKIM Check
Send a test email to another domain's account, and see if SPF and DKIM checks are passed in the message source.
Example:
Authentication-Results: dkim-verifier.icloud.com;
dkim=pass (2048-bit key) header.d=your-domain.com header.i=@your-domain.com header.b=yn+tGP2N
Authentication-Results: spf.icloud.com; spf=pass (spf.icloud.com: domain of you@your-domain.com designates 1.2.3.4 as permitted sender) smtp.mailfrom=you@your-domain.com
Your email server will also perform SPF and DKIM checks on other domains.
Example:
Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=1234:f8b0:5678:90::372; helo=mail-yw1-xc2d.google.com; envelope-from=someone@gmail.com; receiver=<UNKNOWN>
Authentication-Results: you.your-domain.com;
dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="IsoKGudn";
dkim-atps=neutral
Postfix Can’t Connect to OpenDKIM
Check the logs
$ vi /var/log/mail*
$ sudo journalctl -eu opendkim
If you see this:
connect to Milter service local:opendkim/opendkim.sock: No such file or directory
check the opendkim systemd service.
$ sudo systemctl status opendkim
If opendkim is running, it means Postfix can’t connect to OpenDKIM via the Unix domain socket (local:opendkim/opendkim.sock).
Check the socket file:
$ ls -l /var/spool/postfix/opendkim/opendkim.sock
srwxrwxr-x 1 opendkim opendkim 0 Mar 2 15:09 /var/spool/postfix/opendkim/opendkim.sock
And postfix user:
$ id postfix
uid=89(postfix) gid=89(postfix) groups=89(postfix),12(mail),988(opendkim)
Be sure the postfix user has group opendkim.
If all else fails, you can configure OpenDKIM to use a TCP/IP socket instead of Unix local socket.
File: /etc/opendkim.conf
Socket inet:8892@localhost
File: /etc/postfix/main.cf
smtpd_milters = inet:127.0.0.1:8892
Restart OpenDKIM and Postfix.
sudo systemctl restart opendkim postfix
Now Postfix will connect to OpenDKIM via the TCP/IP socket.
Configuration Error in Email Client
DKIM signing could fail if you do not use STARTTLS or SSL/TLS.
Type | Port | Encryption | Password |
---|---|---|---|
SMTP | 587 | STARTTLS | Normal |
IMAP | 143 | STARTTLS | Normal |
SMTP | 465 | SSL/TLS | Normal |
IMAP | 993 | SSL/TLS | Normal |
Wrong Settings
Port 25 as the SMTP port in mail clients to submit outgoing emails. No encryption method was selected.
Testing Email Score and Placement
Visit Mail-Tester https://www.mail-tester.com and send an E-Mail to the unique email address displayed on the home page. They will analyze it and return a sender score.
GlockApps https://glockapps.com/ will show you where your emails are being delivered at Gmail, Outlook, & all major ISPs.
What is DMARC?
DMARC stands for Domain-based message authentication, reporting and conformance. DMARC is a protcol for protecting your Internet Domain from abuse.
It extends SPF and DKIM using another DNS entry.
Originators of Internet Mail need to be able to associate reliable and authenticated domain identifiers with messages, communicate policies about messages that use those identifiers, and report about mail using those identifiers. These abilities have several benefits: Receivers can provide feedback to Domain Owners about the use of their domains; this feedback can provide valuable insight about the management of internal operations and the presence of external domain name abuse.
Reference: https://datatracker.ietf.org/doc/html/rfc7489
Create DMARC Record
DMARC policies are published as a TXT record in DNS.
-
Before creating a DMARC record, you must first create SPF and DKIM records.
-
Send a test email from your domain, and check the raw email headers at the recipient’s mailbox. Ensure the domain is the same in:
- Return-path: you@domain
- From: you@domain
- d=domain in the DKIM signature
If the 3 domains are identical, then they are aligned.
If Return-Path: or DKIM d= uses a subdomain instead of the main domain name, then this is called relaxed alignment. If no subdomain is used and the main domain names are the same, it’s called strict alignment.
DMARC Record TXT
Domain Owner DMARC preferences are stored as DNS TXT records in subdomains named "_dmarc". For example, the Domain Owner of "example.com" would post DMARC preferences in a TXT record at "_dmarc.example.com".
In your Domain Registration DNS manager add a new TXT record.
Name field:
_dmarc
Value field:
v=DMARC1; p=none; pct=100; rua=mailto:dmarc-reports@your-domain.com
Definition:
- v=DMARC1: Version (plain-text; REQUIRED). Identifies the record retrieved as a DMARC record. It MUST have the value of "DMARC1".
- p=none: Requested Mail Receiver policy (plain-text; REQUIRED for policy records).
- pct=100: (plain-text integer between 0 and 100, inclusive; OPTIONAL; default is 100). Percentage of messages from the Domain Owner's mail stream to which the DMARC policy is to be applied.
- rua: Addresses to which aggregate feedback is to be sent (comma- separated plain-text list of DMARC URIs; OPTIONAL).
There are 3 policies you can choose from:
- none: The Domain Owner requests no specific action be taken regarding delivery of messages.
- quarantine: The Domain Owner wishes to have email that fails the DMARC mechanism check be treated by Mail Receivers as suspicious.
- reject: The Domain Owner wishes for Mail Receivers to reject email that fails the DMARC mechanism check. Rejection SHOULD occur during the SMTP transaction.
Another option to consider is:
-
fo: Failure reporting options (plain-text; OPTIONAL; default is "0") Provides requested options for generation of failure reports. Report generators MAY choose to adhere to the requested options. This tag's content MUST be ignored if a "ruf" tag (below) is not also specified. The value of this tag is a colon-separated list of characters that indicate failure reporting options as follows:
-
0: Generate a DMARC failure report if all underlying authentication mechanisms fail to produce an aligned "pass" result.
-
1: Generate a DMARC failure report if any underlying authentication mechanism produced something other than an aligned "pass" result.
-
d: Generate a DKIM failure report if the message had a signature that failed evaluation, regardless of its alignment. DKIM- specific reporting is described in [AFRF-DKIM].
-
s: Generate an SPF failure report if the message failed SPF evaluation, regardless of its alignment. SPF-specific reporting is described in [AFRF-SPF].
-
-
ruf: Addresses to which message-specific failure information is to be reported (comma-separated plain-text list of DMARC URIs; OPTIONAL). If present, the Domain Owner is requesting Mail Receivers to send detailed failure reports about messages that fail the DMARC evaluation in specific ways (see the "fo" tag above).
Try fo=1 at first for detailed DMARC failure reports. When you change to a more restrictive policy, use fo=0.
v=DMARC1; p=none; pct=100; fo=1; ruf=mailto:dmarc-reports@your-domain.com
If you have a domain name that will not send emails, use p=reject
policy.
v=DMARC1; p=reject; pct=100;
DMARC Record Check
You can check your DMARC record from Linux terminal with the following command:
$ dig txt +short _dmarc.example.com
"v=DMARC1; p=none; pct=100; rua=mailto:postmaster@your-domain.com"
You can also install opendmarc-check that to check a DMARC record.
Install opendmarc package
sudo apt install opendmarc
It checks DNS and translates the DMARC record to a human readable form.
$ opendmarc-check your-domain.com
DMARC record for your-domain.com:
Sample percentage: 100
DKIM alignment: relaxed
SPF alignment: relaxed
Domain policy: none
Subdomain policy: unspecified
Aggregate report URIs:
mailto:postmaster@your-domain.com
Failure report URIs:
(none)
DMARC Test E-Mail
Send an email from your domain to another domain's account. If DMARC is configured correctly then you will see dmarc=pass in the Authentication-Results: header.
Authentication-Results: dmarc.icloud.com; dmarc=pass header.from=your-domain.com
X-DMARC-Info: pass=pass; dmarc-policy=none; s=r1; d=r1; pdomain=your-domain.com
X-DMARC-Policy: v=DMARC1; p=none; pct=100; rua=mailto:postmaster@your-domain.com
Authentication-Results: dkim-verifier.icloud.com;
dkim=pass (2048-bit key) header.d=your-domain.com header.i=@your-domain.com header.b=wVFZ+19t
Authentication-Results: spf.icloud.com; spf=pass (spf.icloud.com: domain of you@your-domain.com designates 1.2.3.4 as permitted sender) smtp.mailfrom=you@your-domain.com
Received-SPF: pass (spf.icloud.com: domain of you@your-domain.com designates 1.2.3.4 as permitted sender) receiver=spf.icloud.com; client-ip=1.2.3.4; helo=mail.your-domain.org; envelope-from=you@your-domain.com
Interpret a DMARC Report
There are two kinds of DMARC reports.
- Daily XML-based [1] aggregate report generated by Gmail, Yahoo, Hotmail, etc.
- Real-time forensic reports (copies of individual pieces of email that fail the DMARC check)
Normally you only want to receive the aggregate (rua) report. The data that DMARC produces is invaluable for understanding what is going on for any given email domain. However, raw DMARC report data is super hard to read and understand.
Postmark offers a free service to process these reports. The nice part about Postmark is that you can tell receiving email servers to send XML reports directly to Postmark for processing. So instead of entering your email address in the DMARC record, you enter an email address of postmarkapp.com that is unique to you.
v=DMARC1; p=none; pct=100; fo=1; rua=mailto:unique-to-you@dmarc.postmarkapp.com;
You can also specify multiple email addresses, separated by commas.
v=DMARC1; p=none; pct=100; fo=1; rua=mailto:unique-to-you@dmarc.postmarkapp.com,mailto:dmarc-report@your-domain.com;
After your DMARC record has been verified by Postmark, you will receive a DMARC report weekly every Monday in your email inbox. You don’t need to register an account at Postmark.
Many other firms exist to create DMARC reports. If you are into a lot of E-Mail marketing, you should check some more out.
Reference:
- https://www.linuxbabe.com/mail-server/create-dmarc-record
- https://postmarkapp.com
- https://datatracker.ietf.org/doc/html/rfc7489#section-7.2
E-Mail Relay - Linux in the House - https://linux-in-the-house.org