'in <string>' requires string as left operand, not BoundWidget sendgrid - python

I am working on a django web application. I have a contact us form. when a user submits the form, the message in the form is sent as a mail to a predefined email id.
For sending the email, I am using sendgrid. I created an account and generated an api for this purpose. I stored the api key in a dotenv file and access the api in the settings.py file
.env file
SENDGRID_API_KEY=XXXXXXXXXXXXXXXXXXXX
settings.py
import os
from dotenv import load_dotenv
load_dotenv()
...
EMAIL_BACKEND = "sendgrid_backend.SendgridBackend"
SENDGRID_API_KEY = os.environ.get("SENDGRID_API_KEY")
SENDGRID_SANDBOX_MODE_IN_DEBUG=False
views.py
def index(request):
if request.method == "POST":
ContactUsForm = ContactUs(request.POST)
if ContactUsForm.is_valid():
firstName = ContactUsForm['firstName']
fromEmail = ContactUsForm['email']
message = ContactUsForm['message']
send_mail(subject=f"{firstName} sent you a message", message=message, from_email=fromEmail, recipient_list=['toaddress#email.com'])
return redirect('home')
else:
ContactUsForm = ContactUs()
context = {'contactUs': ContactUsForm}
return render(request, 'index.html', context)
But when I submit the form, I get this error message
TypeError: 'in <string>' requires string as left operand, not BoundWidget
I dont know where I went wrong.
This is the link I followed to send emails with sendgrid

You're accessing the fields themselves, instead of the validated data. You need:
firstName = ContactUsForm.cleaned_data['firstName']
fromEmail = ContactUsForm.cleaned_data['email']
message = ContactUsForm.cleaned_data['message']

Related

Can i use the views.py file to actually send emails?

I am trying to create a contact form in Django that actually sends emails for real. Can i put all the email configs in the views.py file itself? I want to do that because i want only the legitimate owners of emails to actually send emails. I do not people to send me emails using their friends email.
Yes obviously you can, but make sure you have your email credentials stored in your settings.py file safely
What is ideal is to save your email credentials as environment variables
In your settings.py File
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = "from#example.com"
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# If you are using any other smtp host.
# Search documentation for other smtp host name and port number
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = "from#example.com"
EMAIL_HOST_PASSWORD = "SUPER_SECRET_PASSWORD"
In your view that you want to use to send email
views.py
from django.core.mail import EmailMessage
def email_send_view(request):
if request.method == "POST":
# Get email information via post request
to_email = request.POST.get("to", "")
subject = request.POST.get("subject", "")
message = request.POST.get("message", "")
if to_email and message:
email = EmailMessage(subject=subject,body=body,to=[to])
email.send()
# Complete your view
# ...
return redirect("REDIRECT_VIEW")
If you want to send html template or image using email Email Template via your django app
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from YourProject.settings import EMAIL_HOST_USER
def email_send_view(request):
if request.method == "POST":
# Get email information via post request
to_email = request.POST.get("to", "")
subject = request.POST.get("subject", "")
message = request.POST.get("message", "")
if to_email and message:
# Gets HTML from template
# Make sure in this case you have
# html template saved in your template directory
html_message = render_to_string('template.html',
{'context': 'Special Message'})
# Creates HTML Email
email = EmailMultiAlternatives(subject,
from_email=EMAIL_HOST_USER,
to=[to])
# Send Email
email.attach_alternative(html_message, "text/html")
email.send()
# Complete your view
# ...
return redirect("REDIRECT_VIEW")

How to send an email to currently logged in user Django

