flask mail works perfectly on my local host but it is failing to work on heroku. Below is my setup code
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = '#gmail.com'
app.config['MAIL_PASSWORD'] = '*****'
mail = Mail(app)
#app.route("/mymessage" ,methods= ['POST','GET'])
def mymessage():
em = request.form['email']
mm = request.form['message']
msg = Message('Hello', sender = '#gmail.com', recipients =
['#gmail.com'])
msg.body = mm + " " + 'email address of client :' + em
mail.send(msg)
flash("Message sent successful")
return redirect(url_for('home'))
I get this error "2021-07-10T16:36:34.785576+00:00 app[web.1]: smtplib.SMTPAuthenticationError: (534, b'5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs\n5.7.14 YJZzLi6GK2jMF6AunHXhEoSyz2r6fSOYLB4ABgjP0jNdTWHh3ig-fhlvwc7oxm-quoLVa\n5.7.14 Z7CHpvU2lMufxnPm_0Dsc3p1uWgZhenvZQpb2TdWaZTZ-Sg_wojgwf4zlOlBe44O>\n5.7.14 Please log in via your web browser and then try again.\n5.7.14 Learn more at\n5.7.14 https://support.google.com/mail/answer/78754 m6sm3480925qtx.9 - gsmtp')
2021-07-10T16:36:34.787223+00:00 heroku[router]: at=error code=H13 desc="Connection closed without response" method=POST path="/mymessage" host=buykev.herokuapp.com request_id=fe5ec81e-6d2f-4f8a-b148-a37a15c0bc28 fwd="102.176.94.10" dyno=web.1 connect=4ms service=871ms status=503 bytes=0 protocol=https"
Google blocks your signin attempt from heroku. You need to enable less secure apps and use an app password for your mail account to solve this.
First we have to enable two step verification then only we can use the app password. After enabling the 2-step verification, go to app password and select app as mail and device (I selected windows computer) after you get the app password replace your current password with it. and try sending the mail again. It will work.
app.config['MAIL_PASSWORD'] = 'your_app_password_here'
Related
I have been trying to create a web app which takes email address as an input through HTML form and sends a one time pin for further access to website.
I have 2 html files in my template folder (one for taking user's email address and other for OTP entering)
i have config.json file which stores my accountid and password through which i intend to send the OTP.
.py file
from flask import Flask, render_template, request
from random import randint
import json
from flask_mail import *
with open('config.json','r') as f:
params = json.load(f)['params']
mail = Mail(app)
otp = randint(100,999) #otp production
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = params['gmail-user']
app.config['MAIL_PASSWORD'] = params['gmail-password']
#app.route('/')
def home():
return(render_template('otpgive.html'))
#app.route('/getOTP', methods = ['POST'])
def getOTP(): #OTP send and Verify here
email_id = request.form['usermail']
msg = Message('OTP for the APPLICATION', sender = 'my_email', recipients = [email_id])
#my_email is the email through which i plan to send messages.
msg.body = "Greetings! Your email has been verified successfully. Kindly note your OTP is " + str(otp)
mail.send(msg)
return render_template('otpconfirm.html')
#app.route('/validateOTP', methods = ['POST'])
def validateOTP():
userotp = request.form['otp']
if (otp == int(userotp)):
return ("Email Verified Succcessfully ")
else:
return render_template('otpgive.html',msg = 'incorrect otp')
if __name__ == '__main__':
app.run(debug = False)
#app.run(host='0.0.0.0',port=5000, debug = True)
Solutions I tried but failed:
Tried disabling the firewall.
Tried setting the port number for 0.0.0.0
Tried debug = False
I was expecting it to work. i.e send emails to the users but it shows ConnectionError or InternalServerError
Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
ConnectionRefusedError:
[WinError 10061] No connection could be made because the target machine actively refused it
I finally got the solution.
Since I was using G-Mail, I had to enable 2FA (2-Factor Auth) first on my profile, and then generate a new password for my app.
The password thus obtained was pasted in the config.json file instead of my
main profile password.
Used directions from this thread Less Secure option in gmail unavailable
Now Changes I made in my code:
Reverted back to ip: host='0.0.0.0', port=5000, debug = True
I kept firewall disabled as a precaution.
I repositioned mail = Mail(app) line to after all app.configs
Please i have a problem when i host my flask application on heroku. I explain to you. the code that I will present to you below works perfectly locally. but when I deploy it I manage to connect (on the connection page) but while I am redirected to the home page I am disconnected. However, I use redis (which works very well locally with the same url). I think the problem comes from gunicorn because it's the only parameter that changes between the local version on the browser. how to make the session persist please? my code here:
app.py
app.config['SQLALCHEMY_DATABASE_URI'] = "postgresql://myurlofmydatabase"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SESSION_TYPE'] = "redis"
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_USE_SIGNER'] = True
app.config['SESSION_REDIS'] = redis.from_url(
"redis://default:password#redis-xxxxxxxx.com:10320")
app.config['SECRET_KEY'] = 'what_a_bad_secret_key'
app.config['SESSION_COOKIE_NAME'] = "session"
server_session = Session(app)
db = SQLAlchemy(app)
# cross_origin
# app.route('/login', methods=["POST"])
def login_user():
email = request.json["email"]
password = request.json["password"]
user = Users.query.filter_by(email=email).first()
if user is None:
return jsonify({"error": "error"}), 401
session["user_id"] = user.id
return jsonify({
"id": user.id
})
so, why gunicorn avoid to use flask session even with redis ? and how to fix it ?
I am trying to send a mail from my django app via Amazon SES but I keep getting the following error:
smtplib.SMTPSenderRefused: (501, b'Invalid MAIL FROM address
provided', '=?utf-8?q?AKIAWMDVL5UEWNT3ODOO?=')
These are the settings that I am using:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'email-smtp.ap-south-1.amazonaws.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'smtp credential key'
EMAIL_HOST_PASSWORD = 'smtp credential password'
EMAIL_USE_TLS = True
and here's the code:
class CompanyCreateAPIView(APIView):
permission_classes = (permissions.AllowAny,)
def post(self, request):
email = request.data["company_email"]
phone = request.data["company_phone"]
def random_with_N_digits(n):
range_start = 10 ** (n - 1)
range_end = (10 ** n) - 1
return randint(range_start, range_end)
code = random_with_N_digits(4)
subject = 'Comapny Creation'
message = 'Company Code is {}'.format(code)
email_from = settings.EMAIL_HOST_USER
recipient_list = [str(email), ]
send_mail(subject, message, email_from, recipient_list)
I tried changing the port but it doesn't work, I have verified the email address in SES.. What is it that I am missing ?
You probably do not want to use the SMTP credentials username as the "email from" value. That should be something human readable, whatever you want your recipients to see as the address where the email came from. That address and/or domain also need to be whitelisted in the SES settings.
In Django's settings.py, set the DEFAULT_FROM_EMAIL setting to that address:
DEFAULT_FROM_EMAIL = 'info#example.com'
Do not pass email_from as an explicit setting to send_mail, unless you want to override it for specific emails (e.g. send from info#... for certain emails and newsletter#... for other kinds of emails).
I have the following in my settings.py:
EMAIL_HOST = 'mail.domain.com'
EMAIL_HOST_USER = 'user#domain.com'
EMAIL_HOST_PASSWORD = '******'
EMAIL_PORT = 567
EMAIL_USE_TLS = True
I have the following code to send email:
email = EmailMessage()
email.subject = subject
email.body = body
email.from_email = from_email
email.to = to
email.attach(file_name, pdf, 'application/pdf')
email.send()
Sometimes our server is down and there is no way for me to detect if the mail was sent or not. One way I can think of is to show Mail not sent error when Django cannot connect to mail server. How can I detect a failed connection to the server?
You can use try except.
try:
email.send()
except Exception as e:
print str(e.message)
# you can do some action.
Minor but annoying issue, I have setup my django app to use my company's gmail account to send emails. The sending works fine, but the from in the emails is always the gmail account. Here are me settings/code - I have changed all the addresses etc, but to be sure everything works fine except for the from e-mail.
def send_discrepency_email(action, cart, atype):
r = False
user = cart.user
subject = "%s - User Discrepency Response for order %s (%s)" % (action.upper(), cart.web_order_id, cart.syspro_order_id)
message = "The user %s (%s) has opted to %s his/her order with the following discrepency type: %s." %(user.email, user.customer_id, action.upper(), atype)
try:
e = EmailMessage(subject, message, 'no-reply#rokky.com', ["ecommerce_requests#rokky.com", "pewet#s6688m.com"])
e.send(fail_silently=False)
r = True
except Exception as e:
print "Error sending discrepency email: %s" % e
return r
Note: for the code I have also tried overriding with the headers kwarg to no avail.
DEFAULT_FROM_EMAIL = "ecommerce_requests#rokkyy.com"
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'no-actual-account#gmail.com'
EMAIL_HOST_PASSWORD = 'fakepword'
EMAIL_PORT = 587
Is this even doable with gmail, I swear I used this once before and it worked fine.
In short, no matter what changes I make, the FROM email is always no-actual-account#gmail.com
This is a security setting with gmail. I ran into this issue with a rails app that I wrote. The from address must either be the account you sign in with aka 'no-actual-account#gmail.com' or an alias to that account. You can always just set the reply-to and get a similar effect to changing the from address. Or you will have to use a different SMTP server.