Opened 12 years ago

Last modified 16 months ago

#6989 assigned Bug

Inability to define DNS_NAME in django.core.mail results in e-mail messages being rejected or marked as spam

Reported by: Franklin Owned by: heathervm
Component: Core (Mail) Version: master
Severity: Normal Keywords: local_hostname, DNS_NAME, CachedDnsName, smtplib, SMTPConnection
Cc: jeremy+django@…, davidgrant@… Triage Stage: Accepted
Has patch: yes Needs documentation: yes
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no


Being the case that the application server's hostname may not necessarily be a valid fully qualified domain name (FQDN) the use of socket.getfqdn() in defining DNS_NAME may yield a number of e-mail messages either rejected or marked as spam. Rejection issues arise if settings.EMAIL_USE_TLS is True - meaning smtplib.ehlo() will be called - and if a mail server is particularly strict (or misconfigured) and rejects any ehlo command followed by an invalid FQDN. Spam issues arise with DNS_NAME being used as the local_hostname argument to smtplib.SMTP() within the method, meaning the initial "Received:" e-mail header may be from an invalid FQDN. Further increasing the chance of being marked as spam is DNS_NAME being used by the make_msgid() method, leaving the "Message-ID:" e-mail header ending in an invalid FQDN.

Real World Scenario
A shared server has a hostname, which you may not and can not change, of "star-wars-reference". The socket.getfqdn() method fails to find info on its IP address and by default simply returns said hostname. E-mail is then sent by Django with a Message-ID of "200804....@star-wars-reference" from a server claiming to be "star-wars-reference ([server's IP address])" and is, of course, marked as spam.

Provide an optional settings variable such as EMAIL_LOCAL_HOSTNAME where Django developers may define a FQDN which maps to their application's server. EMAIL_LOCAL_HOSTNAME will be used by the class defining DNS_NAME in lieu of socket.getfqdn() if EMAIL_LOCAL_HOSTNAME exists in the settings file (this has the added benefit of preventing a call to socket.getfqdn() - further reducing overhead on restarts).

Attachments (2)

mail-local-hostname.diff (465 bytes) - added by Franklin 12 years ago.
mail-local-hostname2.diff (3.9 KB) - added by Jeremy Grosser 9 years ago.

Download all attachments as: .zip

Change History (23)

Changed 12 years ago by Franklin

Attachment: mail-local-hostname.diff added

comment:1 Changed 12 years ago by edgarsj

Needs documentation: set
Patch needs improvement: set
Triage Stage: UnreviewedDesign decision needed

comment:2 Changed 10 years ago by stilldodge

This still appears to be an issue. Possibly this was unresolved because email servers used to accept an invalid FQDN. I can confirm that Exchange 2007 rejects the connection if the local host "calculated" name is not truly a valid FQDN

comment:3 Changed 10 years ago by Malcolm Tredinnick

Triage Stage: Design decision neededAccepted

Changed 9 years ago by Jeremy Grosser

Attachment: mail-local-hostname2.diff added

comment:4 Changed 9 years ago by Jeremy Grosser

I've attached an updated and documented patch (mail-local-hostname2.diff) allowing the user to specify EMAIL_LOCAL_HOSTNAME. Please review and let me know if any changes are necessary to get this merged.

comment:5 Changed 9 years ago by Jeremy Grosser

Cc: jeremy+django@… added

comment:6 Changed 9 years ago by Adrian Holovaty

I'm just skimming this, but my immediate reaction is: introducing a new setting is a non-starter. Is there a way to accomplish what you want without a setting?

comment:7 Changed 9 years ago by Jeremy Grosser

We could force anybody needing this to subclass the SMTP EmailBackend, but that seems a bit excessive to me.

comment:8 Changed 9 years ago by Julien Phalip

Severity: Normal
Type: Bug

comment:9 Changed 8 years ago by Aymeric Augustin

UI/UX: unset

Change UI/UX from NULL to False.

comment:10 Changed 8 years ago by Aymeric Augustin

Easy pickings: unset

Change Easy pickings from NULL to False.

comment:11 Changed 7 years ago by Edwin

Here is a workaround.

Python's socket.getfqdn() resolution process works like this on Linux:

  1. Get hostname of server.
  2. Resolve IP address for hostname.
  3. Resolve name for IP address.
  4. If 2 or 3 fail, just use the hostname.

Therefore, if you add a line like this to your /etc/hosts, socket.getfqdn() will resolve myhostname to and resolve to myfqdn since that is the first name in the list. You also have to make sure that there are no other entries for on previous lines.       myfqdn myhostname

comment:12 Changed 7 years ago by anonymous

That workaround only makes sense if the server is hosting one django project. I have one Linux server with several django projects. Each uses a different fqdn but the same IP.

comment:13 Changed 7 years ago by davidgrant@…

Can we get this in? Relying on socket.get_fqdn() seems very wrong and patch looks good.

comment:14 Changed 7 years ago by davidgrant@…

So where do we go from here? Instead of a setting we could use an environment variable. Other than that I don't see any other way.

comment:15 Changed 7 years ago by davidgrant@…

Cc: davidgrant@… added

comment:16 Changed 7 years ago by Russell Keith-Magee

@davidgrant - Where do we go? We go the same way we do with any other ticket that has stalled: Start a discussion on django-dev. Summarize the problem. Summarize the alternatives. Propose a solution.

I'll also note that Adrian's comment about settings -- we've historically avoided adding new settings wherever possible. But if it truly isn't possible (at all, or for all practical purposes) to avoid a setting, it's not completely off the cards.

comment:17 Changed 3 years ago by Tim Graham

I think a setting is fine considering we added other mail settings recently. The patch needs to be updated, checked against the PatchReviewChecklist, and turned into a pull request.

comment:18 Changed 3 years ago by heathervm

Owner: changed from nobody to heathervm
Status: newassigned

comment:19 Changed 2 years ago by Diederik van der Boor

Python's smtplib.SMTP works around this problem with a fallback to the IP address::

            # RFC 2821 says we should use the fqdn in the EHLO/HELO verb, and
            # if that can't be calculated, that we should use a domain literal
            # instead (essentially an encoded IP address like [A.B.C.D]).
            fqdn = socket.getfqdn()
            if '.' in fqdn:
                self.local_hostname = fqdn
                # We can't find an fqdn hostname, so use a domain literal
                addr = ''
                    addr = socket.gethostbyname(socket.gethostname())
                except socket.gaierror:
                self.local_hostname = '[%s]' % addr

This is overwritten as Django's django.core.mail.backens.smtp.EmailBackend overwrites this to:

connection_params = {'local_hostname': DNS_NAME.get_fqdn()}

One possible extra fix would be to support the same fallback to IP-addresses when there is no dot in the hostname, just like does.

Last edited 2 years ago by Diederik van der Boor (previous) (diff)

comment:20 Changed 2 years ago by Diederik van der Boor

To add, this issue also happens on Kubernetes pods.

A standard Pod on Kubernetes has the following configuration:


# Kubernetes-managed hosts file.	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
fe00::0	ip6-mcastprefix
fe00::1	ip6-allnodes
fe00::2	ip6-allrouters	examplepod-77f687b9b9-5hlsg


search NAMESPACE.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Hence email is submitted using EHLO examplepod-77f687b9b9-5hlsg and thus triggering spam filtering.

comment:21 Changed 16 months ago by Diederik van der Boor

I bumbed into this again, in the end I had to fix this by patching:

django.core.mail.utils.DNS_NAME._fqdn = ""

Note: See TracTickets for help on using tickets.
Back to Top