mailcow / mailcow-dockerized

mailcow: dockerized - 🐮 + 🐋 = 💕
https://mailcow.email
GNU General Public License v3.0
9.06k stars 1.18k forks source link

Allow setting MAILER-DAEMON from address/domain to prevent SPF/DKIM issues #4866

Closed timwhite closed 3 months ago

timwhite commented 2 years ago

Summary

When a message bounces through the system, the sender address (something like MAILER-DAEMON@mail.example.com) may not pass SPF/DKIM and so end up in a spam folder. This is because many of us run the primary domain "example.com" but use mail.example.com for Mailcow UI and server address. But SPF/DKIM is only setup on example.com, and with a strict DMARC policy for example.com (i.e. not allowing subdomains) this means anything from @mail.example.com will be rejected/quarantined.

This is particularly an issue when your bounce attempts to go to an external user

Motivation

Bounce messages ending up in spam don't help anyone

Additional context

No response

mkuron commented 2 years ago

This is particularly an issue when your bounce attempts to go to an external user

Bounce messages should never be sent externally. Internal bounce messages don‘t go through the spam filter, so a DMARC violation should not matter. Do you have a specific scenario where this is actually a problem?

timwhite commented 2 years ago

Oddly enough I do. I have some servers at home that send with my mailcow as the smarthost. They do this with an authenticated user (SASL auth) on the mailcow server that is allowed to send from any user at that domain. Because the server at home can't receive mail. However, the servers at home can't receive emails, plus I don't want those emails going back to those servers, so the actual FROM we are sending from is an Alias on the mailcow server, to an external account.

This leads to a scenario where we are sending to an external account, it bounces for some reason, so we then send the bounce to the FROM address, which is an alias to another external account, and ends up in the spam filter.

I'll try and lay it out a bit better.

Home Server, sending as servername@homeserver.domain via auth@homeserver.domain through mailcow Mailcow, hosts @homeserver.domain domain, has auth@homeserver.domain account. Also has servername@homeserver.domain as an alias to timsotheremails@bigprovider.com.

  1. Home Server: Send email to bob@example.com from servername@homeserver.domain via relayhost Mailcow. (Authed as auth@homeserver.domain)
  2. Mailcow, takes email and attempts to send it to bob@example.com. example.com rejects the email as bob has too many emails.
  3. Mailcow, generates a bounce from MAILER-DAEMON@mail.mailcowprimardomain.com to servername@homeserver.domain
  4. Mailcow takes the bounce for servername@homeserver.domain, finds it's an alias to timsotheremails@bigprovider.com, sends from MAILER-DAEMON@mail.mailcowprimardomain.com to timsotheremails@bigprovider.com, but there is no SPF/DKIM for mail.mailcowprimardomain.com
  5. bigprovider.com puts the email into spam (rightly so) as DMARC on mailcowprimardomain.com says don't allow any subdomains.

Yes, the simple solution for me in this case is to make servername@homeserver.domain be a local account. However it shows we can't always guarantee a bounce will stay local, especially when sending from an alias address.

I hope that's clearer than mud

andryyy commented 2 years ago

Just setup a DMARC record for that domain then. With corresponding and limited SPF.

timwhite commented 2 years ago

My hope was to just setup mail.mailcowdomain in Mailcow as a domain, that way I could setup DKIM for it too. But unfortunately Mailcow doesn't allow us to add the mailcow hostname as a domain. Yes, SPF and DMARC will be "enough", but if we could set the MAILER-DAEMON address that would be better.

