2015-08-03 Switching to Postfix

What I want to do is read all my email using Google. I like Gmail, I like Inbox, I like their spam filtering. Cool. I also want to receive email for my various domains. Thus, all these domains have an MX record pointing to my Raspberry Pi. It runs Postfix and Dovecot, and my accounts have .forward files pointing to kensanata@gmail.com. This ought to be cool, too. If I remove that .forward file, I can read my email on the Raspberry Pi using IMAP.

Sadly, I’m getting a lot of these:

<kensanata@gmail.com>: host gmail-smtp-in.l.google.com[] said:
    550-5.7.1 [      12] Our system has detected that this message
    is 550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to
    Gmail, 550-5.7.1 this message has been blocked. Please visit 550 5.7.1
    https://support.google.com/mail/answer/188131 for more information.
    eu1si12802336wic.49 - gsmtp (in reply to end of DATA command)

So now I’m trying to setup up things to fix this. I’ve tried doing these things using Exim but I find the official documentation to be hard to understand for newbies like me. So now I’m trying to switch to Postfix.


In order to reduce spam, I have a TXT record in my zone file with some SPF1 information. There is some info by Google on what they suggest (include:_spf.google.com ~all) and there is the SPF Record Syntax documentation which shows you how to indicate who else can send mail for your domain (mx means “the MX records” and a means “the current domain”).

@ 10800 IN TXT "v=spf1 ip6:2001:4830:134:3::10 mx a include:_spf.google.com ~all"

The IP6 number is for egg.gnu.org. When I send mail from my Raspberry Pi to my gnu.org address without this information, it arrives on Gmail with the following headers:

Received: from eggs.gnu.org (eggs.gnu.org. [2001:4830:134:3::10])
        by mx.google.com with ESMTPS id g4si5396462igt.36.2015.
        for <kensanata@gmail.com>
        (version=TLSv1 cipher=RC4-SHA bits=128/128);
        Mon, 03 Aug 2015 02:14:24 -0700 (PDT)
Received-SPF: softfail (google.com: domain of transitioning alex@alexschroeder.ch does not designate 2001:4830:134:3::10 as permitted sender) client-ip=2001:4830:134:3::10;
Authentication-Results: mx.google.com;
       spf=softfail (google.com: domain of transitioning alex@alexschroeder.ch does not designate 2001:4830:134:3::10 as permitted sender) smtp.mail=alex@alexschroeder.ch
Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)
	(envelope-from <alex@alexschroeder.ch>)
	id 1ZMBp9-0002rf-2D
	for kensanata@gmail.com; Mon, 03 Aug 2015 05:14:23 -0400
X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org
X-Spam-Status: No, score=-0.0 required=5.0 tests=BAYES_40 autolearn=disabled
Received: from fencepost.gnu.org ([2001:4830:134:3::e]:37492)
	by eggs.gnu.org with esmtp (Exim 4.71)
	(envelope-from <alex@alexschroeder.ch>)
	id 1ZMBp8-0002rb-VG
	for kensanata@gmail.com; Mon, 03 Aug 2015 05:14:22 -0400
Received: from eggs.gnu.org ([2001:4830:134:3::10]:45863)
	by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256)
	(Exim 4.82)
	(envelope-from <alex@alexschroeder.ch>)
	id 1ZMBp8-0005RP-Lv
	for alex@gnu.org; Mon, 03 Aug 2015 05:14:22 -0400
Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)
	(envelope-from <alex@alexschroeder.ch>)
	id 1ZMBp5-0002r8-Ar
	for alex@gnu.org; Mon, 03 Aug 2015 05:14:22 -0400
Received: from 77-57-27-11.dclient.hispeed.ch ([]:48751 helo=mail.alexschroeder.ch)
	by eggs.gnu.org with esmtp (Exim 4.71)
	(envelope-from <alex@alexschroeder.ch>)
	id 1ZMBp5-0002qy-3w
	for alex@gnu.org; Mon, 03 Aug 2015 05:14:19 -0400
Received: by mail.alexschroeder.ch (Postfix, from userid 1001)
	id BA59610FC; Mon,  3 Aug 2015 10:35:13 +0200 (CEST)

So, the mail went from mail.alexschroeder.ch to eggs.gnu.org, was scanned for spam and forwarded to fencepost.gnu.org which is where my account is, and my .forward file there tells the Gnu mail server to send it on to gmail.com. There, they find that eggs.gnu.org is not allowed to send mail in the name of alexschroeder.ch. Adding the IP6 number 2001:4830:134:3::10 to my SPF record changes that.


sudo apt-get install postfix postgrey

That should install Greylisting.


Transport Layer Security makes sure nobody can eavesdrop on your emails. This used to be a separate step when I was using Exim. When I switched to Postfix, it was the standard.

