Unable to send emails through Flask-mail - flask

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

Related

Flask-mail: How to handle multiple email requests at once

So I wrote a dedicated flask app for handling emails for my application and deployed it on heroku. In which I have set up a route to send emails:
#app.route('/send', methods=['POST'])
def send_now():
with app.app_context():
values = request.get_json()
email = values['email']
code = values['code']
secret_2 = str(values['secret'])
mail = Mail(app)
msg = Message("Password Recovery",sender="no*****#gmail.com",recipients=[email])
msg.html = "<h1>Your Recovery Code is: </h1><p>"+str(code)+"</p>"
if secret == secret_2:
mail.send(msg)
response = {'message': 'EmailSent'}
return jsonify(response), 201
It works fine for a single user at a time, however when multiple users send a POST request, the client user needs to wait till the POST returns a 201. Thus the wait period keeps increasing (it may not even send). So how do I handle this so accommodate multiple simultaneous users. Threads? Buffer? I have no idea
You need to send mail via Asynchronous thread calls in Python. Have a look at this code sample and implement in your code.
from threading import Thread
from app import app
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
def send_email(subject, sender, recipients, text_body, html_body):
msg = Message(subject, sender=sender, recipients=recipients)
msg.body = text_body
msg.html = html_body
thr = Thread(target=send_async_email, args=[app, msg])
thr.start()
This will allow to send the mail in background.

Authentication with GitLab to a terminal

I have a terminal that served in webbrowser with wetty. I want to authenticate the user from gitlab to let user with interaction with the terminal(It is inside docker container. When user authenticated i ll allow him to see the containers terminal).
I am trying to do OAuth 2.0 but couldn't manage to achieve.
That is what i tried.
I created an application on gitlab.
Get the code and secret and make a http call with python script.
Script directed me to login and authentication page.
I tried to get code but failed(Their is no mistake on code i think)
Now the problem starts in here. I need to get the auth code from redirected url to gain access token but couldn't figure out. I used flask library for get the code.
from flask import Flask, abort, request
from uuid import uuid4
import requests
import requests.auth
import urllib2
import urllib
CLIENT_ID = "clientid"
CLIENT_SECRET = "clientsecret"
REDIRECT_URI = "https://UnrelevantFromGitlabLink.com/console"
def user_agent():
raise NotImplementedError()
def base_headers():
return {"User-Agent": user_agent()}
app = Flask(__name__)
#app.route('/')
def homepage():
text = 'Authenticate with gitlab'
return text % make_authorization_url()
def make_authorization_url():
# Generate a random string for the state parameter
# Save it for use later to prevent xsrf attacks
state = str(uuid4())
save_created_state(state)
params = {"client_id": CLIENT_ID,
"response_type": "code",
"state": state,
"redirect_uri": REDIRECT_URI,
"scope": "api"}
url = "https://GitlapDomain/oauth/authorize?" + urllib.urlencode(params)
print get_redirected_url(url)
print(url)
return url
# Left as an exercise to the reader.
# You may want to store valid states in a database or memcache.
def save_created_state(state):
pass
def is_valid_state(state):
return True
#app.route('/console')
def reddit_callback():
print("-----------------")
error = request.args.get('error', '')
if error:
return "Error: " + error
state = request.args.get('state', '')
if not is_valid_state(state):
# Uh-oh, this request wasn't started by us!
abort(403)
code = request.args.get('code')
print(code.json())
access_token = get_token(code)
# Note: In most cases, you'll want to store the access token, in, say,
# a session for use in other parts of your web app.
return "Your gitlab username is: %s" % get_username(access_token)
def get_token(code):
client_auth = requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET)
post_data = {"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI}
headers = base_headers()
response = requests.post("https://MyGitlabDomain/oauth/token",
auth=client_auth,
headers=headers,
data=post_data)
token_json = response.json()
return token_json["access_token"]
if __name__ == '__main__':
app.run(host="0.0.0.0",debug=True, port=65010)
I think my problem is on my redirect url. Because it is just an irrelevant link from GitLab and there is no API the I can make call.
If I can fire
#app.route('/console')
that line on Python my problem will probably will be solved.
I need to make correction on my Python script or different angle to solve my problem. Please help.
I was totally miss understand the concept of auth2. Main aim is to have access_token. When i corrected callback url as localhost it worked like charm.

Python smtplib email doesn't send to External Addresses

I'm able to automate some emails internally using mime and smtplib, but for some reason, these emails fail to send to external addresses (outside of company's domain)
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email import Encoders
import smtplib
SERVER = 'mailrelay'
FROM = 'myemail#internaldomain.com'
TO = ['myemail#internaldomain.com','someemail#externaldomain.com']
body = 'This is a test'
msg = MIMEMultipart()
msg["To"] = ','.join(TO)
msg["From"] = FROM
msg["Subject"] = 'Automated Test Email'
msgText = MIMEText(body, 'html')
msg.attach(msgText)
message = msg.as_string()
server = smtplib.SMTP(SERVER)
server.sendmail(FROM,TO,message)
server.quit()
Produces this error:
SMTPRecipientsRefused: {'someemail#externaldomain.com': (550, '5.7.1 Unable to relay')}
Admin insists that relaying is enabled, and told me that sending emails to external domains using Powershell works, so it can't be a relay issue.
So now I'm stuck. If it's not the problem python is telling me it is, is my admin wrong or is something else going on?
Any ideas?
Looks like I just needed to authenticate in this case:
server.ehlo()
server.starttls()
server.ehlo
server.login('user', 'pass')

