I am trying to make EMAIL_HOST settings configurable within admin and I will create a model with required fields like:
EMAIL_HOST
EMAIL_HOST_USER
EMAIL_HOST_PASSWORD
EMAIL_PORT
But how can I use those fields in views using send_mail?
If you want to use send_mail, you'll have to create your own email backend which uses your custom settings and then pass it to send_mail in the connection attribute.
This works for me
from django.core.mail import EmailMessage
from django.core.mail.backends.smtp import EmailBackend
config = Configuration.objects.get(**lookup_kwargs)
try:
backend = EmailBackend(
host=config.host,
port=config.port,
password=config.password,
username=config.username,
use_tls=config.use_tls,
fail_silently=config.fail_silently
)
mail = EmailMessage(
subject="subject",
body="body",
from_email=config.username,
to=["email#gmail.com"],
connection=backend,
)
mail.send()
except Exception as err:
print(err)
Sending mail with a custom configured SMTP setting in the admin page which is independent of the Django setting:
from django.core import mail
from django.core.mail.backends.smtp import EmailBackend
from <'Your SMTP setting in admin'> import <'Your model'>
def send_mail(subject, contact_list, body):
try:
con = mail.get_connection()
con.open()
print('Django connected to the SMTP server')
mail_setting = <'Your model'>.objects.last()
host = mail_setting.host
host_user = mail_setting.host_user
host_pass = mail_setting.host_pass
host_port = mail_setting.host_port
mail_obj = EmailBackend(
host=host,
port=host_port,
password=host_pass,
username=host_user,
use_tls=True,
timeout=10)
msg = mail.EmailMessage(
subject=subject,
body=body,
from_email=host_user,
to=[contact_list],
connection=con)
mail_obj.send_messages([msg])
print('Message has been sent.')
mail_obj.close()
return True
except Exception as _error:
print('Error in sending mail >> {}'.format(_error))
return False
Related
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")
I am trying to send a password reset email to users, via an App we are developping with Django.
When trying the App locally, the user can select to reset a pwd if forgotten , input his email into a field and submit, in order to receive an email. The sender email is a business email address.
Checking into Sendgrid, I can see the activity log that the email has been processed and delivered. So it seems working.
However, when trying to do the same passing via Github, Azure, on https://XXXXXX.azurewebsites.net/en/password_reset/, I get the following :
SMTPSenderRefused at /en/password_reset/
(550, b'Unauthenticated senders not allowed', 'nicolas#XXXXX.com')
in the log I get the following as well:
raise SMTPSenderRefused(code, resp, from_addr)
Is there something I am missing with Azure, another key to include. I read through many similar issues, but could not find a suitable response to my problem. The fact Sendgrid works locally but not with Azure make me think I am missing a connection at that level. Otherwise, All other aspects of the App works when hosting it on Azure..
Below are the codes I am using:
in settings.py
import os
ALLOWED_HOSTS = ['XXXXXX.azurewebsites.net']
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
SENDGRID_API_KEY = os.getenv('SENDGRID_API_KEY')
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = 'apikey' #Exactly that
EMAIL_HOST_PASSWORD = SENDGRID_API_KEY
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = 'nicolas#XXXXX.com'
in views :
from django.core import mail
from django.template.loader import render_to_string
from django.utils.html import strip_tags
def send_password_reset_email(request):
subject = 'email reset'
html_message = render_to_string('password_reset_email.html', {'context': 'values'})
plain_message = strip_tags(html_message)
from_email = 'nicolas#XXXXX.com'
form = (request.POST)
if form.is_valid():
data = form.cleaned_data
to=data.get("email")
mail.send_mail(subject, plain_message, from_email, [to], html_message=html_message,fail_silently=False)
in url.py:
urlpatterns=[
url('', views.send_password_reset_email)
]
merci
Nicolas
This is solved: If SendGrid works locally, but not on Azure:
In Azure, select ‘configuration', 'Application settings', 'new application settings' and then, as per below, using the correct API name made it work.
In SendGrid, I had named my API key ‘test’, and thought in Azure I should name it the same. However, I should have named it the same as in my code:
SENDGRID_API_KEY
Not obvious at first.
I'm developing a Flask application that implements a user registration system. The application uses Flask-Mail and itsdangerous to confirm a user's registration and reset their password via email. I configured Flask-Mail to use the recommended server settings provided by the email host that I'm using.
MAIL_PORT = 587
MAIL_USE_SSL = False
MAIL_USE_TLS = True
At first, things were working fine; I could submit emails without any issues. However, seemingly without changing any configuration settings, I now receive the following error when attempting to submit an email using Flask-Mail:
[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)
I'm not sure where the problem is, and I am wondering if something has changed on the email provider's end? I have tried setting MAIL_PORT = 25 with MAIL_USE_SSL=False and MAIL_USE_TLS=False; and, MAIL_PORT = 465 with MAIL_USE_SSL=True and MAIL_USE_TLS=False as well. Using the former, I receive the same error as with port 587, but using the latter I'm receiving STARTTLS extension not supported by server.
I'm running the Flask app in development mode at localhost:5000. Here's some of my configuration settings and code:
config.py
SECRET_KEY = 'verysecret'
MAIL_SERVER = "smtp.mymailservice.com"
MAIL_PORT = 587
MAIL_USE_SSL = False
MAIL_USE_TLS = True
MAIL_USERNAME = "myemail#myhostname.com"
MAIL_PASSWORD = "mypassword"
MAIL_DEFAULT_SENDER = 'Brand <noreply#myhostname.com>'
app/mailing.py
from flask_mail import Message
from flask import current_app
from .extensions import mail
def send_email(to, subject, template):
msg = Message(
subject,
recipients=[to],
html=template,
sender=current_app.config["MAIL_DEFAULT_SENDER"]
)
mail.send(msg)
app/users/routes.py
(One of the routes where I receive the error)
from flask import (
render_template, session, request, redirect, url_for, g, jsonify, flash
)
import uuid
from passlib.hash import sha256_crypt
from app.mailing import send_email
from app.extensions import db
from app.users import bp
from app.users.forms import *
from app.users.models import *
from app.users.token import *
#bp.route('/register', methods=['POST', 'GET'])
def register():
# Initialize the Register Form
form = RegisterForm()
# If the submitted form is valid
if form.validate_on_submit():
# Check to see if a user already exists with this email address
user = User.query.filter_by(email=form.email.data).first()
# If there is not a user with this email address, create a new user
if not user:
new_user = User(public_id=str(uuid.uuid4()),
email=form.email.data,
password=sha256_crypt.encrypt(
(form.password.data)),
first_name=form.firstname.data,
last_name=form.lastname.data
)
db.session.add(new_user)
db.session.commit()
token = generate_confirmation_token(new_user.email)
confirm_url = url_for("users.confirm_email",
token=token, _external=True)
html = render_template('confirm_email.html',
confirm_url=confirm_url)
subject = "Please confirm your email"
try:
send_email(new_user.email, subject, html)
flash("A confirmation email has been sent to you. Please verify your email address to activate your account.", category="success")
except Exception as e:
flash(
"There was a problem sending the confirmation email. Please try again later.", category="danger")
print(e)
session["user_id"] = new_user.public_id
session["email"] = new_user.email
session["name"] = new_user.first_name
flash("Thanks for registering!", category="success")
return redirect(url_for('users.unconfirmed'))
else:
flash("There is already an account associated with this email address. Log in, or use a different email address.")
return render_template("register_user.html", form=form)
app/extensions.py
from flask_mail import Mail
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
bootstrap = Bootstrap()
mail = Mail()
app/init.py
from flask import Flask
from config import Config, DevelopmentConfig
from .errors import (
page_not_found, forbidden, internal_server_error
)
from .extensions import (
db, mail, bootstrap
)
def create_app(config_class=DevelopmentConfig):
app = MyFlask(__name__)
# Set Configuration
app.config.from_object(config_class)
# Register extensions
# Initialize Boostrap-Flask
bootstrap.init_app(app)
# Initialize Flask-SQLAlchemy
db.init_app(app)
# Initialize Flask-Mail
mail.init_app(app)
# Register error views
app.register_error_handler(404, page_not_found)
app.register_error_handler(403, forbidden)
app.register_error_handler(500, internal_server_error)
with app.app_context():
# register blueprints
from app.main import bp as bp_main
app.register_blueprint(bp_main)
from app.users import bp as bp_users
app.register_blueprint(bp_users)
return app
This answer was almost there but not quite for me. Even more TL:DR.
Put this in your config.py file and forget about the rest...
class Config:
MAIL_USE_TLS = True
MAIL_USE_SSL = False
More details...
You probably have a config.py file that looks like this:
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY')
SQLALCHEMY_DATABASE_URI = 'sqlite:///site.db' # os.environ.get('DATABASE_URI')
MAIL_SERVER = os.environ.get('MAIL_SERVER')
MAIL_PORT = os.environ.get('MAIL_PORT')
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS')
MAIL_USE_SSL = os.environ.get('MAIL_USE_SSL')
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
MAIL_DEFAULT_SENDER = os.environ.get('MAIL_DEFAULT_SENDER')
And then you think you can have something like this in your VSCode debug config or the environment of your server:
"env": {
"MAIL_USE_SSL":"true",
"MAIL_USE_TLS":"true",
Well that doesn't work because of the answer from #serrobit because "true" in VSCode turns into a str instead of a Python True.
So back to the start, hard code TLS to True and SSL to False in the config.py file and go spend time on something useful.
I figured out what was going on. Evidently, you can pass in non-boolean types for MAIL_USE_TLS and MAIL_USE_SSL when initializing the Mail object from Flask-Mail. This becomes a problem when the Connection object calls configure_host() and conditionally checks if self.mail.use_ssl.
Thus, as long as self.mail.use_ssl is not None, the method will set host = smtplib.SMTP_SSL(self.mail.server, self.mail.port), which in my case, lead to [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123) because mail.port was set to 587.
tl;dr
Ensure the configuration variables for your Flask app are set to the appropriate type, especially if you are using environment variables, as those will always be of type str when accessing them via the os.environ dict.
flask_mail.py
class Connection(object):
"""Handles connection to host."""
def __init__(self, mail):
self.mail = mail
def __enter__(self):
if self.mail.suppress:
self.host = None
else:
self.host = self.configure_host()
self.num_emails = 0
return self
def __exit__(self, exc_type, exc_value, tb):
if self.host:
self.host.quit()
def configure_host(self):
## PROBLEM OCCURRED HERE BECAUSE type(self.mail.use_ssl) = <class 'str'> ##
if self.mail.use_ssl:
host = smtplib.SMTP_SSL(self.mail.server, self.mail.port)
else:
host = smtplib.SMTP(self.mail.server, self.mail.port)
host.set_debuglevel(int(self.mail.debug))
if self.mail.use_tls:
host.starttls()
if self.mail.username and self.mail.password:
host.login(self.mail.username, self.mail.password)
return host
Change this in your config.py:
class Config:
MAIL_USE_TLS = bool(strtobool(os.environ.get('MAIL_USE_TLS', 'False')))
MAIL_USE_SSL = bool(strtobool(os.environ.get('MAIL_USE_SSL', 'False')))
I'm trying to send a email via smtp using Django. When I try to send the email, I do not get any error, but my application does not respond and it keeps waiting on to send the email, but obviously it does not send nothing.
I have tried with smtp gmail and smtp hotmail, but it is not working. I have already checked my Windows firewall, and again it is not working. I have tried to send the email using Python shell but it does not send nothing.
I think that I have tried almost everything that I saw on the other posts here in Stack Overflow.
settings.py:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.office365.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'myemail#hotmail.com'
EMAIL_HOST_PASSWORD = 'mypassword'
SERVER_EMAIL = EMAIL_HOST_USER
mails.py:
from django.conf import settings
from django.template.loader import get_template
from django.core.mail import EmailMultiAlternatives
class Mail:
#staticmethod
def send_complete_order(orden, user):
subject = 'order sent'
template = get_template('orders/mails/complete.html')
content = template.render({
'user': user
})
message = EmailMultiAlternatives(subject, 'Testing',
settings.EMAIL_HOST_USER, [user.email])
message.attach_alternative(content, 'text/html')
message.send()
views.py:
#login_required(login_url='login')
def complete(request):
cart = get_or_create_cart(request)
order = get_or_create_order(cart, request)
if request.user.id != order.user_id:
return redirect('carts:cart')
order.complete()
Mail.send_complete_order(order, request.user)
destroy_cart(request)
destroy_order(request)
messages.success(request, "order complete")
return redirect('index')
Create a secure SSL context
context = ssl.create_default_context()
try:
with smtplib.SMTP_SSL(smtp_mail, port, context=context) as server2:
server2.login(your_mail, passwort)
server2.sendmail(mail_from, mail_to, message.as_string())
print("Successfully sent email")
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.