Django-templated-email does not send email - django

I am using the following package https://github.com/vintasoftware/django-templated-email in a Django app to try and send an email. I am running it inside a django management command.
When I run the command the email part outputs to the console but no email is actually sent out. The SMTP settings and such are correct as emails work fine for other areas of the application.
from templated_email import send_templated_mail
send_templated_mail(
template_name='welcome',
from_email='from#example.com',
recipient_list=['to#example.com'],
context={
'username':"test",
'full_name':"test",
'signup_date':"test"
},
)
Any help is appreciated. I suspect I have misunderstood the syntax of the package.

Signup_date must be date and username and full_name must use single quote

Related

Unsure of how to manage email configurations

I am attempting to create Reset Password functionality using Djoser. I am successfully hitting my API's auth/users/reset_password/ endpoint, which is then sending an email as expected. But the problem is occurring in the content of the email. It is sending a redirection link to my api, rather than to my frontend.
Please note, any <> is simply hiding a variable and is not actually displayed like that
Here is an example of what the email looks like:
You're receiving this email because you requested a password reset for your user account at <api>.
Please go to the following page and choose a new password: <api>/reset-password/confirm/<uid>/<token>
Your username, in case you've forgotten: <username>
Thanks for using our site!
The <api> team
The goal with this email is to send the user to the /reset-password/confirm/ url on my frontend, not on my api, which is currently occurring.
Here are my DJOSER settings:
DJOSER = {
'DOMAIN': '<frontend>',
'SITE_NAME': '<site-name>',
'PASSWORD_RESET_CONFIRM_URL': 'reset-password/confirm/{uid}/{token}',
}
The expected behavior is for the DOMAIN setting to alter the link that is being placed in the email, but it is not. I can't seem to find reference to this particular problem within the docs.
Any help here would be greatly appreciated, thanks.
I figured it out:
Due to Djoser extending the package django-templated-mail, the variables DOMAIN and SITE_NAME have to override django-templated-mail setting rather than Djoser's setting. So, you have to pull variables specific to django-templated-mail out of the Djoser variable.
The working setup actually looks like:
DOMAIN = '<frontend>',
SITE_NAME = '<site-name>',
DJOSER = {
'PASSWORD_RESET_CONFIRM_URL': 'reset-password/confirm/{uid}/{token}',
}

does django send_mail() support custom 'from'?

my django app is sending emails (via SendGrid API) using django.core.mail's send_mail
send_mail(
subject='foo',
message=message,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[user.email],
fail_silently=False,
html_message=rendered)
the emails send fine but since it's sending from hi#myapp.com the email "From" alias in inboxes just shows up as "hi", and I'd like to make it more verbose so my recipients know who sent them the email ("Hi from AppName"). I don't see any field in send_mail docs (https://docs.djangoproject.com/en/2.1/topics/email/) for customizing how the "From" sender alias string appears (beyond the email itself) other than 'The “From:” header of the email will be the value of the SERVER_EMAIL setting'. does django's send_mail not support this (i.e., I need to rewrite this to using a sendgrid lib? https://github.com/sendgrid/sendgrid-python?) or is there a config setting in SendGrid where I can automatically set 'fromname'? thanks
Is that
Your example includes from_email=settings.DEFAULT_FROM_EMAIL. The docs say that the more verbose form is permitted, for example:
from_email="Hi from Appname <hi#myapp.com>",
You might also be able to change DEFAULT_FROM_EMAIL to the more verbose form. However the docs don't say whether this is supported or not, so I'm not sure whether this would cause problems somewhere.

Integration Testing Django All-Auth Email Confirmation

I'd like to do some integration testing and I'm stuck on how I should test the email confirmation bit of the sign up process.
My user story is (basically) that a new visitor comes to the site, decides that they want to sign up, confirm their email address and then get redirected to their shiny new profile.
How would I simulate clicking on the link in the email to get redirected to the user profile?
I'm currently using Selenium to conduct my functional/integration testing and to a certain extent the django test suite.
These two documentation pages have everything you need:
https://docs.djangoproject.com/en/1.10/topics/testing/overview/
https://docs.djangoproject.com/en/1.10/topics/testing/tools/#email-services
A simple example:
from django.test import TestCase
from django.core import mail
class EmailTestCase(TestCase):
def setUp(self):
## Do something
pass
def test_email_content(self):
## Do something that triggers an email.
## Check the number of emails.
print(len(mail.outbox))
## Check the content of the first email.
first_email = mail.outbox[0]
if first_email:
print(first_email.body)
You should look up a python way to read emails.
Steps:
Find the email
Store the link
Start up your selenium test, and open up said link
Validate that you are on the page

Testing Django email backend

In my settings.py, I put:
EMAIL_BACKEND = 'mailer.backend.DbBackend'
So even when importing from from django.core.mail import send_mail, the send_mail function still queues up the email in the database instead of sending it immediately.
It works just fine when actually running the website, but when testing the website, and accessing some webpages that trigger emails, emails are no longer queued anymore:
def test_something(self):
...
# Check no emails are actually sent yet
self.assertEquals(len(mail.outbox), 0) # test fails here -- 2 != 0
# Check queued emails.
messages = Message.objects.all()
self.assertEquals(messages.count(), 2) # test would also fail here -- 0 != 2
...
How come it doesn't seem to be using the backend when it is testing? (importing send_mail from mailer itself gets the tests to pass, but I can't really change the imports of other mailing apps like django-templated-email)
According to this question django overrides the setting.EMAIL_BACKEND when testing to 'django.core.mail.backends.locmem.EmailBackend'. It's also in the django docs here.
To properly test email with django-mailer, you need to override two settings:
Make the tests to use the django-mailer backend
Make the djano-mailer backend to use the test backend
If you don't set the django-mailer backend (number 2), your tests will try to send the email for real.
You also need to simulate running django-mailer's send_mail management command so that you can check mail.outbox for the correct email.
Here's an example of how to setup a test method:
from mailer.engine import send_all
#override_settings(EMAIL_BACKEND='mailer.backend.DbBackend')
#override_settings(MAILER_EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')
def test_email(self):
# Code that generates email goes here.
send_all() # Simulates running django-mailer's send_mail management command.
# Code to check the email in mail.outbox goes here.
This strategy makes your tests specific to django-mailer which you don't always want or need. I personally only use this setup when I'm testing specific functionality enabled by django-mailer. Otherwise, I use the default test email backend setup by django.
If you really want have sending of emails (like default) via SMTP in django tests use the decorator:
from django.test.utils import override_settings
#override_settings(EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend')
class TestEmailVerification(TestCase):
...
Try the following:
django.core.mail.backends.console.EmailBackend

