Django: Prevent email notification on SuspiciousOperation

Django 1.4.4 introduced the ALLOWED_HOSTS setting as implemented in django/http/

A list of strings representing the host/domain names that this Django site can serve. This is a security measure to prevent an attacker from poisoning caches and password reset emails with links to malicious hosts by submitting requests with a fake HTTP Host header, which is possible even under many seemingly-safe webserver configurations.

If the host header holds an unknown host and DEBUG is set to False, a SuspiciousOperation exception is raised. This results in an HTTP 500 (Internal Server Error) error code which is returned to the client. I believe this was chosen over the HTTP 4xy-class error (Client Error) so that the admins are notified via email (see the Error Reporting docs). This is a good thing if you have misconfigured the ALLOWED_HOSTS setting and forgot to include some host name that should be usable with the site.

If, however, you are constantly spammed by Django error messages because someone is scanning your website and tries to set a fake Host header, things get annoying. I posted a bug report on the Django bug tracker, and it looks like this will be handled either in 1.5.1 or at least in 1.6. (I wish to note at this place that I’m very grateful that Django has such a responsive dev team. The first response came in in less than 3 hours after the bug, and the first proposed patch was posted on the same day. Thank you!)

Until Django is properly fixed, I need some workaround that I implemented as a logging filter that prevents SuspiciousOperation exceptions from being sent via email (it does not change the HTTP 500 into an HTTP 400):

from django.core.exceptions import SuspiciousOperation

def skip_suspicious_operations(record):
  if record.exc_info:
    exc_value = record.exc_info[1]
    if isinstance(exc_value, SuspiciousOperation):
      return False
  return True

To activate this filter, it must be included in your file just like in the logging docs, where I also got the blueprint for the code that is listed above.

I prepared a minimal example project for your convenience. It comes with the filter enabled.

If you’d like to verify that the filter works, do the following:

  • Check out the example project and make sure that Django is installed (either globally or in a virtualenv).
  • Run the dev server:
    python runserver
  • On a second terminal, run the SMTP debugging server built into Python:
    sudo python -m smtpd -n -c DebuggingServer localhost:25

    (sudo is necessary because port 25 (SMTP default) can only be used by root)

  • On a third terminal, check that the main page works:
    curl http://localhost:8000/

    (should print “Hello, world” to the console)

  • Check that changing the Host name leads to an error message, but that no email is sent (look at the terminal that runs the SMTP server, nothing should be printed there):
    curl -H "Host: asdfasdf" http://localhost:8000/
  • Check that other server errors are sent out as an email (the SMTP debugging server should print the lenghty message):
    curl http://localhost:8000/500

Join the Conversation


  1. Thank you for posting this! I just switched to the latest version of django and this was driving me crazy!

  2. Hi,

    In my case (Django 1.6.2) I still get an email for curl -H “Host: asdfasdf” http://localhost:8000/ .
    Here it is :

    ———- MESSAGE FOLLOWS ———-
    MIME-Version: 1.0
    Content-Type: text/plain; charset=”utf-8″
    Content-Transfer-Encoding: 7bit
    Subject: [Django] ERROR: Invalid HTTP_HOST header: ‘asdfasdf’.You may need to
    add u’asdfasdf’ to ALLOWED_HOSTS.
    From: root@localhost
    To: ad@min.example
    Date: Thu, 13 Mar 2014 11:43:07 -0000

    No stack trace available

    Request repr() unavailable.
    ———— END MESSAGE ————

    1. The same problem occurs for Django 1.6 and Django 1.6.1 (tested in virtualenvs).
      I can’t get an other behavior than this “Request repr() unavailable.”… !

      Any idea?

          1. I think the fix for Django 1.6 is to change or duplicate ‘django.request’ to ‘’ under LOGGING[‘loggers’], like so:

            ‘loggers’: {
            ‘django.request’: {
            ‘handlers’: [‘mail_admins’],
            ‘level’: ‘ERROR’,
            ‘propagate’: True,
            ‘’: {
            ‘handlers’: [‘mail_admins’],
            ‘level’: ‘ERROR’,
            ‘propagate’: True,

            Since these SuspiciousOperation warnings are now routed through the log handler: see the comments on

Leave a comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.