Postfix to GMail Catchall (updated… again)
by Emile `iMil' Heitor - 2021-12-21
The other day, my wife asked me if I could just redirect all mails going to her own domain to her GMail account. “Easy task”, foolish past-me thought, not knowing the standards you have to meet to actually forward a mail from somwhere to GMail…
I naively searched for a simple bouncing method and postfix
’s virtual tables seemed
perfectly fit for the task (from man virtual
):
The main applications of virtual aliasing are:
o To redirect mail for one address to one or more addresses.
o To implement virtual alias domains where all addresses are
aliased to addresses in other domains.
So here we go and:
$ pwd
/etc/postfix
$ grep ^virtual main.cf
virtual_alias_maps = hash:/etc/postfix/virtual
$ cat virtual
@herdomain.com heruser@gmail.com
$ sudo postmap virtual
Easy! let’s send an email from another domain just to validate everything works correctly:
Diagnostic-Code: smtp; 550-5.7.26 This message does not have authentication
information or fails to 550-5.7.26 pass authentication checks. To best
protect our users from spam, the 550-5.7.26 message has been blocked.
Please visit 550-5.7.26
https://support.google.com/mail/answer/81126#authentication for more 550
5.7.26 information. b11si14737855wrg.755 - gsmtp
wtf?
Oh, I see… the DKIM key doesn’t match because the mail is originally from
otherdomain.com which has a DKIM entry, but is delivered by my own mail server, which also
have a DKIM entry, and obviously they don’t match. This post which explains how to
rewrite DKIM in the header did not leave me a good / clean feeling, so let’s simply try and
remove the DKIM header!
This is easily done by the header_checks
postfix
feature, basically this:
$ grep ^header_checks main.cf
header_checks = regexp:/etc/postfix/header_checks
$ cat header_checks
/^DKIM-Signature:.*/ IGNORE
will get rid of the previous DKIM signature, let’s try it… and same error. But yes, no
DKIM-Signature:
header was found on the transmitted email.
The headers might help to understand what’s going on:
Return-Path: <heruser@otherdomain.com>
Received: by senate.imil.net (Postfix, from userid 1000)
id 60AB84EA91; Tue, 21 Dec 2021 16:58:21 +0100 (CET)
Received: from mail-4325.protonmail.ch (mail-4325.protonmail.ch [185.70.43.25])
by senate.imil.net (Postfix) with ESMTPS id 168844E610
for <test@herdomain.com>; Tue, 21 Dec 2021 16:58:21 +0100 (CET)
Date: Tue, 21 Dec 2021 15:58:18 +0000
To: "test@herdomain.com" <test@herdomain.com>
From: Test User <heruser@otherdomain.com>
Reply-To: Test User <heruser@otherdomain.com>
Maybe bouncing directly from virtual
is not a so good idea considering Google’s strict
policy on mail transfer.
OK then, let’s try a good old fashioned .forward
based forwarding, that’s a good trick! I’ll
simply change the virtual
to a local user who’s going to have a .forward
file in his home
directory, containing the final destination address:
$ cat virtual
@herdomain.com heruser
$ cat /home/heruser/.forward
heruser@gmail.com
Still no luck. Same message, yet more steps in the headers:
Return-Path: <heruser@otherdomain.com>
Received: by senate.imil.net (Postfix)
id 9BEB84E5C9; Tue, 21 Dec 2021 17:20:36 +0100 (CET)
Delivered-To: heruser@home.imil.net
Received: by senate.imil.net (Postfix, from userid 1003)
id 9596E4EA91; Tue, 21 Dec 2021 17:20:36 +0100 (CET)
Received: from mail-4318.protonmail.ch (mail-4318.protonmail.ch [185.70.43.18])
by senate.imil.net (Postfix) with ESMTPS id 7BDCC4E5C9
for <test@herdomain.com>; Tue, 21 Dec 2021 17:20:36 +0100 (CET)
Date: Tue, 21 Dec 2021 16:20:35 +0000
To: "test@herdomain.com" <test@herdomain.com>
From: Test User <heruser@otherdomain.com>
Reply-To: Test User <heruser@otherdomain.com>
At this point I don’t understand why SPF didn’t match, considering that this next
solution does work: procmail
to the rescue!
So instead of a .forward
file, I used a very simple .procmailrc
:
MAILDIR=$HOME/Maildir/
DEFAULT=$HOME/Maildir/
LOGFILE=$HOME/log/procmail.log
:0c
! heruser@gmail.com
What this does is forwarding mails to heruser@gmail.com
, but while at it, also copies the
email locally for if she wants to use a independent, free MUA one day… so let’s remove
the .forward
file and try this setup.
Delivered-To: heruser@gmail.com
Received: by 2002:a05:6a10:cd05:0:0:0:0 with SMTP id gw5csp3514080pxb;
Tue, 21 Dec 2021 08:49:01 -0800 (PST)
ARC-Authentication-Results: i=1; mx.google.com;
spf=pass (google.com: domain of heruser@home.imil.net designates 2001:bc8:234c:1::1 as permitted sender) smtp.mailfrom=heruser@home.imil.net;
dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com
Return-Path: <heruser@home.imil.net>
Received: from senate.imil.net (senate.imil.net. [2001:bc8:234c:1::1])
by mx.google.com with ESMTP id s9si9509084wrw.307.2021.12.21.08.49.00
for <heruser@gmail.com>;
Tue, 21 Dec 2021 08:49:01 -0800 (PST)
Received-SPF: pass (google.com: domain of heruser@home.imil.net designates 2001:bc8:234c:1::1 as permitted sender) client-ip=2001:bc8:234c:1::1;
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of heruser@home.imil.net designates 2001:bc8:234c:1::1 as permitted sender) smtp.mailfrom=heruser@home.imil.net;
dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com
Received: by senate.imil.net (Postfix, from userid 1013) id ABFAA4EA90; Tue, 21 Dec 2021 17:49:00 +0100 (CET)
X-Original-To: heruser@home.imil.net
Delivered-To: heruser@home.imil.net
Received: by senate.imil.net (Postfix, from userid 1003) id 9F4814EA91; Tue, 21 Dec 2021 17:49:00 +0100 (CET)
Received: from mail-40140.protonmail.ch (mail-40140.protonmail.ch [185.70.40.140]) by senate.imil.net (Postfix) with ESMTPS id 85BD24E5C9 for <test@herdomain.com>; Tue, 21 Dec 2021 17:49:00 +0100 (CET)
Date: Tue, 21 Dec 2021 16:48:57 +0000
To: "test@herdomain.com" <test@herdomain.com>
From: Test User <heruser@otherdomain.com>
Reply-To: Test User <heruser@otherdomain.com>
I removed the unnecessary headers, but here we are, the mail went through, and for a reason I still not get, SPF passed this time. Kinda victory.
What’s the magic behind the use of procmail
? I’m not sure. It’s a process spawned by
postfix
on behalf of the user, a whole new mail sending process, the Return-Path:
is set
to the current user and origin domain but should this affect the delivery mechanism?
I would have thought the .forward
mechanism would have done a good job but I was wrong.
Have you got a better idea, or a clear explanation? Leave it in the comments!
Update
In my previous solution, only the SPF test passed because the From:
field was still
referencing otherdomain.com
, so as the purpose of this catchall is really to receive
mails from third parties for confirmations, there’s no need for replies, so I simply rewrote the
From:
field with a domain handled by my server, heruser@herdomain.com
:
$ cat .procmailrc
MAILDIR=$HOME/Maildir/
DEFAULT=$HOME/Maildir/
LOGFILE=$HOME/log/procmail.log
:0fhw
| formail -i "From: heruser@herdomain.com"
:0c
! heruser@gmail.com
And there we go, SPF and DKIM are now green:
SPF: PASS with IP 2001:bc8:234c:1:0:0:0:1
DKIM: 'PASS' with domain herdomain.com
Update 2
Just in case she actually needs to reply to a forwarded mail, I slightly modified the
procmailrc
file to force add a Reply-To:
header pointing to the original From:
:
SENDER=`formail -xFrom:`
:0fhw
| formail -i "From: heruser@herdomain.com" -i "Reply-To: $SENDER"
Update 3
In order to catch MAILER-DAEMON
messages before it creates a loop and fills your hard drive with carbon copies cough cough, add this rule as the first one:
:0
* ^From.*MAILER-DAEMON.*
.mailer-daemon/