How to send a file from Django to Gmail? - django

There is a feedback form in which the user can write a text message and attach the file.
This form is sent to managers by mail (gmail, for example).
Is there any way to make this file come to mail in its normal form (in a preview, for example) so that you can immediately see or download it?
For now, I'm just sending a file link in the message.

Thanks for help #dirkgroten
def send_contact_us_notification(file, name: str, email: str, body: str, phone='', nda=False):
try:
file = settings.MEDIA_URL[1:] + str(contact_form.file)
from django.core.mail import EmailMessage
msg = EmailMessage('Subject of the Email', 'Body of the email', 'dinamo.mutu111#gmailcom', ['dimaonlyvit#gmail.com'])
msg.attach_file(file)
msg.send()
except Exception as e:
print(e)

Related

Django send bulk emails

I am working on a service to send bulk emails in django.
I have this method which is working well with celery
#shared_task(bind=True)
def send_mails(self,saved_id):
text = BroadCast.objects.get(id=saved_id)
attendees = EventAttendee.objects.filter(event__id=text.id)
message = text.body
subject = text.subject
document = text.attachment
recipient_list=[]
for attend in attendees:
text_content = render_to_string(template_text, {'name': attend.client_name, 'message':message})
html_content = render_to_string(template_html, {'name': attend.client_name,'message':message})
mail.send(
[attend.client_email],
email_from,
subject=subject,
html_message=html_content,
attachments = {str(document):document}
)
my challenge is that if i have for examples 1000 attendees, I will have to open 1000 connections which I believe is a very bad.
How can I restructure it so that I only open one connection and be able to send 1000 emails..
From Django's docs
django.core.mail.send_mass_mail() is intended to handle mass emailing.
Since you are sending html, you would need an extra step, consider the following piece of code from this stackoverflow answer:
from django.core.mail import get_connection, EmailMultiAlternatives
def send_mass_html_mail(datatuple, fail_silently=False, user=None, password=None,
connection=None):
"""
Given a datatuple of (subject, text_content, html_content, from_email,
recipient_list), sends each message to each recipient list. Returns the
number of emails sent.
If from_email is None, the DEFAULT_FROM_EMAIL setting is used.
If auth_user and auth_password are set, they're used to log in.
If auth_user is None, the EMAIL_HOST_USER setting is used.
If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.
"""
connection = connection or get_connection(
username=user, password=password, fail_silently=fail_silently)
messages = []
for subject, text, html, from_email, recipient in datatuple:
message = EmailMultiAlternatives(subject, text, from_email, recipient)
message.attach_alternative(html, 'text/html')
messages.append(message)
return connection.send_messages(messages)
Then you probably want to use send_mass_mail
only one connection to the mail server would be opened
So construct a tuple of messages for all the emails you want to send. (The linked official documentation does a good job explaining usage)

How to send an email with bold string using Django

My Django app sends an email as follows:
mail_subject='Hi'
to_email='xyz#gmail.com'
message=render_to_string('app1/xyz.html',{
'user':User1,'var1':'BLUE'})
email = EmailMessage(mail_subject, message, to=[to_email])
email.send();
xyz.html looks like below:
I would like for the following string to be bold
<strong>{{var1}}</strong>
but it just shows as <strong>BLUE</strong> in the email. I would like to see BLUE
from django.core.mail import send_mail
from django.template.loader import render_to_string
msg_html = render_to_string('templates/xyz.html', {'some_params': some_params})
send_mail(
'email title',
'Hi',
'sender#gmail.com',
['xyz#gmail.com'],
html_message=msg_html,
)
We can create any structure (bold/italic) in xyz.html and it will display nicely inside an email.

Sending EmailMultiAlternatives in mail_admins()

I have the below view code snippet and I would like to send email as EmailMultiAlternatives to the admins, the problem is...it doesn't render the html tags.
Kindly assist with some ideas.
subject = "A New Feedback"
ctx = {
'name': name,
'email': email,
'message': message
}
message = ('ecoke/includes/email_feedback.html', ctx)
mail_admins(subject, message, fail_silently=True, html_message='text/html')
mail_admins is a wrapper around send_mail.
In the send_mail documentation html_message is described as the HTML message to be attached to the email where as message is the plain text string.
From what you have above you will need to render (render_to_string) the message and attach it as HTML.
subject = "A New Feedback"
ctx = {
'name': name,
'email': email,
'message': message
}
html_message = render_to_string(
'ecoke/includes/email_feedback.html',
context=ctx
)
text_message = 'Hi %s, <plain text goes here>' % name
mail_admins(subject, text_message, fail_silently=True, html_message=html_message)
What happens is that you have two versions of the text; one for plain text one for HTML. As the HTML is not rendered by mail_admins you will need to render the template to HTML manually. The HTML message is attached as an alternative as illustrated here.

Django - Attach PDF generated by a view to an email