I think we just need to set the myorigin = $mydomain config for postfix, I believe the default is myorigin = $myhostname which has the FQDN for the server, where $mydomain is the parent domain of the FQDN. (And yes, I can set this manually following the instructions at https://docs.mailcow.email/manual-guides/Postfix/u_e-postfix-extra_cf/) but we should probably consider if this should be a default, or at least mentioned in the docs?

dragoangel commented 4 months ago

This is particularly an issue when your bounce attempts to go to an external user

Bounce messages should never be sent externally. Internal bounce messages don‘t go through the spam filter, so a DMARC violation should not matter. Do you have a specific scenario where this is actually a problem?

Hi @mkuron, where do you read that bounces should be never be sent externally?

mkuron commented 4 months ago

It‘s called email backscatter. To avoid it, errors should be reported during the SMTP conversation instead of afterwards via bounce.

dragoangel commented 4 months ago

It‘s called email backscatter. To avoid it, errors should be reported during the SMTP conversation instead of afterwards via bounce.

@mkuron main reality here is: to avoid. Ideally yes, you need reject connection at SMTP stage, and in setup like mailcow where you have LMA locally, directly after MTA - yes, such bounces honestly should not occur generally, but can occur even in such simple setup in case you using forwarding. As you get more complicated setups - bounces outside of TCP session increase. Main idea of avoiding backscatters is simple: always reject DMARC fail at SMTP session - this will not send ever backscatter to person with strict DMARC and failed checks. Any big complex ESP send bounces outside of TCP session usually in some cases, more or less. So this false statement.

And this not changing fact that mailcow really missing in DNS tool configuration that needed to authorize bounces properly.

To authorize bounces needed 2 things:

  1. Have DKIM for MAILCOW_HOSTNAME domain as mailer daemon send with From $my_hostname
  2. Create SPF for MAILCOW_HOSTNAME domain as envelope-from in bounces is empty and server's greeting is used to check SPF.
Mygod commented 3 months ago

I think we just need to set the myorigin = $mydomain config for postfix, I believe the default is myorigin = $myhostname which has the FQDN for the server, where $mydomain is the parent domain of the FQDN. (And yes, I can set this manually following the instructions at https://docs.mailcow.email/manual-guides/Postfix/u_e-postfix-extra_cf/) but we should probably consider if this should be a default, or at least mentioned in the docs?

I just tried this fix from @timwhite and although it does change the domain of the outgoing mail-daemon emails, it still fails the DKIM/SPF checks. I suspect this might be because of Return-Path being null, and it looks like Gmail is using the hostname for SPF checks still. Therefore, it's a better idea to add a SPF record like v=spf1 a ~all to stop bouncing instead.

dragoangel commented 3 months ago

I just tried this fix from @timwhite and although it does change the domain of the outgoing mail-daemon emails, it still fails the DKIM/SPF checks. I suspect this might be because of Return-Path being null, and it looks like Gmail is using the hostname for SPF checks still. Therefore, it's a better idea to add a SPF record like v=spf1 a ~all to stop bouncing instead.

  1. It's about empty envelope-from for bounces. If envelope from is empty - host greeting (HELO which is mailcow's FQDN) always used to verify SPF.
  2. Dmarc pass when at least one of SPF or dkim pass, so technically when you sign bounces with dkim - spf is not strictly required.
  3. Better use -all always, just forget about ~ in SPF.
Mygod commented 3 months ago

Hmm gmail seems to verify the hostname though and doesn't seem to show what is envelope from. smtp.helo shows the hostname which seems to be what was used. DKIM-Signature is indeed missing but my other emails do have a DKIM signature.

dragoangel commented 3 months ago

To add why this doesn't needed, you also guys have watchdog, which also sends emails as watchdog@{MAILCOW_HOSTNAME}, and while you potentially can sign bounces with DKIM (if reconfigure rspamd additionally) you can't sign watchdog for sure as it should operate when things goes fully wrong, so it routed directly to MX of rcpt, not via postfix & rspamd, as result no dkim signing...

Hi @DerLinkman I think we can add to the docs info about watchdog and MAILER-DAEMON and requirement to set SPF and DMARC at MAILCOW_HOSTNAME level, f.e.:

_dmarc.cow.example.com IN TXT "v=DMARC1; p=reject"
cow.example.com IN TXT "v=spf1 ip4:192.0.2.146/32 ip6:2001:db8::1/128 -all"

It can be part of Post Installation Tasks like: SPF to authorize watchdog and bounces or something like that 😁

DerLinkman commented 3 months ago

Can you create a PR for that inside docs? @dragoangel

dragoangel commented 3 months ago

@DerLinkman I prepared PR https://github.com/mailcow/mailcow-dockerized-docs/pull/740 - but it requires DE translation and review, can you please take a look?

DerLinkman commented 3 months ago

Done, see docs