We're slowly migrating over to Office 365 away from Postfix/Dovecot, with the goal of enabling a few users at a time. Mail for our domain should come in to Office 365 then if there's no address match found within Office 365, it should get forwarded on to Postfix which delivers it to a Dovecot mailbox (we are using a virtual users setup, all users being stored in a separate LDAP server). This allows us to use Office 365 for users that have been set up, but for others that haven't, mail goes to the existing Postfix/Dovecot system.

I have followed these instructions on making connectors etc and it works - after whitelisting EOP IPs, Office 365 will deliver to Postfix fine. The problem is getting things to go in the opposite direction. All outgoing email should be relayed through Office 365, and if I set a relayhost variable and remove our local domain from mydestinations then this works... but then Postfix won't deliver any incoming mail (results in a bounce loop). If I keep our domain in mydestinations then mail gets delivered locally and doesn't go through the relay, which means that users still on the Postfix system are unable to send email to Office 365 users.

Is there a way to force all outbound email (including locally delivered) to go via the relay yet still accept inbound email for the same domain? I've been running up against a wall all yesterday and the only real solution I can think of is to run two separate Postfix instances - one that relays everything and the other that is just used for incoming mail. But surely there's a way to do this with just one instance? I've searched but everywhere just seems to assume you're only relaying email and doing nothing else.

postconf -n looks like this (domain changed to example.com). I've taken out all the changes I made in the attempt to get Office 365 relaying:

alias_database = hash:/etc/aliases
alias_maps = hash:/etc/aliases
append_dot_mydomain = no
biff = no
content_filter = smtp-amavis:[]:10024
dovecot_destination_recipient_limit = 1
inet_interfaces = all
inet_protocols = all
mailbox_command = /usr/lib/dovecot/deliver
mailbox_size_limit = 0
mailbox_transport = dovecot
message_size_limit = 20480000
mydestination = $myhostname, silver.example.com, localhost.example.com, localhost, example.com
myhostname = smtp.example.com
mynetworks = [::ffff:]/104 [::1]/128
myorigin = /etc/mailname
readme_directory = no
receive_override_options = no_address_mappings
recipient_bcc_maps = hash:/etc/postfix/recipient_bcc
recipient_delimiter = +
relayhost =
smtp_tls_note_starttls_offer = yes
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
smtpd_recipient_restrictions = check_recipient_access hash:/etc/postfix/recipient_access, check_sender_access hash:/etc/postfix/sender_access, check_sender_access cidr:/etc/postfix/o365, reject_authenticated_sender_login_mismatch, permit_sasl_authenticated, permit_mynetworks, reject_invalid_hostname, reject_non_fqdn_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unknown_sender_domain, reject_unknown_recipient_domain, reject_unauth_pipelining, reject_unauth_destination, reject_rbl_client bl.spamcop.net, reject_rbl_client b.barracudacentral.org, reject_rbl_client zen.spamhaus.org, reject_rbl_client cbl.abuseat.org
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = private/auth
smtpd_sasl_type = dovecot
smtpd_sender_login_maps = hash:/etc/postfix/local_senders, ldap:/etc/postfix/ldap_senders.cf
smtpd_tls_CAfile = /etc/ssl/certs/example.com.cabundle
smtpd_tls_cert_file = /etc/ssl/certs/example.com.crt
smtpd_tls_key_file = /etc/ssl/private/example.com.key
smtpd_tls_loglevel = 1
smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3
smtpd_tls_received_header = yes
smtpd_tls_security_level = may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_session_cache_timeout = 3600s
smtpd_use_tls = yes
tls_random_source = dev:/dev/urandom
virtual_alias_domains = events.example.com
virtual_alias_maps = hash:/etc/postfix/redirect, ldap:/etc/postfix/ldap_virtual_users.cf, ldap:/etc/postfix/ldap_virtual_groups.cf
virtual_transport = dovecot

To get all mail relaying, I could set relayhost = example-com.mail.protection.outlook.com and remove example.com from the mydestinations list, which gets delivery working for Office 365 but then breaks the old system.

I looked into using transport_maps to try sending all emails for specific email addresses (ie. the ones moved to Office 365) via the relay and everything else works locally, but the values in there seem to always get ignored.

I'm totally out of ideas, so if anyone has any I'd be grateful.

  • I would setup all users on o365, point MX there and add a subdomain for postfix, use o365 mail enabled contacts to send the emails to the local accounts. Sadly o365 doesn't have the same dual delivery options that Google app has... Which honestly I would use for this specific case as an inbound relay for both. Dec 12 '17 at 5:06
  • That was my original plan (subdomain + forwarding), but I found if I set up our o365 domain as an internal relay then set up connectors and change MX to point to o365, any email sent to o365 that doesn't match an account instead gets forwarded on to our Postfix system, which is exactly the behaviour I want. Not sure if that's a recent development or not - last year when I looked at this project it didn't seem to be a possibility but maybe I overlooked it.
    – David M
    Dec 13 '17 at 0:45
  • Hello @DavidM - I know it's a stretch but I have a similar situation 3 years later with a difference being Postfix doesn't accept emails sent from O365 because it thinks Postfix is authoritative for a domain. Do you have some feedback on what to change in the config to allow this? serverfault.com/questions/1066334/…
    – MadBoy
    Jun 10 '21 at 18:24

OK I'm not totally happy with this, but I got it working. I feel like there's a more straightforward way though, but I can't figure it out.

After further research, I found that virtual_alias_maps is run before anything in transport_maps, which is why I thought it was being ignored. So if you have addresses being rewritten then whatever the output from the virtual alias rewrites needs to match what you're going to feed into transport_maps. Then my transport_maps hash looks like this:

email@example.com        smtp:example-com.mail.protection.outlook.com
@example.com  :
*       :

This would cause email sent to email@example.com to be relayed to Office 365, but everything else gets delivered locally.

It works, but I still feel like there's a better way to handle this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.