pi@raspberrypi ~ $ grep -i tls /etc/postfix/main.cf 
# TLS parameters
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache


I’m not sure how this is supposed to work. Looking at the Postfix SASL Howto it would seem that Postfix can use my Dovecot installation. But to be honest, I’m not quite sure I need this.


I’m reading How To Install and Configure DKIM with Postfix on Debian Wheezy.

pi@raspberrypi ~ $ sudo apt-get install opendkim opendkim-tools

I then edited /etc/opendkim.conf and added the following:

# How To Install and Configure DKIM with Postfix on Debian Wheezy
# https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-dkim-with-postfix-on-debian-wheezy

AutoRestart             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

The instructions mentioned something about editing /etc/default/opendkim and adding SOCKET="inet:12301@localhost" but this seems unnecessary. A comment at the top says Command-line options specified here will override the contents of /etc/opendkim.conf. I’m not doing anything for the moment since I see the «Socket» setting in /etc/opendkim.conf.

I added the following lines to /etc/postfix/main.cf:

milter_protocol = 2
milter_default_action = accept
smtpd_milters = inet:localhost:12301
non_smtpd_milters = inet:localhost:12301

I created the necessary directories:

sudo mkdir -p /etc/opendkim/keys

And I moved the key pair I had created there. These I had created using the instructions elsewhere instead of using opendkim-genkey.

openssl genrsa -out dkim.private 1024
openssl rsa -in dkim.private -out dkim.public -pubout -outform PEM

As far as I can tell, the key cannot be more than 1024 because the TXT record in the zone (see below) is limited in size.

Change ownership and permissions of the private key:

sudo chown opendkim:opendkim dkim.private
sudo chmod 440 keys/dkim.private 

Previously, my permission for the private key had been -rw-r--r-- and I was getting key data is not secure errors in my /var/log/mail.err. as they say, if anyone on the system can change the key, or generate signatures, or steal the key, that’s not good. When I tried to use -r-------- I was getting a different error: can't load key from /etc/opendkim/keys/dkim.private: Permission denied. So now I’m using -r--r-----.

I also added the following line to my zone file:

dkim._domainkey 10800 IN TXT "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGMDmbDQEk62j5n8pcHsWNAkrnvhes2g+c2O/gXEytr40E7nqX21YuIDj1e6S07+A8aM/0TSV5nIiWEhOocJtG91wNeM7ypqAgR5zihYoolkXk4FWsdIPbuwZbIEbLBLkgJdD2qbgLLOe/OFMIF3/MQROrfVh+rrxHun2RFJLKDwIDAQAB"

Test it using dig -t TXT dkim._domainkey.alexschroeder.ch. This should tell you whether the record is correct. In addition to that, Check a DKIM Core Key.

Then I created the following files. Note that I’m using the selector dkim instead of mail because of the guide I had followed in an earlier attempt, linked above.




dkim._domainkey.alexschroeder.ch alexschroeder.ch:dkim:/etc/opendkim/keys/dkim.private
dkim._domainkey.communitywiki.org communitywiki.org:dkim:/etc/opendkim/keys/dkim.private
dkim._domainkey.orientalisch.info orientalisch.info:dkim:/etc/opendkim/keys/dkim.private
dkim._domainkey.campaignwiki.org campaignwiki.org:dkim:/etc/opendkim/keys/dkim.private
dkim._domainkey.arabisch-lernen.org arabisch-lernen.org:dkim:/etc/opendkim/keys/dkim.private
dkim._domainkey.oddmuse.org oddmuse.org:dkim:/etc/opendkim/keys/dkim.private
dkim._domainkey.emacswiki.org emacswiki.org:dkim:/etc/opendkim/keys/dkim.private


*@alexschroeder.ch dkim._domainkey.alexschroeder.ch
*@communitywiki.org dkim._domainkey.communitywiki.org
*@orientalisch.info dkim._domainkey.orientalisch.info
*@campaignwiki.org dkim._domainkey.campaignwiki.org
*@arabisch-lernen.org dkim._domainkey.arabisch-lernen.org
*@oddmuse.org dkim._domainkey.oddmuse.org
*@emacswiki.org dkim._domainkey.emacswiki.org

With all of this done, it’s time to restart our services.

sudo service postfix restart
sudo service opendkim restart

Getting Off Blacklists

I had to request the removal of my Raspberry Pi’s IP number from some blacklists.

Accepting Mail

Sending mail to my various domains resulted in “Relay access denied” messages:

554 5.7.1 <admin@campaignwiki.org>: Relay access denied

I realized what the problem was: What domains to receive mail for needs to list all of them!

In /etc/postfix/main.cf I changed this line:

mydestination = alexschroeder.ch, mail.alexschroeder.ch, communitywiki.org, orientalisch.info, campaignwiki.org, arabisch-lernen.org, oddmuse.org, emacswiki.org, localhost.alexschroeder.ch, localhost


