Domain-based SMTP relay routing

Is there a way to configure postfix to use different SMTP relays based on the sender domain?

It should work something like this:

  • domain1.tld uses a Google SMTP relay with IP-based authentication (no login preferred, but can be auth if we manage to make app password work),
  • domain2.tld uses user1 SMTP login provided by MXroute,
  • domain3.tld uses user2 SMTP login provided by MXroute (different credentials to track usage),
  • domain4.tld and all other domains keep use normal postfix delivery

ChatGPT and Claude provided half-baked solutions which didn’t really work. Is this achievable somehow or can you point me to a different solution?

Sender-transport maps with additional services would do the trick. From the docs, ApisCP already provides a map to use.

To allow authless SMTP from additional IP ranges, override mynetworks. This is covered in the “Customizing” section of the docs.

To declare specific SMTP relays, there are two approaches: either create a new service in master.d/ or set the literal next-hop.

# master.d/google-relay.cf, see docs
google-relay  -       -       n       -       -       smtp
        -o relayhost=[smtp.google.com]:587

/etc/postfix/sender_transport

@domain1.tld google-relay:

Run postmap /etc/postfix/sender_transport after

Alternatively:
/etc/postfix/sender_transport

@domain1.tld smtp:[smtp.google.com]:587

Run postmap /etc/postfix/sender_transport after

Then wire up authentication for the relay:
/etc/postfix/smarthost-auth

[smtp.google.com]:587 USERNAME:PASSWORD

Run postmap /etc/postfix/smarthost-auth after

Restart postfix service and those relays will be used if the sending domain matches. Pattern the remaining 2 SMTP relays and sender domains based off the above examples. Using a declared SMTP service deduplicates the SMTP relay and allows customization down the road, like throttling relay rates.

Note, untested but the math looks right…

1 Like

Looks good on paper, but math isn’t mathing yet.

[root@web6 ~]# cat /etc/postfix/master.d/google-relay.cf 
google-relay-out unix  -       -       n       -       -       smtp
        -o relayhost=[smtp-relay.gmail.com]:587
[root@web6 ~]# cat /etc/postfix/sender_transport
@nicolae.co     google-relay-out:
# @anatolinicolae.com     mxroute-1:
@wp-kit.com     mxroute-relay-out:
[root@web6 ~]# postmap -q @nicolae.co hash:/etc/postfix/sender_transport
google-relay-out:
[root@web6 ~]# postmap -q @wp-kit.com hash:/etc/postfix/sender_transport
mxroute-relay-out:

This currently makes sense and seems to be correct. However, outbound email isn’t routed through the Google relay nor MXroute. Seems to be ignored and delivered by postfix directly, or at least that’s what I’m reading in the email headers.

Already ran postmap and upcp -sb mail/configure-postfix. Am I missing a step?

Looking further into this…

trivial-rewrite resolves routing, smtp handles connection. relayhost isn’t available to smtp service, which means we need to work backward in the pipeline.

For this to work, sender_dependent_relayhost_maps must be set. This gets used by trivial-rewrite to determine next hop before injecting back into qmgr.

In main.cf, set:

sender_dependent_relayhost_maps=hash:/etc/postfix/sender_relayhost

For /etc/postfix/sender_relayhost:

@nicolae.co     [smtp-relay.gmail.com]:587

Run postmap /etc/postfix/sender_relayhost after

Note the use of brackets. This bypasses MX lookup for the named host. The value must explicitly match in smarthost-auth, including brackets and port if specified.

You may also remove the additional service in master.d/ unless custom concurrency limits outside relaylim service are desired.

1 Like

The sender_dependent_relayhost_maps solution is what GPTs usually suggest, and can work in a simpler setup for sure but not in this case: the same relay host may need different credentials and I couldn’t find a way to instruct postfix to use the proper ones.

The additional services seem to be exactly what I need in this case. I managed to figure out a working config for Google:

# /etc/postfix/master.d/google-relay.cf 
google-relay unix  -       -       n       -       -       smtp
    -o smtp_tls_security_level=encrypt
    -o smtp_tls_wrappermode=no
    -o relayhost=[smtp-relay.gmail.com]:587

# /etc/postfix/sender_transport
@nicolae.co	google-relay:[smtp-relay.gmail.com]:587

Using just google-relay: wasn’t enough, but adding the next hop seems to do the job. :+1:

ChatGPT o1 spiraled into the same back-forth solutions as mentioned above, but managed to give me a good tip for the other service:

# /etc/postfix/master.d/mxroute-relay.cf
mxroute2-relay unix  -       -       n       -       -       smtp
    -o smtp_tls_security_level=encrypt
    -o smtp_use_tls=yes
    -o relayhost=[safari.mxrouting.net]:587
    -o smtp_sasl_auth_enable=yes
    -o smtp_sasl_password_maps=hash:/etc/postfix/sasl_passwd_mxroute2
    -o smtp_sasl_security_options=noanonymous

# /etc/postfix/sasl_passwd_mxroute2
[safari.mxrouting.net]:587	user1@domain2.tld:password1

# /etc/postfix/sender_transport
@domain2.tld	mxroute2-relay:[safari.mxrouting.net]:587

Turns out you can be very specific with services, and setting smtp_sasl_password_maps can be exactly what I need since I can create different services pointing to different password maps to properly authenticate a specific domain/pool with a specific relay user.

Although it’s working and I have replicated the same thing on another node, I think I messed config partially and would like to reset to postfix base config. Do we have a scope for that?

Enable smtp_sender_dependent_authentication. In this setting the lookup key is the sender’s email rather than SMTP relay hostname. I’d imagine the same lookup treatment occurs: first the full email then @domain.

This has no effect. relayhost is used by trivial-rewrite, not smtp service.

rm -f /etc/postfix/main.cf
dnf reinstall -y postfix
upcp -sb mail/configure-postfix

Edit: Reminds me, you should be able to define a static map with the service definition in master.cf. Something like this:

mxroute2-relay unix  -       -       n       -       -       smtp
    -o smtp_tls_security_level=encrypt
    -o smtp_use_tls=yes
    -o relayhost=[safari.mxrouting.net]:587
    -o smtp_sasl_auth_enable=yes
    -o smtp_sasl_password_maps=static:username:password
    -o smtp_sasl_security_options=noanonymous

Alternatively inline: would work if you still need a lookup.