0

So I have been scouring the internet trying to get my code to work and i feel like I've read every post about this issue and still haven't figured out why I can't get my form to send me an email. I created a class based view which inherits FormView and have written a method that should send an email to me anytime there is a post-request. For the life of me, I can't get it to work.

For those who are in the same boat, this is one post that seemed promising so hopefully this will help you even if it doesn't help me:

Django sending email

My views.py: (both email addresses are the same. It should simulate me sending an email to myself.)

class CandRegisterView(FormView):
    template_name = 'website/candidate_register.html'
    form_class = UploadResumeForm
    def send_email(self, request):
        if request.method == 'POST':
            send_mail('Test', 'This is a test', 'myemail@gmail.com', ['myemail@gmail.com'], fail_silently=False)

my forms.py:

from django import forms

class UploadResumeForm(forms.Form):
    first_name = forms.CharField(
        widget=forms.TextInput(
            attrs={
            'type':'text',
            'class': 'form-control',
            'placeholder': 'First Name',
            }), 
        required=True)

my settings.py (the variables are stored in a .env file and I use python decouple to add them without exposing the information on github. But these are their associated values)

EMAIL_USE_TLS=True
EMAIL_USE_SSL=False
EMAIL_HOST=smtp.gmail.com
EMAIL_HOST_USER=myemail@gmail.com
EMAIL_HOST_PASSWORD=***************
EMAIL_PORT=587
EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend'
DEFAULT_FROM_EMAIL='myemail@gmail.com'
SERVER_EMAIL='myemail@gmail.com

urls.py:

from django.urls import path, re_path
from .views import CandRegisterView

re_path(r'^candidate-register/$', CandRegisterView.as_view(success_url="/candidate-register/"), name='cand_register'),

candidate_register.html:

<form method= "post" action="" accept-charset="UTF-8" role="form">
                {% csrf_token %}

                <fieldset>
                  <div class="form-group">
                    <div class="input-group input-group-lg">
                      <span class="input-group-addon"><i class="fa fa-fw fa-user"></i></span>
                      {{form.first_name}}
                      <!-- <input type="text"  class="form-control" placeholder="First Name" name={{form.first_name}}> -->
                    </div>
                  </div>
                  <input class="btn btn-lg btn-primary btn-block" type="submit" value="Send Email">
                </fieldset>
              </form>

Here is what i get from the console after clicking the 'submit' button.:

[10/Jul/2019 13:19:21] "POST /candidate-register/ HTTP/1.1" 302 0
[10/Jul/2019 13:19:22] "GET /candidate-register/ HTTP/1.1" 200 16782
[10/Jul/2019 13:19:22] "GET /candidate-register/ HTTP/1.1" 200 16782

All i want it to be able to do is send me the first name of the person for right now. later on i want them to be able to send me a file with their resume but i figured that I'd start off simple and make it more complex as include other fields but I can't even get this to work. Any help or tips would be greatly appreciated. It seems like the Post Request is happening but the email isn't being sent. I also tried using the send_mail function in the python manage.py shell and it showed a response that looked promising (the log showed what the email would have looked like.) but it didn't send an email to my account.

Tom H
  • 175
  • 3
  • 12
  • So I partially figured out the issue. I came across this Stack overflow answer and it had to do with setting up a mail application with its own secret password. https://stackoverflow.com/questions/6914687/django-sending-email – Tom H Jul 10 '19 at 18:18
  • That being said, I still don't understand why my code isn't firing off an email. I can do it from the shell but not from my code. – Tom H Jul 10 '19 at 18:19

1 Answers1

1

In your form class, you will want to define a send_mail function that can be called after form_valid. So for example:

from django.core.mail import EmailMessage as email_msg


class UploadResume(forms.Form):
    first_name = forms.CharField()
    last_name = forms.CharField()
    email = forms.EmailField()
    resume_file = forms.FileField()

    class Meta:
        title = 'Resume Upload'

    def send_message(self, email, first_name, last_name, file):
        '''
        This function will be used to create an email object that will then be \
transmitted via a connection call.  This function takes in arguments that will \
be provided by the corresponding CBV's form_valid function.
        '''
        email_obj = email_msg(
            subject=f'Resumed Uploaded by {first_name} {last_name}!',
            body = 'You received a resume upload from {first_name} {last_name} \
                    at {email}.  Please follow-up.  \nThank you,\nYour Platform'
            from_email=email,
            to=['myemail@gmail.com'],
            reply_to= ['myemail@gmail.com']
            )
        # after creating the email object with the cleaned data generated from
        # the form fields, we will attach the resume contents to the object,
        # then submit it via SMTP settings from the settings.py file.

        attach_name = file.name
        try:
            attach_content = file.open().read()
        except Exception:
            attach_content = file.getvalue()
        attach_mimetype = mimetypes.guess_type(attach_name)[0]
        email_obj.attach(attach_name, attach_content, attach_mimetype)
        try:
            email_obj.send()
        except Exception as e:
            print(type(e), e.args, e)

From here, you can overwrite the form_valid function in your CBV, pull the relevant arguments by using the form.cleaned_data.get(insert_arg_here) function.

An example of how to do this could be in the following way:

class CandRegisterView(FormView):
    template_name = 'website/candidate_register.html'
    form_class = UploadResumeForm

    def form_valid(self, form):
        if form.is_valid:
            email_addr = form.cleaned_data.get('email')
            first_name = form.cleaned_data.get('first_name')
            last_name = form.cleaned_data.get('last_name')
            file = form.cleaned_data.get('resume_file')
            form.send_message(email_addr, first_name, last_name, file)
        else:
            return form.errors

Just noticed this: when you're crafting your form tag in your HTML, ensure that enctype="multipart/form-data" is present in the tag.

  • This is great. It still doesn't work but this will definitely help clean up the emails that I receive. What exactly do you mean by 'overwrite the form_valid function"? – Tom H Jul 10 '19 at 21:47
  • I updated my answer to better answer that question. I think my example can basically be copied + pasted into your files. Essentially, the general FormView has a specific form validation function that gets executed when managing form data, and to achieve a specific function (such as sending email), then you are best advised to take the cleaned data that is generated after `form.is_valid()` gets called. – Francis Secada Jul 10 '19 at 23:14