Configuring postfix to prevent your emails from being flagged as SPAM
This post describes how to properly defines postfix server properties to prevent your emails from being falsely flagged as spams or even rejected (especially by Google). It lists the different policies and tools that have to be checked to ensure a maximum probability to pass all filters. This post is dedicated to my old buddy Stéphanie, whose email (gmail) address often rejected (maybe not wrongly) my emails.
As a use case example, we will consider that the user (me) wants to send email from the addresses tuxette@mydomain.org
and samantha@myotherdomain.wf
via the mail server with name mail.mydomain.org
. I own the two domain names mydomain.org
and myotherdomain.wf
. mail.mydomain.org
has for IP XX.YYY.ZZZ.WW
which reverses to the server name chix.mydomain.org
. In addition, my server only sends email via IPV4 (option inet_protocols = ipv4
in the file /etc/postfix/main.cf
to avoid painful headaches in configuring properly DNS and PTR for IPV6).
MX, PTR and reverse
All these records must be set properly (in my case, they are managed through the OVH user interface because my domain names are rented by OVH:
-
MX records for
myotherdomain.wf
andmydomain.org
points tomail.mydomain.org
which means that all emails sent to@myotherdomain.wf
and@mydomain.org
are directed to the mail servermail.mydomain.org
. This rule writes</p>IN MX 1 mail.mydomain.org.
-
DNS and PTR records must also be properly set: the DNS record associates the IP
XX.YYY.ZZZ.WW
to the mail servermail.mydomain.org
. This rule is restricted to the domain namemydomain.org
and writes</p>mail IN A XX.YYY.ZZZ.WW
Also, a PTR has to be set for the IP address
XX.YYY.ZZZ.WW
. This PTR record associates a domain name to the IP, in my casechix.mydomain.org
(hence, PRT does not necessarily points to the FQDN of the mail server butchix.mydomain.org
must have a PTR record which matches the IPXX.YYY.ZZZ.WW
). </li> </ul>All these records (as well as IP blacklisting) can be checked at this link. In particular:
-
MX Lookup should return
mydomain.org
when queried onmydomain.org
ormyotherdomain.wf
; -
Blacklisting Check should be OK for
XX.YYY.ZZZ.WW
; -
Blacklisting Check should be OK for
XX.YYY.ZZZ.WW
; -
DNS Lookup for
mail.mydomain.org
andchix.mydomain.org
should returnXX.YYY.ZZZ.WW
; -
Reverse Lookup (PTR) for
XX.YYY.ZZZ.WW
should returnchix.mydomain.org
; -
finally, both
mydomain.org
ormyotherdomain.wf
can be checked for “Test Email Server” to find any anomaly in mail server configuration.
SPF
A SPF (Sender Policy Framework) record tells which servers/IP … are allowed to send emails for a given domain name. If no SPF is defined and an email is sent to a gmail address, you should see the following record in the headers:
Received-SPF: neutral (google.com: XX.YYY.ZZZ.WW is neither permitted nor denied by best guess record for domain of samantha@myotherdomain.wf) client-ip=XX.YYY.ZZZ.WW;
This framework can be used to tell the receiver’s email server that the email has actually been sent by the expected mail server. In my case, I created a SPF record for both
mydomain.org
andmyotherdomain.wf
with the same policy which tells that the IP ofmydomain.org
andmyotherdomain.wf
are allowed to send emails as well as the MX ofmydomain.org
andmyotherdomain.wf
. Finally, I also explicitely authorized the IPXX.YYY.ZZZ.WW
to send emails. This record writes600 IN TXT "v=spf1 a mx ip4:XX.YYY.ZZZ.WW ~all"
in which the
~all
tells that this is a soft policy (maybe emails can be sent by other servers although it is not expected). OVH interface allows to configure in a very intuitive manner SPF.Sending an email to a gmail account, the received header should now look like:
Received-SPF: pass (google.com: domain of samantha@myotherdomain.wf designates XX.YYY.ZZZ.WW as permitted sender) client-ip=XX.YYY.ZZZ.WW;
More details about SPF at this link (in French). SPF records can be checked at this link.
DKIM
DKIM enables a domain name to be associated with an email message and thus to claim for responsibility for an email. DKIM is powered by asymmetric cryptography: a key is included in every email header which should match your DKIM record (TXT field corresponding to your domain name) in order to pass the DKIM filter. I installed it using the tutorial available at this link. First, opendkim tools have to be installed:
sudo apt-get install opendkim opendkim-tools
which configuration file
/etc/opendkim.conf
is edited to addAutoRestart Yes AutoRestartRate 10/1h UMask 002 Syslog yes SyslogSuccess Yes LogWhy Yes Canonicalization relaxed/simple ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts KeyTable refile:/etc/opendkim/KeyTable SigningTable refile:/etc/opendkim/SigningTable Mode sv PidFile /var/run/opendkim/opendkim.pid SignatureAlgorithm rsa-sha256 UserID opendkim:opendkim Socket inet:12301@localhost
Then,
/etc/default/opendkim
is editing and the following line is added:SOCKET="inet:12301@localhost"
To connect opendkim to postfix, edit the file
/etc/postfix/main.cf
and add the following two lines:milter_protocol = 2 milter_default_action = accept
Create a file
/etc/opendkim/TrustedHosts
with127.0.0.1 localhost 192.168.0.1/24 *.mydomain.org *.myotherdomain.wf
and a file
/etc/opendkim/KeyTable
withmail._domainkey.mydomain.org mydomain.org:mail:/etc/opendkim/keys/mydomain.org/mail.private mail._domainkey.myotherdomain.wf myotherdomain.wf:mail:/etc/opendkim/keys/myotherdomain.wf/mail.private
and also a file
/etc/opendkim/SigningTable
with*@mydomain.org mail._domainkey.mydomain.org *@myotherdomain.wf mail._domainkey.myotherdomain.wf
Finally, to generate the keys, create the following directories in
/etc/opendkim
:keys/mydomain.org
keys/myotherdomain.wf
and runsudo opendkim-genkey -s mail -d mydomain.org sudo chown opendkim:opendkim mail.private
inside
/etc/opendkim/keys/mydomain.org
andsudo opendkim-genkey -s mail -d myotherdomain.wf sudo chown opendkim:opendkim mail.private
inside
/etc/opendkim/keys/myotherdomain.wf
.A DKIM record is then added to each of the two domain name:
mail._domainkey IN TXT "v=DKIM1; k=rsa; p=WWWWWWWWWWW"
in which
WWWWWWWWWWW
has to be replaced by the (long) text key available in the file/etc/opendkim/keys/mydomain.org/mail.txt
(and similarly for the record DKIM record forclementine.wf
). Then, an email received by gmail includes the following text in the headers:Authentication-Results: mx.google.com; spf=pass (google.com: domain of samantha@myotherdomain.wf designates XX.YYY.ZZZ.WW as permitted sender) smtp.mailfrom=samantha@myotherdomain.wf; dkim=pass header.i=@samantha@myotherdomain.wf;
which tells that both DKIM and SPF filters have been successfully passed. Again, DKIM records can be checked at this link.
DMARC
Finally, SPF and DKIM can be monitored using a DMARC record. DMARC, which stands for “Domain-based Message Authentication, Reporting & Conformance”, standardizes how email receivers perform email authentication using the well-known SPF and DKIM mechanisms. This means that senders will experience consistent authentication results for their messages.
A DMARC rule can be recorded in a TXT field of your domain name (so, in the present use case for
mydomain.org
andmyotherdomain.wf
. A basic overview of how DMARC rules are created and work is available at this link. In my case, I created a DMARC record which takes no policy for domain mismatch, subject 10% of the messages to filter (this rule seems to be overridden by google anyway) and relaxed policy for alignment of SPF and DKIM records. Daily reports will be received attuxette@mydomain.org
:_dmarc IN TXT "v=DMARC1;p=none;sp=reject;pct=10;adkim=r;aspf=r;fo=1; ri=86400;rua=mailto:tuxette@mydomain.org"
The reports can be checked and better understood using the tool available at this link. A proper DMARC record should lead to headers similar to:
Authentication-Results: mx.google.com; spf=pass (google.com: domain of samantha@myotherdomain.wf designates XX.YYY.ZZZ.WW as permitted sender) smtp.mailfrom=samantha@myotherdomain.wf; dkim=pass header.i=@samantha@myotherdomain.wf; dmarc=pass (p=NONE dis=NONE) header.from=samantha@myotherdomain.wf
DMARC records can be checked at this link.
</div> -
MX Lookup should return