Use Postfix Transport Map & Relayhost Map For Flexible Email Delivery
In previous tutorials, we discussed how to quickly set up a full-featured mail server using iRedMail or Modoboa, and we also learned how to set up SMTP relay with Postfix SMTP server to bypass port 25 blocking or IP blacklists. However, you might not want to set up your entire email server to use a relay host. We can configure Postfix transport map and relay map so that some emails are delivered via relay host, other emails are sent directly to recipients.
There are many SMTP relay services. In this tutorial, I use Sendinblue which allows you to send 9000 emails per month for free. SMTP relay services maintain a good IP reputation. They stop the bad senders and grow the good ones, so using SMTP relay service will increase the chance of hitting the inbox.
How to Use Postfix Transport Map
The transport map defines mappings from recipient address to transport method. By default, the value of the transport_maps
parameter in Postfix is not set, as can be checked with:
postconf transport_maps
Sample output:
transport_maps =
iRedMail and Modoboa use MySQL/MariaDB database to store transport maps. If you used iRedMail to set up your mail server, then the output should be like:
transport_maps = proxy:mysql:/etc/postfix/mysql/transport_maps_user.cf proxy:mysql:/etc/postfix/mysql/transport_maps_domain.cf
If you used Modoboa to set up your mail server, then the output should be like:
transport_maps = proxy:mysql:/etc/postfix/sql-transport.cf proxy:mysql:/etc/postfix/sql-spliteddomains-transport.cf
The transport_maps
parameter points to one or more transport lookup tables. You can edit the Postfix main configuration file.
sudo nano /etc/postfix/main.cf
And set a value by adding the following line at the end of the file. The /etc/postfix/transport
file will contain the lookup table.
transport_maps = hash:/etc/postfix/transport
If you use iRedMail, you can find the transport_maps
parameter and set the value to
transport_maps = hash:/etc/postfix/transport proxy:mysql:/etc/postfix/mysql/transport_maps_user.cf proxy:mysql:/etc/postfix/mysql/transport_maps_domain.cf
If you use Modoboa, you can find the tranport_maps
parameter and set the value to:
transport_maps = hash:/etc/postfix/transport proxy:mysql:/etc/postfix/sql-transport.cf proxy:mysql:/etc/postfix/sql-spliteddomains-transport.cf
A lookup table can be a file, or in the form of MySQL/MariaDB database tables. Lookup tables will be searched in the specified order until a match is found.
Save and close the Postfix main configuration file. Next, we need to create the lookup table file.
sudo nano /etc/postfix/transport
In this file, we can define mappings from recipient addresses to transport methods. For example, I found that many .pl
(Poland) domains are using a particular blacklist that blocks my mail server’s IP address. I can add the following line in this file so that emails sent to .pl domains will be relayed through Sendinblue.
.pl relay:[smtp-relay.sendinblue.com]:587
Some people find that it’s hard to get into the inbox of Microsoft mailboxes (hotmail.com, outlook.com, etc). It’s very likely that your email will be put in the spam folder. Well, you can try using Sendinblue to deliver emails to Microsoft mailbox users. Sendinblue even allows you to see if the recipient opened or clicked links in your email. So I put the following lines in the file.
/.*@hotmail.*/i relay:[smtp-relay.sendinblue.com]:587 /.*@outlook.*/i relay:[smtp-relay.sendinblue.com]:587 /.*@live.*/i relay:[smtp-relay.sendinblue.com]:587 /.*@msn.*/i relay:[smtp-relay.sendinblue.com]:587
If you want to use relay host to deliver emails to a particular recipient, but send emails directly to all other recipients in the same domain, then you can add a line like below.
[email protected] relay:[smtp-relay.sendinblue.com]:587
If a certain SMTP server doesn’t use the default SMTP port 25, but uses a different port such as 2525 to receive incoming emails, you can add the following line
example.com smtp:[mail.example.com]:2525
It’s a good practice to add your own domain name in this file like below.
your-domain.com local
This tells Postfix that emails sent to your own domain should be delivered locally. This is the default behavior for canonical domains. If your mail server has multiple virtual domains, you should add all of your virtual domains.
your-domain1.com local your-domain2.com local
If you just put the following two lines in the file and don’t add other lines, this will make all emails, excluding emails sent to your own domain, delivered via the relay host. The asterisk (*) is a wild-card character that represents any email address.
your-domain.com local * relay:[smtp-relay.sendinblue.com]:587
We can also have the following configuration, which means that emails sent to your own domain are delivered locally. Email sent to gmail.com are delivered normally by performing MX lookup and all other emails are delivered via the relay host.
your-domain.com local gmail.com smtp * relay:[smtp-relay.sendinblue.com]:587
Save and close the file. Then run the following command to build the index file.
sudo postmap /etc/postfix/transport
Restart Postfix for the changes to take effect.
sudo systemctl restart postfix
Sender Dependent Relay Maps
The transport map defines mappings from a recipient address to transport method. If you want to define mappings from sender address to relay hosts, use the sender_dependent_relay_maps
parameter. By default, its value is empty, as can be seen with:
postconf sender_dependent_relayhost_maps
Output:
sender_dependent_relayhost_maps =
iRedMail uses MySQL/MariaDB database to store sender-dependent relayhost maps. If you used iRedMail to set up your mail server, then the output should be like:
sender_dependent_relayhost_maps = proxy:mysql:/etc/postfix/mysql/sender_dependent_relayhost_maps.cf
The sender_dependent_relayhost_maps
parameter points to one or more lookup tables. You can edit the Postfix main configuration file.
sudo nano /etc/postfix/main.cf
And set a value by adding the following line at the end of the file. The /etc/postfix/relay_by_sender
file will contain the lookup table.
sender_dependent_relayhost_maps = hash:/etc/postfix/relay_by_sender
If you use iRedMail, you can find the sender_dependent_relayhost_maps
parameter and set the value to
sender_dependent_relayhost_maps = hash:/etc/postfix/relay_by_sender proxy:mysql:/etc/postfix/mysql/sender_dependent_relayhost_maps.cf
Lookup table can be a file, or in the form of MySQL/MariaDB database tables. Lookup tables will be searched in the specified order until a match is found.
Save and close the Postfix main configuration file. Next, we need to create the lookup table file.
sudo nano /etc/postfix/relay_by_sender
Add rules like below, this will make emails sent from [email protected]
delivered via the relay host specified on the right side.
[email protected] [smtp-relay.sendinblue.com]:587
Let’s say if you have a Linux server that hosts two websites and each website has its own mail server running on two separate hosts, then you can add the following two lines to make each website uses its own mail server.
@domain1.com [mail.domain1.com]:587 @domain2.com [mail.domain2.com]:587
Save and close the file. Then build the index file.
sudo postmap /etc/postfix/relay_by_sender
Restart Postfix for the changes to take effect.
sudo systemctl restart postfix
Set Up SMTP Authentication
Now we need to set up SMTP authentication so that the Postfix SMTP client can use the relay host. Edit the Postfix main configuration file.
sudo nano /etc/postfix/main.cf
Add the following lines at the end of this file. The /etc/postfix/sasl_password
will contain the username and password.
# outbound relay configurations smtp_sasl_auth_enable = yes smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd smtp_sasl_security_options = noanonymous smtp_tls_security_level = may header_size_limit = 4096000
If you have set the relayhost
parameter, then I recommend giving it an empty value like below, because we are now using transport maps and sender dependent relayhost maps.
relayhost =
Save and close the file. Then create the /etc/postfix/sasl_passwd
file.
sudo nano /etc/postfix/sasl_passwd
Add the SMTP relay host and SMTP credentials to this file like below. Replace smtp_username
and smtp_password
with your own username and password that are given by SendinBlue. Note there’s a colon between the username and password.
[smtp-relay.sendinblue.com]:587 smtp_username:smtp_password
Save and close the file. Then create the corresponding hash db file with postmap
.
sudo postmap /etc/postfix/sasl_passwd
Now you should have a file /etc/postfix/sasl_passwd.db
. Restart Postfix for the changes to take effect.
sudo systemctl restart postfix
By default, sasl_passwd
and sasl_passwd.db
file can be read by any user on the server. Change the permission to 600 so only root can read and write to these two files.
sudo chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
Testing
Now you can send test email to the recipients defined in transport maps, or send an email from the address specified in sender dependent relayhost maps. Then check the mail log (/var/log/mail.log
or /var/log/maillog
) to see if it’s working.
Note that if you are using a third-party SMTP relay service like Sendinblue, then it’s likely that you are required to validate your domain name in your account and edit SPF and DKIM record.
Troubleshooting
error #1
If your email wasn’t delivered and you found the following message in the mail log (/var/log/maillog
),
Relay access denied (in reply to RCPT TO command))
then you might need to edit the /etc/postfix/sasl_passwd
file and remove the port number after the hostname like below.
smtp-relay.sendinblue.com smtp_username:smtp_password
Save and close the file. Then build the index file again.
sudo postmap /etc/postfix/sasl_passwd
Restart Postfix for the changes to take effect.
sudo systemctl restart postfix
Now you can flush the email queue (attempt to deliver the previous emails).
sudo postqueue -f
error #2
Note that sender_dependent_relayhost_maps
doesn’t support the special keywords: smtp
, local
, etc. If you see the following error in Postfix logs, it means you used the smtp
keyword.
Host or domain name not found. Name service error for name=smtp type=A: Host not found
Bonus Tip: smtp_fallback_relay
You can specify a fallback relay host in Postfix. This way, if an SMTP destination can’t be reached (no MX record, no A record) or the primary relay host is offline, Postfix will use the fallback relay host.
Edit the main Postfix configuration file.
sudo nano /etc/postfix/main.cf
Add the following line in this file. Replace secondary.relayhost.com
with the actual relayhost name. This relay host can be from Sendinblue or any other SMTP relay services.
smtp_fallback_relay = [secondary.relayhost.com]:587
Save and close the file. Then you should edit the /etc/postfix/sasl_passwd
file and add the SMTP credentials for the fallback relay host just like above. Finally, restart Postfix for the changes to take effect.
Note that if the SMTP destination is using greylisting to temporarily reject email messages, then your Postfix SMTP server will also use the fallback relay host.
Per-User Relay Rules with Virtual Mailboxes
Let’s say you have set up business emails on a third-party service like Zoho. Now you have a self-hosted email server which is using virtual mailboxes. You want to keep the old email addresses on Zoho, but create new email addresses in your own email server. In this case, you need to create per-user relay rules so that emails destined for the old email addresses will be sent to the Zoho mail server.
Edit Postfix main configuration file.
sudo nano /etc/postfix/main.cf
Find the virtual_mailbox_maps
parameter and add hash:/etc/postfix/transport
to the value field.
virtual_mailbox_maps = hash:/etc/postfix/transport proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf, proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf
Save and close the file. Then in the /etc/postfix/transport
file, you can define relay rules for the old email addresses like below. (Note: You can also use the relay
keyword instead of smtp
. They are both correct in this case.)
[email protected] smtp:[mx.zoho.com]:25 [email protected] smtp:[mx.zoho.com]:25 [email protected] smtp:[mx.zoho.com]:25
Save and close the file. Then build the hash table for the /etc/postfix/transport
file.
sudo postmap /etc/postfix/transport
Then restart Postfix.
sudo systemctl restart postfix
Wrapping Up
I hope this tutorial helped you use Postfix transport maps and sender dependent relayhost maps. As always, if you found this post useful, subscribe to our free newsletter to get more tips and tricks. Take care 🙂
This is a great tutorial! As usual! I have been waiting for this. I only have one question remaining, I use iRedmail. The transport maps are where expected. How do I edit the mysql database to redirect a domain. Is it done in the cf file or directly to the db? What is the format?
Many thanks
iRedAdmin Pro users can easily manage transport maps in the admin panel. If you use the free version of iRedAdmin, you need to log into MySQL/MariaDB and use SQL command to add transport maps. More details can be found at https://docs.iredmail.org/per-account.transport.html
You can still create transport maps on iRedMail server with the plain text file /etc/postfix/transport, if the parameter is set to:
Thanks for this tutorial… I use the sender_dependent_relayhost_maps and it works – but only for recipient domains, which are not local mail domains. This is the postfix standard and might be usefull in most cases.
Is there an option to change this behaviour? To always use the SMTP relay insted of local delivery even if sender and recipient are on the same server?
The use case is that the SMTP Relay Server manages archiving for example…
In
/etc/postfix/transport
file, addThen
What if I want only a few domains using sendinblue and the rest goes to the server’s smtp. I have about 80 domains, looking for an easier way instead of listing them one by one.
My log:
How yo fix it?
You have duplicate entries in
/etc/postfix/master.cf
file. You have twosmtps
services.Ok tks XIao, what about warning on this line:
Very detailed tutorial!
Hi Xiao,
Thanks for sharing such detailed and helpful tutorial. Would you mind helping me to setup the same configuration for Exim 4.9x? Actually, I’ve been using DirectAdmin control panel and this comes up with Exim MTA only. And my IP is whitelisted on all major mail servers except the Outlook/Hotmail one. I want you to use the same way to configure Exim to only relay/route emails for hotmail.com/outlook.com etc.
Waiting for your response.
This helped me, however my e-mail wasn’t relaying, it said authentication required – even though everything was configured.
After a bit more Google’ing, it turns out the hostname/port in /etc/postfix/sasl_passwd must match exactly with /etc/postfix/relay_by_sender. I.e. it needs the [ ] in /etc/postfix/sasl_passwd too:
should be:
this a very good post, thanks a lot.
I’m using modoboa and everything work well until my emails get blocked by hotmail, outlook.. etc. I research and i can use the SendGrid or the Sendinblue as relay server but i don’t have clear how manage the DNS records required by the relay hosts and the previously created on my domains. I already have the SPF and DKIM configured with the modoboa keys. I can add also the relay hosts DNS records without problem ?
Yes, you can add multiple DKIM records, because each DKIM record has its own selector.
dkim._domainkey
uses thedkim
selector.mail._domainkey
uses themail
selector.SPF records can be merged into one record to include new SMTP hosts.
That’s great. Thank you.
Great post – glad I found it. The transport map works fine for simple destinations, but I can’t get your example of how to it for Microsoft destinations to work (with the wildcards). When I try to do a query against the map, it doesn’t match. Here’s one that doesn’t work:
but
works fine.
My example is
Found the problem: if you want to use regular expressions in the transport map, it must be a ‘regexp’ lookup file, not a ‘hash’. So the ‘main.cf’ configuration is ‘transport_maps = regexp:/etc/postfix/transport’, and all entries in the map must be regular expressions (enclosed in ‘/’s).
Thanks again for a great article!
i dont’t get it working with virtual mailboxes. it seems, as if the transport_maps are not triggered. Any solution/workaround to get it done with virtual mailboxes?
Hi there
I’m having issues with this tutorial, transport is not being parsed according to the filter and additionally “mail transport unavailable” is reported. I have previously setup postfix along with dovecot.
These are the config files and log
/etc/postfix/main.cf
https://pastebin.com/YMemmwTv
/etc/postfix/master.cf
https://pastebin.com/u4ruVcpW
/etc/dovecot/conf.d/10-master.conf
https://pastebin.com/kRimqyE4
/var/log/mail.log
https://pastebin.com/fsTi53tc
Thanks in advance.
Martin
Hi Martin,
If you need to send emails to Microsoft users or bypass email blacklist, I have a dedicated tutorial for this: How to Bypass the Microsoft Outlook IP Blacklist & Other Blacklists
Great tutorial. Thank you.
In the section “Set Up SMTP Authentication” you increased the header size…
The default value of 102400 seems adequate. Can you provide some reasoning for why you recommend the increase?
It’s okay. I found your comments relating to this setting in another of your tutorials.
I didn’t use iRedMail or Modoboa. I’m following the PostfixAdmin virtual mailboxes instructions.
/etc/postfix/main.cf
/etc/postfix/sasl_passwd
/etc/postfix/transport
Like your example, I have local emails in postfix and old emails in a third party email server.
Above are my configurations. Which I based according to your documentation. It works great. However, I want don’t want to list all my old emails under transport but instead relay all emails based on my domain.
These are the options I’ve tried. One at the time not all together (under etc/postfix/transport):
None of the above worked. Am I missing something?
If you followed my PostfixAdmin tutorial, then you just need to add
You shouldn’t change the
virtual_mailbox_maps =
parameter.For the virtual mailbox example.
Is there a way to relay all email from my own domain instead of listing every single old email address under /etc/postfix/transport?
I tried the following (one at the time)/etc/postfix/transport
None of the above worked.
It only works if I list each email individually:
Why do you want to relay your own domain email? I just use the following line in /etc/postfix/transport to use the local delivery agent.
My mail server hosts emails for linuxbabe.com. I don’t want to use a relay to deliver emails to my own domain.
I have an Office365 Exchange server which is holds the majority of my emails.
This postfix server will host just a few additional emails.
All incoming and outgoing email for my domain goes through Office365 server:
1.When an email for a postfix user is detected, my Office365 relays the email to Postfix.
2.All outgoing email from Postfix should first relay to Office365 before going to the internet
If my domain is stablished as local under /etc/postfix/transport, my Postfix emails cannot communicate to my Office365 emails. This is because it only looks for emails in the postfix MySQL server and when it does not find a matching account, it believes it doesn’t exist and the email is not delivered between the two servers.
Again, since the majority of my emails reside in Office365 it’s tedious having to list them all under /etc/postfix/transport. I would like to set the entire domain to relay to the relayDestination (Office365) by default…
You are using one domain name and storing most of the email addresses on the Exchange server and some on the Postfix server. This is a bad setup.
It’s better just to host all email addresses of a domain name on a single server. You can migrate the email addresses to the Postfix server.
How to Easily Transfer Old Emails to Your New Email Server
hi linuxbabe,
Thanks for this tutorial, which is really helpful. One small error though:
You are using regular expressions in your /etc/postfix/transport file, so you should use regexp table type in /etc/postfix/main.cf like this:
See postfix table types here: https://www.postfix.org/DATABASE_README.html
Please correct the tutorial, thank you!
i want to make custom transport in postfix and send emails to specific domain like example.com with delay 2s per emails this rate limit will not effect local domain “slow” is transporter name
slow_destination_recipient_limit = 2
slow_destination_rate_delay = 2s
per domain more than 1 email will go with 2 second delay
plz help
I defined transport as follows ‘transport_maps = hash:/etc/postfix/transport’ in main.cf.
My transport mappings are
# cat /etc/postfix/transport | tail -2
*.example.com local
* relay:[smtp.gmail.com]:587
Even though, when i try to send email to [email protected]. It’s keep on relaying gmail.com with port 587.
Please provide your suggestion.
Thanks in advance,
What is the priority between transport_maps and sender_dependent_relayhost_maps ?
Let’s imagine if I got a rule for gmail.com in transport_maps (“Use SMTP X) and a another specific rule in sender_dependent_relayhost_maps (“This sender should be relayed through SMTP Y”)
What will happen if this user tries to send an e-mail to gmail.com ? Which rule will be applied ?
Dear, We have followed the same above steps for our iRedMail Pro server of sending via different transport.
but in systemctl status postfix.service
following error showing
Sep 12 01:37:28 mail.vinsys.live postfix/qmgr[3832]: warning: connect to transport private/smtp-mail.outlook.com: No such file or directory
Note: we are using outlook.com SMTP
Regards,
Sidharth