Sending email not working on heroku

I have this function in forms.py. There is currently no email specifications in my settings.py.
def send_email(FROM_NAME,FROM,TO,SUB,MSG,EXISTING_EMAIL,EXISTING_PASSWORD):
FROMADDR = "%s <%s>" % (FROM_NAME, FROM)
LOGIN = EXISTING_EMAIL
PASSWORD = EXISTING_PASSWORD
TOADDRS = [TO]
SUBJECT = SUB
msg = ("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n" % (FROMADDR, ", ".join(TOADDRS), SUBJECT) )
msg += MSG+"\r\n"
server = smtplib.SMTP('smtp.gmail.com', 587)
server.set_debuglevel(1)
server.ehlo()
server.starttls()
server.login(LOGIN, PASSWORD)
server.sendmail(FROMADDR, TOADDRS, msg)
server.quit()
I call it my views.py like so
send_email('my_name','from_me#gmail.com','to_som1#gmail.com','my subject','mymessage','my_existing_email#gmail.com','password_to_existing_email')
This works locally. I have tested it with yahoomail and gmail. But when I upload to heroku it gives the error "(535, '5.7.1 Please log in with your web browser and then try again. Learn more at\n5.7.1 support.google.com/mail/bin/answer.py?answer=78754 et6sm2577249qab.8')"
Can anyone help?
You want to use this:
FROMADDR = "%s <%s>" % (your_name, your_email)
You shouldn't be building emails with string interpolation, that's a good way to get your site used to send spam via header injections. See my answer here for details on how to construct emails securely.
Generally speaking, when formatting from addresses, you should use the format Display Name <email#example.com>. See RFC 5322 for details.
Have you read the page linked to in the error message?
If you're repeatedly prompted for your username and password, or if
you're getting an 'invalid credentials' or 'web login required' error,
make sure your password is correct. Keep in mind that password are
case-sensitive.
If you’re sure your password is correct, sign in to your account from
the web version of Gmail instead at http://mail.google.com
In most cases signing in from the web should resolve the issue
Here is what worked for me. After getting the error Please log in with your web browser and then try again. Learn more etc. when trying to send email from my web application, I logged in to the email via browser from my local computer.
After I logged in, there was a yellow notification bar on top which asking me if I want to allow external application access my mail. I confirmed this and Google asked me to log in to the account from the application within the next 10 mins. This will white-list the application.