I am currently trying to set up a view so when the user visits the path /clip it will send an email to the user's inbox.
Eg. I visit path, email turns up in my inbox.
I am using this:
from django.core.mail import send_mail
def clippy(request):
current_user = request.user
subject = "test"
message = "testing"
recipient_list = [current_user.email]
send_mail(subject, message, recipient_list)
I'm using 3.0.4 and get this error when I visit the path:
send_mail() missing 1 required positional argument: 'recipient_list'
Can anyone help? Thanks
EDIT: I have used the answer by reza heydari and it fixes this issue, now I get the following:
TypeError at /clip/
send_mail() missing 1 required positional argument: 'from_email'
#login_required()
def clippyemail(request):
current_user = request.user
subject = 'Clippy here',
message = 'Hi! I am clippy! You resserected me somehow so thanks!',
recipient_list = [current_user.email, ]
send_mail(subject, message, recipient_list=recipient_list)
is there any way I can set it up so it just sends the email using the SMTP settings in settings.py?
The 3rd arg of send_mail is from_email based on docs
Change your code like that:
send_mail(subject, message, from_email="example#email.com", recipient_list=recipient_list)
And also add
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
For your local to recieve email in terminal

passing django object context to sendgrid email via sendgrid-python API lib

my django app has a view where accounts can send out newsletter emails to its contacts and subscribers using Sendgrid's API. sending is working with a plaintext email:
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import (Mail, Subject, To, ReplyTo, SendAt, Content, From, CustomArg, Header)
def compose_email(request, send_to, *args, **kwargs):
...
if request.method == 'POST':
subject = request.POST.get('subject')
from_name = request.POST.get('from_name')
body = request.POST.get('body')
reply_to = request.POST.get('reply_to')
test_address = [request.POST.get('test_address')]
# send test email
if request.POST.get('do_test'):
if form.is_valid():
message = AccountEmailMessage(account=account, subject=subject,
from_name=from_name, destination=destination, body=body, reply_to=reply_to,
is_draft=True, is_sent=False)
message.save()
email = Mail(
subject=subject,
from_email=hi#app.foo,
html_content=body,
to_emails=test_address,
)
email.reply_to = ReplyTo(reply_to)
try:
sendgrid_client = SendGridAPIClient(settings.SENDGRID_API_KEY)
response = sendgrid_client.send(email)
message.sendgrid_id = response.headers['X-Message-Id']
message.save()
except Exception as e:
log.error(e)
messages.success(request, 'Test message has been successfully sent')
else:
messages.error(request, 'Please, check for errors')
this works. but we want to render django object properties (model fields via template tags) in an html email template from Account (account) [assume it's just a vanilla obj req query account = Account.objects.get(id=selected_account) in the view], and I'm not clear what's the recommended docs approach.
the attempt:
if request.method == 'POST':
subject = request.POST.get('subject')
from_name = request.POST.get('from_name')
body = request.POST.get('body')
reply_to = request.POST.get('reply_to')
if request.POST.get('send'):
if form.is_valid():
message = AccountEmailMessage(account=account, subject=subject,
from_name=from_name, destination=destination, body=body, reply_to=reply_to,
is_draft=False, is_sent=True)
message.save()
rendered = render_to_string('email/newsletter.html', {
'account': account,
'protocol': settings.DEFAULT_PROTOCOL,
'domain': settings.DOMAIN,
'message_body': body
})
email = Mail(
subject=subject,
from_email=hi#app.foo,
html_content=rendered,
to_emails=recipients,
mime_type='text/html'
)
email.reply_to = ReplyTo(reply_to)
try:
sendgrid_client = SendGridAPIClient(settings.SENDGRID_API_KEY)
response = sendgrid_client.send(email)
message.sendgrid_id = response.headers['X-Message-Id']
message.save()
except Exception as e:
log.error(e)
but on submit, this throws an err: NoReverseMatch: Reverse for 'account' not found. 'account' is not a valid view function or pattern name when I try to pass account as a kwarg to the context and render it as a string.
looking at the docs (https://github.com/sendgrid/sendgrid-python#use-cases) I see Mail() has a .dynamic_template_data property. that's very inefficient to process a large number of fields from the same obj, as well as attributes like image urls, and also requires use of legacy transactional templates (https://sendgrid.com/docs/ui/sending-email/create-and-edit-legacy-transactional-templates/). I see Sendgrid has a Personalization obj (https://sendgrid.com/docs/for-developers/sending-email/personalizations/) - is that the recommended way to implement this?
thanks to Iain on further testing realized we had two issues:
was attempting to encode a url in the template via {% url %} tag, that threw the NoReverseMatch
mime_type='text/html' isn't a valid kwarg for Mail(), removed that as well.
after (1) and (2) everything's working properly, no need for personalization

In Django1.10, sending email functionality not working without any exception

I would like to send email in Django 1.10.
This is the snippet code in settings.py file.
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'my email address'
EMAIL_HOST_PASSWORD = 'password'
EMAIL_PORT = '587'
EMAIL_USE_TLS = True
This is the snippet code in views.py file which is responsible for sending email.
from django.shortcuts import render
from django.core.mail import send_mail
from django.conf import settings
from .forms import contactForm
def contact(request):
form = contactForm(request.POST or None)
if form.is_valid():
name = form.cleaned_data['name']
comment = form.cleaned_data['comment']
subject = 'Message form MYSITE.com'
message = '%s %s' %(comment, name)
emailFrom = form.cleaned_data['email']
emailTo = [settings.EMAIL_HOST_USER]
send_mail(subject, message, emailFrom, emailTo, fail_silently=True)
context = locals()
template = "contact.html"
return render(request,template,context)
When I clicked submit button, I only received Review blocked sign-in attempt - google email.
So I have set my email account as Allow less secure apps: OFF.
Then hit the submit button again, I haven't received any email without any exception. As if sending email functionality working - browser loading for a little while.
I'm not sure why I couldn't receive email.
When I change fail_silently = False, I get a error like this.
SMTPAuthenticationError at /contact/
(534, '5.7.14 https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbtS\n5.7.14 Mr_jh-DUic292PQTLx5X6kZmxxN8WFLelRksUwF0nHxSUPVpU_fX3m7ds3VOoUuTxL9Gya\n5.7.14 bqnAiUAIf2Er2n31EXEHIOpy2Kqn9cFH-PsIJSx1GBn_SxygkjHWgZ9KWc9cxIAKTGQtru\n5.7.14 O3QBqKb6vCyVHCiN8wUY6jAVRdoRg9aK9BL5GTo6QKUomIilah549hrwMgvMcYrrKCLMGI\n5.7.14 YuEWvMHHPdW6TXkBB75UP2wxRZ9fI> Please log in via your web browser and\n5.7.14 then try again.\n5.7.14 Learn more at\n5.7.14 https://support.google.com/mail/answer/78754 u2sm3991912edl.71 - gsmtp')
How can I handle it.

Django not sending email through gmail

I am trying to build a online book store and I am trying to send an verification email to new signed users, but for some reason Email is not getting sent, I also tried to use app specific password in gmail.
A help will be greatly appreciated.
Here is my Email code in settings.py
EMAIL_BACKEND = 'django_smtp_ssl.SSLEmailBackend'
EMAIL_HOST='smtp.gmail.com'
EMAIL_HOST_USER='kshitu.rangari#gmail.com'
EMAIL_HOST_PASSWORD='jgpcjiajvklxraof'
EMAIL_PORT=587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = 'books#pickabook.com'
Code in my Views.py
from .models import Book
def index (request):
return render (request,'template.html')
def store (request):
return render (request, 'store.html' )
def store (request):
count = Book.objects.all().count()
context = {
'count':count,
}
return render (request,'store.html',context)
As you already have the settings for email ready and to test whether emails are being sent, do the following
In settings.py make
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
Run interactive mode,
python manage.py shell
Import the EmailMessage module,
from django.core.mail import EmailMessage
Send the email,
email = EmailMessage('Subject', 'Body', to=['kshitu.rangari#gmail.com'])
email.send()
If the above works successfully then your gmail account is configured to send emails.
For Gmail specifically, you might need to toggle the "enable less secure apps" function within your Google account.
https://support.google.com/accounts/answer/6010255?hl=en

Categories