This question has some elements here, but no final answer.
There is view generating a PDF with easy_pdf
from easy_pdf.views import PDFTemplateResponseMixin
class PostPDFDetailView(PDFTemplateResponseMixin,DetailView):
model = models.Post
template_name = 'post/post_pdf.html'
Then, I want to attach this generated PDF to the following email :
#receiver(post_save, sender=Post)
def first_mail(sender, instance, **kwargs):
if kwargs['created']:
user_email = instance.client.email
subject, from_email, to = 'New account', 'contact#example.com', user_email
post_id = str(instance.id)
domain = Site.objects.get_current().domain
post_pdf = domain + '/post/' + post_id + '.pdf'
text_content = render_to_string('post/mail_post.txt')
html_content = render_to_string('post/mail_post.html')
# create the email, and attach the HTML version as well.
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.attach_file(post_pdf, 'application/pdf')
msg.send()
I also have tried this one:
msg.attach_file(domain + '/post/' + post_id + '.pdf', 'application/pdf')
I was looking for a way to attach an easy_pdf generated PDF without saving a temp file as well. Since I couldn't find a solution elsewhere, I suggest a short and working proposal using easy_pdf.rendering.render_to_pdf:
from easy_pdf.rendering import render_to_pdf
...
post_pdf = render_to_pdf(
'post/post_pdf.html',
{'any_context_item_to_pass_to_the_template': context_value,},
)
...
msg.attach('file.pdf', post_pdf, 'application/pdf')
I hope it'll help if you are still interested by a way to do this.
Not sure if it helps, but I used EmailMessage built-in to attach PDFs I created for reporting to emails I sent out:
from django.core.mail import send_mail, EmailMessage
draft_email = EmailMessage(
#subject,
#body,
#from_email,
#to_email,
)
Option 1:
# attach a file you have saved to the system... expects the path
draft_email.attach_file(report_pdf.name)
Option 2:
# expects the name of the file object
draft_email.attach("Report.pdf")
Then, sends like you already have:
draft_email.send()
Some initial thoughts: it seems like you are trying to use attach_file to attach a file from the system, but it isn't on the system. I would try using attach instead of attach_file, if I am reading your code correctly, since the pdf is in your memory, not in LTS on the system.

recipient_list send mail just to the first address in the list

I´m using signals to send mails to the users depending of some actions. In one of my signals I need to send the same mail to multiple users, my signal use post_save so for the parameter [recipient_list] I use this instance.email_list email_list is where I store the list of email addresses to send the mail, they are stored in this format user1#mail.com, user2#mail.com, user3#mail.com.
To send the emails I use EMAIL_HOST = 'smtp.gmail.com' the problem is that the only user who recive the email is the first one in the list. So I 'log in' in the gmail account to check the send emails section and actually in the "to" area of the email shows that was send to all the users in the list but the emails never arrive just for the first email address in the list.
I read that if google detect that the account sends a lot of messages could be blocked but only send like 5 emails at the same time and when I'm in the account never shows me some alert or something.
So the problem is how I send the emails or maybe some bad configuration of the gmail account?
Any help is really appreciated.
Sorry for my bad grammar.
EDIT: Here's my code.
forms.py
class MyForm(forms.Form):
userslist = forms.ModelChoiceField(queryset = User.objects.filter(here goes my condition to show the users), empty_label='List of users', label='Users', required=False)
emailaddress = forms.CharField(max_length=1000, label='Send to:', required=False)
comment = forms.CharField(widget=CKEditorUploadingWidget(), label="Comment:")
That form display a list of users to select the email address in the field emailaddress store the values. This is my Ajax to bring the email address:
views.py
class mails(TemplateView):
def get(self, request, *args, **kwargs):
id_user = request.GET['id']
us = User.objects.filter(id = id_user)
data = serializers.serialize('json', us, fields=('email'))
return HttpResponse(data, content_type='application/json')
And here's the <script> I use to populate the emailaddres field:
<script>
$('#id_userlist').on('change', concatenate);
function concatenate() {
var id = $(this).val();
$.ajax({
data: { 'id': id },
url: '/the_url_to_get_data/',
type: 'get',
success: function (data) {
var mail = ""
for (var i = 0; i < data.length; i++) {
mail += data[i].fields.email;
}
var orig = $('#id_emailaddress').val();
$('#id_emailaddress').val(orig + mail + ',');
}
})
}
</script>
The signal I use to send the mail is this:
#receiver(post_save, sender=ModelOfMyForm, dispatch_uid='mails_signal')
def mails_signal(sender, instance, **kwargs):
if kwargs.get('created', False):
if instance.emailaddress:
#Here goes the code for the subject, plane_message,
#from_email and template_message.
send_mail(subject, plane_message, from_email, [instance.emailaddress], fail_silently=False, html_message=template_message)
So if I select 4 users the info is save in this way in the database:
Then I 'log in' in the account to check the 'Sent Mail' section and check the detail of the mail and shows that was send to the 4 users but the only user who recibe the mail was the first in the list.
Your problem is that you are passing a comma-separated string of email addresses inside instance.emailaddress (first#gmail.com, second#hotmail.com, third#hotmail.com etc). Django expects a Python list of addresses, not a comma separated string. It will just ignore everything after the first comma.
Change your code as follows and it will work:
def mails_signal(sender, instance, **kwargs):
if kwargs.get('created', False):
if instance.emailaddress:
#Here goes the code for the subject, plane_message,
#from_email and template_message.
recipients = [r.strip() for r in instance.emailaddress.split(',')]
send_mail(subject, plane_message, from_email, recipients, fail_silently=False, html_message=template_message)