Python error "Connection reset by peer" in requests module

My goal is to create a persistent cookie on-the-fly by supplying user id & password and use that cookie in POST request using a session object. But below code returns below exception.
('Connection aborted.', error(54, 'Connection reset by peer'))
class CreatePersistentCookie(): """This class is created to generate a persistent cookie that can further be used through out session for all the service requests being executed"""
class CreatePersistentCookie():
"""This class is created to generate a persistent cookie that can further be
used through out session for all the service requests being executed"""
def __init__(self, headers, data, url, params, authserver):
self.headers = headers
self.data = data
self.url = url
self.params = params
self.authserver = authserver
def generateCookie(self):
with requests.session() as s:
reqsessionObj = s.post(self.authserver,params = self.params)
reqCookie = reqsessionObj.request.headers['Cookie'] # this returns the Cookie i need
regexObj = re.compile(r'act-uat=\S+') # this is my app specific pattern search that returns the exact cookie text i need.
matchObj = regexObj.search(reqCookie)
sessionCookie = matchObj.group()
self.headers['Cookie'] = sessionCookie # adding Cookie attribute in headers.
try:
r = s.post(self.url, data=json.dumps(self.data), headers=self.headers)
return r.raise_for_status()
except requests.exceptions.RequestException as err:
print err
def main():
# Defining the params variable. This contains authentication details such as user id,password & App id.
params = {"accountId": "John",
"accountPassword": "password",
"appIdKey": "5c9773e36fd6ea7cc2f9f8ffd9da3e3"
}
# Defining the authserver variable that contains the host details where authentication happens.
authserver = 'https://auth-uat.com/authenticate'
# creating a object cookieObj from class CreatePersistentCookie that returns persistent cookie.
#print cookies
headers = {'Content-Type': 'application/json;charset=UTF-8',
'Host':'service-uat1.com'}
data = {"appName":"abc","appKey":"abc","type":"jdbc","queryName":"xyz","version":"v1.2","useCache":"false","bindVars":[{"bindVarName":"In_dt","bindVarVal":"2014-05-13"},{"bindVarName":"In_Location","bindVarVal":"USA"}]}
url = 'https://uat1.com/gsf/abc/derf/abc/services/xyz'
cookieObj = CreatePersistentCookie(headers, data, url, params, authserver)
cookieObj.generateCookie()
if __name__ == '__main__':
main()
Connection reset by peer indicates that the server you're trying to connect to is refusing the connection. Normally, there is a handshake between your computer and the website's server, but here for some reason, the server is refusing the connection. I would use the urllib, requests, mechanize, and cookielib modules (some of which only work in Python 2.7). Then, using urllib you can attach a user-client header like Firefox, which will trick the browser into accepting the connection because they will think you are a regular person surfing the web, not a robot.
Try the below command in terminal it worked for me
pip install requests[security]
In my case it worked from Postman but not from python script. Restarting the system fixed it.

Django send_mail results in error 61 refused on Mac OSX

Running into a very stange error. I'm running Django on my Mac OSX and when I tried to send an email from my application it hangs and gives me this error: "Error 61 Connection Refused"
Any ideas? I don't have my firewall turned on. I can upload an image of the error if needed.
Have you actually configured the EMAIL_* settings in settings.py? Error 61 is the error you get if you leave it on the default values and you don't have a local SMTP server running.
Alternatively, as Peter suggests, if you have set it up then you might need to use authentication with your SMTP server.
Being totally Max OS X ignorant, my first guess would be that your SMTP server requires authentication.
Its simple, if sendmail works via command-line, copy the code from http://djangosnippets.org/snippets/1864/ into a file called sendmail.py
"""sendmail email backend class."""
import threading
from django.conf import settings
from django.core.mail.backends.base import BaseEmailBackend
from subprocess import Popen,PIPE
class EmailBackend(BaseEmailBackend):
def __init__(self, fail_silently=False, **kwargs):
super(EmailBackend, self).__init__(fail_silently=fail_silently)
self._lock = threading.RLock()
def open(self):
return True
def close(self):
pass
def send_messages(self, email_messages):
"""
Sends one or more EmailMessage objects and returns the number of email
messages sent.
"""
if not email_messages:
return
self._lock.acquire()
try:
num_sent = 0
for message in email_messages:
sent = self._send(message)
if sent:
num_sent += 1
finally:
self._lock.release()
return num_sent
def _send(self, email_message):
"""A helper method that does the actual sending."""
if not email_message.recipients():
return False
try:
ps = Popen(["sendmail"]+list(email_message.recipients()), \
stdin=PIPE)
ps.stdin.write(email_message.message().as_string())
ps.stdin.flush()
ps.stdin.close()
return not ps.wait()
except:
if not self.fail_silently:
raise
return False
return True
Inside of settings.py, set the variable:
EMAIL_BACKEND = 'path.to.sendmail.EmailBackend'
I had a similar problem and found this link: http://dashasalo.com/2011/05/29/django-send_mail-connection-refused-on-macos-x/
Basically, you need to have a mail server running in order to send mail from it. If there is no mail server running you will get a 61.