This is how most of my mail is handled:

pi@raspberrypi ~ $ cat /etc/aliases
# /etc/aliases
mailer-daemon: postmaster
postmaster: root
nobody: root
hostmaster: root
usenet: root
news: root
webmaster: root
www: root
ftp: root
abuse: root
noc: root
security: root
admin: root
root: alex

Fighting Spam

I’m following Timo’s blog:

apt-get install spamassassin spamc

This pulls a ton of dependencies… And then edit /etc/default/spamassassin, setting ENABLED=1.

Then edit /etc/spamassassin/local.cf and add my contact email. I also experimented with rewrite_header but found that it made scanning my Junk folder harder than necessary. That’s also the reason why I disabled report_safe.

# rewrite_header Subject *****SPAM*****
report_contact kensanata@gmail.com

#   Save spam messages as a message/rfc822 MIME attachment instead of
#   modifying the original message (0: off, 2: use text/plain instead)
report_safe 0

No Bayes auto-learning because I’m planning to forward all my mails to Gmail eventually. At that point, no more learning would occur.

Now edit /etc/postfix/master.cf and add a line to smtp as follows:

smtp      inet  n       -       -       -       -       smtpd
        -o content_filter=spamassassin

Also add the following at the end:

spamassassin unix -     n       n       -       -       pipe
        user=debian-spamd argv=/usr/bin/spamc -f -e
        /usr/sbin/sendmail -oi -f ${sender} ${recipient}

Restart everything.

sudo service spamassassin restart
sudo service postfix restart

Moving Spam to Junk Folder

Sadly, this doesn’t work as intended. It should be easy but I have permission problems. I get errors like these in my mail log: dovecot: lda(alex): Error: setegid(privileged) failed: Operation not permitted. I think I’m only getting this error when my mail is not spam and should therefore end in /var/mail/alex. Perhaps I have to move from LDA to LMTP.

This is what I had in /etc/postfix/main.cf:

# mailbox_command = procmail -a "$EXTENSION"
mailbox_command = /usr/lib/dovecot/deliver

deliver is linked to deliver-lda and somehow deliver-lda is not allowed to do its job?

So I switched to dovecot-lmtp.

I followed the instructions on the Dovecot wiki. Running apt-get install dovecot-lmtp already added the protocol via /usr/share/dovecot/protocols.d/lmtpd.protocol.

In /etc/dovecot/conf.d/10-master.conf I made the required change:

service lmtp {
 unix_listener /var/spool/postfix/private/dovecot-lmtp {
   group = postfix
   mode = 0600
   user = postfix

No changes were required for /etc/dovecot/conf.d/20-lmtp.conf.

I told Postfix about the change in /etc/postfix/main.cf.

# mailbox_command = procmail -a "$EXTENSION"
# mailbox_command = /usr/lib/dovecot/deliver

# Using Dovecot LMTP
# http://wiki2.dovecot.org/HowTo/PostfixDovecotLMTP
mailbox_transport = lmtp:unix:private/dovecot-lmtp

At this point I restarted both services.

sudo service dovecot restart
sudo service postfix restart

But now I was getting a different error when I sent myself a test email:

Aug  9 09:36:40 raspberrypi postfix/lmtp[29502]: 61A5618B6: to=<alex@alexschroeder.ch>, orig_to=<alex>, relay=mail.alexschroeder.ch[private/dovecot-lmtp], delay=0.57, delays=0.19/0.07/0.13/0.18, dsn=5.1.1, status=bounced (host mail.alexschroeder.ch[private/dovecot-lmtp] said: 550 5.1.1 <alex@alexschroeder.ch> User doesn't exist: alex@alexschroeder.ch (in reply to RCPT TO command))

The problem was that I’m using existing system accounts on my server, not virtual accounts. That’s why the user lookup needs to ignore the domain. I made the following change in /etc/dovecot/conf.d/10-auth.conf:

# auth_username_format = %Lu
# fixing username lookup
# http://www.0xf8.org/2012/11/trouble-with-postfix-and-dovecotpam-unknown-user/
auth_username_format = %Ln

The rest of the file remained unchanged. Which is why it still says at the end:

!include auth-system.conf.ext

It seems to work!

My users now all have the following ~/.dovecot.sieve file:

require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
	fileinto "Junk";

I wanted to set up server-side email filtering with Dovecot Sieve but I couldn’t find the /etc/dovecot/sieve/default.sieve file it told me to edit. Oh well, I just have to users, so copying the tiny file was no problem. :)

Postfix Queue Management

The commands I’ve used the most often:

sudo postcat -q 1EF1841F
sudo postsuper -d 1EF1841F

(From here.)


Show Google +1


Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Please say HELLO.