How can I send a message to all posts in Django Allauth? - python

I am trying to send an email to all registered users in Django Allauth, but when I try to get a list of all users' emails and send it via the send_mail() method, I get an error :
too many values to unpack (expected 2)
When I manually specify the mail in the recipient_list list, then everything works. But I need it to be automatically sent to the emails of all users.
Tried to do through :
def email(request):
cleaned_data = super().clean()
title = cleaned_data.get('articles_title')
message = cleaned_data.get('articles_text')
recipient_list = User.objects.get('email')
email_from = 'mymail'
send_mail(title, message[:50], email_from, recipient_list)
return title, message
or iterate through the for loop:
def email(request):
cleaned_data = super().clean()
title = cleaned_data.get('articles_title')
message = cleaned_data.get('articles_text')
mails = User.objects.get('email')
recipient_list = []
for i in mails:
recipient_list.append(i)
email_from = 'mymail'
send_mail(title, message[:50], email_from, recipient_list)
return title, message
But nothing helps, does someone know some alternative method?

Related

How to exclude 'queryset' characters when using django sqlite orm

I want to send mail to many users using django sendmail.
I am using orm in sqlite3 to get the list of recipients stored in db.
However, the orm result includes 'queryset', so mail cannot be sent
Is there a way to exclude 'queryset' from orm results?
as-is
I want
views.py
def send_form(request):
if request.method == 'POST':
selected_target = request.POST['target']
target = contact.objects.filter(target=selected_target).values_list('email')
return render(request, 'view/send_form.html', {'target': target})
def send_success(request):
if request.method == 'POST':
subject = request.POST['subject']
recipient = request.POST['email']
message = request.POST['message']
send_mail(
subject,
message,
recipient,
[recipient],
fail_silently=False,
)
return render(request, 'view/send_success.html')
send result
Queryset returns to you all (many) of applicable results, if you want only one email, instead of filter use get,
target_email = contact.objects.get(target=selected_target).email
but with queryset (many emails) you can send to each email in a list of queryset
target_emails = contact.objects.filter(target=selected_target)
for each_email in target_emails:
target_email = each_email.email
#this will output your needed email
print(target_email)
#and later do logic with target_email to send mail on it

How to Link Sengrid to a Contact Form in Flask to Forward Email

I am writing a web application and am trying to use sendgrid to handle email delivery services.
I am writing the application in Flask.
Right now I have a contact form, and my problem is that the email only gets delivered if I send the e-mail from my pre-approved e-mail address with sendgrid. Obviously this is not good since everyone else who fills out the e-mail form will not have it go through.
Here's the code that I have:
ROUTE
app.config['MAIL_SERVER'] = 'smtp.sendgrid.net'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = 'apikey'
app.config['MAIL_PASSWORD'] = os.environ.get('SENDGRID_API_KEY')
app.config['MAIL_DEFAULT_SENDER'] = os.environ.get('MAIL_DEFAULT_SENDER')
#app.route('/contact', methods=['GET', 'POST'])
def contactpage():
if request.method == 'POST':
print("Message sent")
print(request.form.to_dict())
m = message(request.form.to_dict())
m.send()
title = "Jonathan Bechtel contact form"
description = "Contact Jonathan Bechtel with questions about teaching or working with him"
return render_template("contact.html",
title=title,
description=description)
Here's my code for actually sending the e-mail:
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
class message():
def __init__(self, message_data):
for key in message_data:
print(key, message_data[key])
setattr(self, key, message_data[key])
def send(self):
message = Mail(
from_email = self.email,
to_emails = 'jonathanbechtel#gmail.com',
subject = 'Sample Email Message',
html_content = f'<strong>From: {self.email}</strong><br><strong>Reason: {self.reason}</strong><br><strong>Message:</strong>{self.message}')
try:
sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sg.send(message)
except Exception as e:
print(e)
If I set the from address in my contact form to my own the e-mail works fine. However, if I use any other one the message does not go through and generates a 403 status code.
I think this means that I'm just not using the correct part of the API but am not sure where to start.
Thank you.
Twilio SendGrid developer evangelist here.
SendGrid does not allow you to send emails from just any email address. I can see that in this case you are just trying to create a contact form that only sends emails to your email address so being able to send from any email address might be useful. But consider a form that allowed users to set the to and the from address and you can see how that might get abused.
You can read more about sender identity and SendGrid here.
In the meantime, for your use-case here is what I would suggest.
Set the from email to your pre-approved email address, include the user's email address in the body of the email, as you are doing already. Then add the user's email as a reply-to email as well, that way you can respond to the email and it will be sent straight to the user.
I believe you can set the reply-to with the mail object's reply_to method:
def send(self):
message = Mail(
from_email = APPROVED_SENDGRID_EMAIL,
to_emails = 'jonathanbechtel#gmail.com',
subject = 'Sample Email Message',
html_content = f'<strong>From: {self.email}</strong><br><strong>Reason: {self.reason}</strong><br><strong>Message:</strong>{self.message}')
# Set the reply-to email
message.reply_to(self.email)
try:
sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sg.send(message)
except Exception as e:
print(e)
See the examples in the helper library for more detail.

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

