Sending email with html in Django 1.7 - python

In send_mail() we have one new parameter - html_message. Docs
I have email.html file and I want to send html version of my message. I can't find any example for Django 1.7.
Can you show me a way, how to do this? Does I need to use os.open() my html file?
Thanks!

render_to_string : which loads a template, renders it and returns the resulting string.
html_message : If html_message is provided, the default message replaced with Html message.
mail/html-message.html
Hi {{ first_name }}.
This is your {{ email }}
Thank you
views.py
def mail_function(request):
subject = 'Test Mail'
from = 'info#domain.com'
to = 'to#domain.com'
c = Context({'email': email,
'first_name': first_name})
html_content = render_to_string('mail/html-message.html', c)
txtmes = render_to_string('mail/text-message.html', c)
send_mail(subject,
txtmes,
from,
[to],
fail_silently=False,
html_message=html_content)

Tim,
You don't need OS.open. You can do this by creating an html template first, and importing it using the get_template method. In your
view, add something along the lines of :
app/view.py
from django.core.mail import EmailMultiAlternatives
from django.http import HttpResponse
from django.template.loader import get_template
def send_mail(request):
text = get_template('email_template.txt')
html = get_template('email_template.html')
data = {'templating variable': data_var}
# If Client cant receive html mails, it will receive the text
# only version.
# Render the template with the data
content_txt = text.render(data)
content_html = html.render(data)
# Send mail
msg = EmailMultiAlternatives(subject, content_text, from_email, [to])
msg.attach_alternative(content_html, "text/html")
msg.send()
Note: You don't need Context for Djange 1.10+. In Django 1.8+, the template's render method takes a dictionary for the context parameter. Support for passing a Context instance is deprecated, and gives an error in Django 1.10+.

Related

Django how to send html-designed email bodies

On my Django project I am trying to send beautiful mails with colorful body and so on. My mail body constructing function looks like the following:
def construct_mail_body():
user = User.objects.get(id=1)
context = {
'username': user.username,
}
template = render_to_string('mail/mail_body.html', context=context)
message = strip_tags(template)
return message
mail_body.html:
{% load static %}
<h3>Hello <span style="color: red;">{{ username }}</span>,</h3>
<h3>You've successfully completed our Tutorial!></h3>
<h3>Congratulations!</h3>
But it doesn't work as expected. My mail bodies looks like:
Body 1:
Body 2 (Btw, why this happens? Why the mail is in purple?):
So how to make HTML tags work properly and is it possible to add some styling properties of css?
Thanks!
Solved:
I found a way how to do that:
from django.core.mail import EmailMessage
mail = EmailMessage(
subject,
body,
settings.EMAIL_HOST_USER,
[email],
)
mail.fail_silently = False
mail.content_subtype = 'html'
mail.send()
This way it works properly.
This is possible, but stick to hex colours, e.g. #ff0000, instead of a named colour.
Text can all go purple, as Willem commented, when something is repeated, or for replies. If you change the subject line when testing, it won't group them, and so it won't do this.
Keep using inline CSS, but stick to HTML4 and CSS2 (higher can be achieved but as a progressive enhancement for some email clients only).

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

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']

Request Approvals by E-mail and process it Python + Django

Maybe I am not asking the right question in the search area, but I can't find an answer for this. I am pretty sure that many people have this use case, but as a beginner in Django + Python, I need to ask it.
I have user that fills up a form and the data is stored in the database. Basically this form asks for an access to a Database and after the form is submitted I want my program to send an email to the user's manager and to the DBA to APPROVE or DENY it. Very simple, right?
My idea is that in this e-mail I send two URL's, one for approving and one for denying the request. When the URL the is clicked I send a response to the server with an update in the manager_approval field.
Has anyone implemented this solution, or could point me to something that could help me?
I am doing everything using Django + Python.
Regards,
Marcos Freccia
Basically this technique used in email verification. This is where you should look into.
Let's say you have model, named request, which has field like username to identify the person who requested access, database name, well, everything. But it will also have two "password-like" fields which will be used to determine if request was declined or not.
class Request(models.Model):
user = models.ForeignKey ...
databasename =
date =
...
access_granted = models.BooleanField(default=False)
deny_token = models.CharField()
allow_token = models.CharField()
The point is to generate those tokens on saving request in the View:
if request.method == POST:
form = RequestForm(request.POST)
if form.is_valid():
data['user'] = form.cleaned_data['user'])
data['databasename'] = form.cleaned_data['databasename'])
...
data['access_token'] = GENERATE_USING_HASH_FUNCTION()
data['deny_token'] = GENERATE_USING_HASH_FUNCTION()
form.save(data)
Then you can use module EmailMultiAlternatives to send html email like so:
subject, from_email, to = 'Request', 'admin#example.com', form.cleaned_data['manager_email']
html_content = render_to_string(HTML_TEMPLATE, CONTEXT) # Just as any regular templates
text_content = strip_tags(html_content)
msg = EmailMultiAlternatives(subject, text_content, from_email, [to], reply_to=["admin#example.com"])
msg.attach_alternative(html_content, "text/html")
msg.send()
And inside that template you construct reverse url:
{% url 'app:grant_access' allow_token=token %} # "token" you get from context
{% url 'app:deny_access' deny_token=token %} # will become example.com/deny_access/7ea3c95, where 7ea3c95 is token
Then add lines to urls.py of your app like that:
url(r'^allow_access/(?P<allow_token>[0-9]+)$', CheckAcessView.as_view(), name="app:grant_access"),
url(r'^deny_access/(?P<deny_token>[0-9]+)$', CheckAcessView.as_view(), name="app:deny_access"),]
Then create CheckAcessView view. Where you access request stored in your database and check if, for example, parameter of url "allow_token" is equal stored allow_token. If so, change request status to allowed.

