Forums

405 Error when sending email via POST request with Django

I'm building my first Django app, and have a simple contact form with the usual fields (recipient's address, subject, sender's address, and message) that I submit via a POST request to the home page view. If the form is valid, it sends the email and redirects to a success page. Searching through the PythonAnywhere forums, it seems that best practice for sending email on PythonAnywhere is to use Google's SMTP servers, so I set up a gmail account and updated my settings accordingly. Code for view, form, HTML template, and settings is below. The URL for the app is here: http://www.doorstepstudios.com/

Whenever I try to submit, I get a "405 Not Allowed" error. My error logs are empty, and the server logs show the following:

DAMN ! worker 3 (pid: 27518) died, killed by signal 9

I've already tried reloading the app, which doesn't resolve the error. I've also confirmed that the redirect URL exists (http://www.doorstepstudios.com/launched)

So, two questions:

  1. Has anyone else had a similar 405 problem, and/or have any insight on what's going on? I found one other related post in the forums here that the user solved themselves, but didn't post their solution, and the only other suggestion was about Flask routes, which as far as I can tell from the docs doesn't apply to Django

  2. Is the best practice for submitting emails on a PythonAnywhere hosted app still to use Google SMTP servers, or is that outdated and therefore causing problems?

views.py

def home_page(request):

    if request.method == 'POST':
        form = ContactForm(data=request.POST)
        if form.is_valid():
            recipients = list(form.cleaned_data['to_field'])
            subject = form.cleaned_data['subject_field']
            sender = form.cleaned_data['from_field']
            message = form.cleaned_data['message_field']
            send_mail(subject, message, sender, recipients, fail_silently=False)
            return HttpResponseRedirect('/launched')

    return render(request, 'home.html', {'dream_form' : DreamsForm(), 'contact_form' : ContactForm()})

forms.py

ContactForm(forms.Form):

to_field = forms.CharField(max_length=100, label="")
subject_field = forms.CharField(max_length=100, label="")
from_field = forms.EmailField(label="", 
    widget=forms.TextInput(attrs={'placeholder' : "Your email..."}))
message_field = forms.CharField(label="", 
    widget=forms.Textarea(attrs={'placeholder': "Say it like you mean it"}))

home.html

<form method="post" id="contact_form">
            {% csrf_token %}
            {% for field in contact_form %}
                    <div class="field_wrapper">
                        {{ field.errors }}
                    </div>
            {% endfor %}
            {{ contact_form }}
            <input type="submit" id="contact_submit" value="Send">
        </form>

settings.py

EMAIL_HOST = "smtp.gmail.com"
EMAIL_HOST_USER = "doorstepstudios@gmail.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_PASSWORD = '[password]'

The indentation in the code segment of the views.py is strange. Could you make it exactly like your code because there may be some insight there.

Sorry, I was fiddling with additional spaces to make it show up as a code block in the forum. It's now indented exactly as it is in my code.

HTTP 405 usually results from using class-based views and not defining a method within the view for the relevant HTTP method; clearly that's not the problem here.

Could you post your urls.py for us, just as a sanity check?

Sure, here you go:

urlpatterns = patterns('',

    url(r'^admin/', include(admin.site.urls)),
    url(r'^$', 'studio_site.views.home_page', name='home'),
    url(r'^start/$', 'studio_site.views.start', name='start'),
    url(r'^contact$', 'studio_site.views.contact', name='contact'),
    url(r'^launched$', 'studio_site.views.launched', name='launched')
)

I don't think it's your code. I think it's your static file mappings. You have a mapping for /, which is probably getting in the way of the post request.

Got it. That mapping was put in by someone at PA - I think Harry - because there was a bug causing 404 requests to spike the memory usage, and that was a temporary workaround until the bug could be figured out. Can I safely remove it?

Ah. Yes that makes sense. We'd like to see if we can debug your web app to work out what's going on with the 404s. We don't want to do that on the live cluster, so we'd like your permission to take your code and setup and try to put it on one of our development environments so we can try to debug it there.

Hi Glenn, sure, go for it. Let me know if you need anything else on my end. Is there a way to get the POST requests on the live site up and running in the meantime?

Maybe, but I'm reluctant to try it because, while it will fix the post on the home page, it's also just as likely to make your site fail horribly and unpredictably. I know it's not a great solution, but I think your best bet at the moment is to comment out the form on the home page until we understand what's causing the original 404 problem. I'll be starting on that in a few minutes and I'll keep you informed.

Ok, sounds good. Thanks for working on it.

Mystery solved!

It looks like this line:

'root': {'level': 'INFO'},

in your settings is setting up some kind of recursive logging. That means it gets an error, tries to log it, which generates an error that it tries to log etc. Take that line out and you can then remove the "/" static files mapping without endangering your entire application.

Awesome, thanks! Looks like that did the trick.

And just to confirm one of the original questions, is it still true that PA doesn't have mail servers, so I should be using Google's SMTP servers to send mail?

Excellent!

And to answer your other question: we don't run a mail server, so using Google's or your own is necessary.