Django EmailMultiAlternatives sending to multiple "to" addresses

Is there a way in Django EmailMultiAlternatives that you can send to multiple "to" addresses, without having to send it again?
Have tried separating the email int the tuple by commas, but only the first recipient receives the emails.
A list of email addresses should work, as the example in the Django docs shows.
to_emails = ['alice#example.com', 'bob#example.com']
msg = EmailMultiAlternatives(subject, text_content, from_email, to_emails)
You might want to use bcc instead of to_emails to prevent users from seeing the other recipients of the email.
msg = EmailMultiAlternatives(subject, text_content, from_email, bcc=to_emails)
I'm using a for loop. I'm also using this to filter which users emails are sent to.
for user in users:
if user.is_active and user != request.user and user.last_login != None:
message = EmailMultiAlternatives(
subject = "your subject here",
from_email = settings.EMAIL_HOST_USER,
to = [user.email],
)
context = {'request':request, 'user':user, 'event':event}
html_template = get_template("notifications/new_event_email.html").render(context)
message.attach_alternative(html_template, "text/html")
message.send()
It might not be the best way, but it's working for me.

Error: SMTPRecipientsRefused 553, '5.7.1 #while working on contact form in django

im trying to make a contact form in django 1.3, python 2.6.
Whats the reason of following error?
error:
SMTPRecipientsRefused at /contact/
{'test#test.megiteam.pl': (553, '5.7.1 <randomacc#hotmail.com>: Sender address
rejected: not owned by user test#test.megiteam.pl')}
my settings.py:
EMAIL_HOST = 'test.megiteam.pl'
EMAIL_HOST_USER = 'test#test.megiteam.pl'
EMAIL_HOST_PASSWORD = '###'
DEFAULT_FROM_EMAIL = 'test#test.megiteam.pl'
SERVER_EMAIL = 'test#test.megiteam.pl'
EMAIL_USE_TLS = True
edit: If any1 else was following djangobook, this is the part causing it:
send_mail(
request.POST['subject'],
request.POST['message'],
request.POST.get('email', 'noreply#example.com'), #get rid of 'email'
['siteowner#example.com'],
The explanation is in the error message. Your email host is rejecting the email because of the sender address randomacc#hotmail.com that you have taken from the contact form.
Instead, you should use your own email address as the sender address. You can use the reply_to option so that replies go to your user.
email = EmailMessage(
'Subject',
'Body goes here',
'test#test.megiteam.pl',
['to#example.com',],
reply_to='randomacc#hotmail.com',
)
email.send()
On Django 1.7 and earlier, there isn't a reply_to argument, but you can manually set a Reply-To header:
email = EmailMessage(
'Subject',
'Body goes here',
'test#test.megiteam.pl',
['to#example.com',],
headers = {'Reply-To': 'randomacc#hotmail.com'},
)
email.send()
Edit:
In the comments you asked how to include the sender's address in the message body. The message and from_email are just strings, so you can combine them however you want before you send the email.
Note that you shouldn't get the from_email argument from your cleaned_data. You know that the from_address should be test#test.megiteam.pl, so use that, or maybe import DEFAULT_FROM_EMAIL from your settings.
Note that if you create a message using EmailMessage as in my example above, and set the reply to header, then your email client should do the right thing when you hit the reply button. The example below uses send_mail to keep it similar to the code you linked to.
from django.conf import settings
...
if form.is_valid():
cd = form.cleaned_data
message = cd['message']
# construct the message body from the form's cleaned data
body = """\
from: %s
message: %s""" % (cd['email'], cd['message'])
send_mail(
cd['subject'],
body,
settings.DEFAULT_FROM_EMAIL, # use your email address, not the one from the form
['test#test.megiteam.pl'],
)

Categories