How to send two variables with html as a JSON in Django?

I want to render two different HTML samples and send it back as response to ajax request.
I have something like this in my view:
def getClasses(request):
User = request.user
aircomcode = request.POST.get('aircompany_choice', False)
working_row = Pr_Aircompany.objects.get(user=User, aircomcode=aircomcode)
economy_classes = working_row.economy_class
business_classes = working_row.business_class
economy = render_to_response('dbmanager/classes.html', {"classes": economy_classes}, content_type="text/html")
business = render_to_response('dbmanager/classes.html', {"classes": business_classes}, content_type="text/html")
return JsonResponse({"economy": economy,
"business": business})
With this I get the error:
django.http.response.HttpResponse object at 0x7f501dc56588 is not JSON serializable"
How can I do my task?
In js when I get the response I would like to insert received HTML into corespoding blocks. Like this:
$.ajax({ # ajax-sending user's data to get user's classes
url: url,
type: 'post',
data: {"aircompany_choice": aircompany_choice}, # send selected aircompanies for which to retrieving classes required
headers: {"X-CSRFToken":csrftoken}, # prevent CSRF attack
}).done (result) ->
add_booking_classes.find(".economy-classes").children(":nth-child(2)").html(result["economy"])
add_booking_classes.find(".business-classes").children(":nth-child(2)").html(result["business"])
Try Django's render_to_string :
economy = render_to_string('dbmanager/classes.html', {"classes": economy_classes})
business = render_to_string('dbmanager/classes.html', {"classes": business_classes})
render_to_string() loads a template, renders it and then returns the resulting string. You can then send these resulting strings as JSON.
Your final code now becomes:
from django.template.loader import render_to_string
def getClasses(request):
User = request.user
aircomcode = request.POST.get('aircompany_choice', False)
working_row = Pr_Aircompany.objects.get(user=User, aircomcode=aircomcode)
economy_classes = working_row.economy_class
business_classes = working_row.business_class
economy = render_to_string('dbmanager/classes.html', {"classes": economy_classes})
business = render_to_string('dbmanager/classes.html', {"classes": business_classes})
return JsonResponse({"economy": economy,
"business": business})
render_to_response is, as the name implies, for rendering a response. You don't want to do that; you want to render two templates, and put them into a JSON response. So use render_to_string.
You can send one in your context and one as where you want to render.

How to send context_instance and some message with HttpResponseRedirect in django?

I am uploading files to the server and want return to the view render_upload_content with some message like Files uploaded successfully.
This is my code:
#(r'^cmanager/upload$', 'mypublisher.views.render_upload_content'),
def render_upload_content(request):
'''render template'''
return render_to_response('cmanager_upload.html',{}, context_instance=RequestContext(request))
#(r'^cmanager/upload/save$', 'mypublisher.views.save_content'),
def save_content(request):
'''save form data with files'''
cmanager = ContentManager()
message = cmanager.handle_uploaded_file(request)
#Now I'm using "render_to_response" to display message on same template
return render_to_response('cmanager_upload.html',{"message": message}, context_instance=RequestContext(request))
How can I send the message as well as context_instance=RequestContext(request) to the template using HttpresponseRedirect.
Thank you in advance!
You can't, because it doesn't make sense: HttpResponseRedirect is exactly what the name implies: a redirection to another URL.
You can use the messages framework to pass messages between requests, or at a lower level explicitly store your information in the session.

Categories