Internal Server Error: when trying to use flask-mail - python

I am trying to send mail to the user through flask-mail. This code shown below works fine on the localhost. But when I deployed my flask app to AWS Elastic Beanstalk and use the send_reset_email function, it throws me Internal Server Error. Where should I change my code? Any help will be appreciated.
My config code:
application = Flask(__name__)
application.config['SECRET_KEY'] = '-------'
application.config["MONGO_URI"] = "mongodb+srv://------"
mongo = PyMongo(application)
db = mongo.db
bcrypt = Bcrypt(application)
application.config['MAIL_SERVER'] = 'smtp.googlemail.com'
application.config['MAIL_PORT'] = 587
application.config['MAIL_USE_TLS'] = True
application.config['MAIL_USERNAME'] = '----'
application.config['MAIL_PASSWORD'] = '----'
mail = Mail(application)
My function file:
def get_reset_token(username, expires_sec=1800):
s = Serializer(application.config['SECRET_KEY'], expires_sec)
return s.dumps({'user': username}).decode('utf-8')
def verify_reset_token(token):
s = Serializer(application.config['SECRET_KEY'])
try:
username = s.loads(token)['user']
except:
return None
user = db.user.find_one({ 'username' : username })
return user
def send_reset_email(user):
token = get_reset_token(username=user['username'])
msg = Message('Password Reset Request',sender='----',recipients=[user['email']])
msg.body = f'''To reset your password, visit the following link:
{url_for('reset_token', token=token, _external=True)}
If you did not make this request then simply ignore this email and no changes will be made.
'''
mail.send(msg)

You can use mail.send_message() that takes in arguments title, sender, recipients and body. Here is a similar code that i used to send email activation token:
code_act = "127.0.0.1:5000/confirm-mail/"+token
mail.send_message("Account activation Link", sender="bot", recipients=email.split(), body="The activation link is " + code_act)

Related

MultiValueDictKeyError varies in localhost and Heroku host

I'm currently learning django and I've created a simple TODO project which has an otp authentication feature. While running the project in localserver otp was generated and stored in the model which is then matched by using if (t.otp == int(request.POST['otp'])): where t is a model object. This works perfectly fine. While I deployed the same in heroku server with DEBUG = True for testing purpose, it is throwing MultiValueDictKeyError in line if (t.otp == int(request.POST['otp'])):. Initially t.opt is set to the value generated and it is reinitialized to 0 once the user enters the correct OTP and registers. Kindly notice the comments in the code that explains the issue a bit more.
My views.py goes as (I've removed some elif part that are not required to reduce the number of lines),
def regsub(request):
if(request.method=="POST"):
uname = request.POST['username']
fname = request.POST['fname']
lname = request.POST['lname']
email = str(request.POST['email'])
pass1 = request.POST['pass1']
try: **#this tries to get the values pass1 and pass 2 whereas except gets the value otp**
if(request.POST['pass1']==request.POST['pass2']):
dictpass = {
'username':uname,
'fname':fname,
'lname':lname,
'email':email,
'password':pass1,
}
the_otp = r.randint(100000,999999)
try:
t=temp.objects.create(name=uname,otp=the_otp)
t.save()
except(IntegrityError):
return render(request,'register.html',{'flag':True,'msg':"Username already exits! Please try again."})
sub = "OTP for registration"
msg = "Some Message " + the_otp
from_email = settings.EMAIL_HOST_USER
to_email = [request.POST['email'],]
send_mail(sub,msg,from_email,to_email)
messages.info(request,"Password Verified! Please Enter the OTP sent to your email.")
return render(request,'register.html',dictpass)
except:
t = temp.objects.get(name=uname)
if (t.otp == int(request.POST['otp'])): **#the flow directly hits here after saving the otp in the model(send_mail part is not executed in try), also throws MultiValueDictKeyError**
user = User.objects.create_user(username=uname, first_name=fname, last_name=lname, email=email, password=pass1)
t.otp = 0
t.save()
user.save()
task.save()
sub = "Account creation successful"
msg = "Some Congrats message"
from_email = settings.EMAIL_HOST_USER
to_email = [request.POST['email'],]
send_mail(sub,msg,from_email,to_email)
messages.info(request,"Account has been created Successfully!")
return render(request,'login.html')
else:
return render(request,'register.html',{'flag':True})
The above code works good in localhost whereas fails in heroku. I have used heroku postgres in production.

Unity POST request to local host

Soooooo, I've checked every answer I can on this site. But I'm not finding a solution that is working. I'm trying to log a user into a site I am developing on local host from a unity application. I'm not passing the boolean "remember" because it was giving me issues.
My unity code is:
IEnumerator Login(string username, string password, bool remember)
{
List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
formData.Add(new MultipartFormDataSection("username=" + username + "&password=" + password));
using (UnityWebRequest www = UnityWebRequest.Post("http://127.0.0.1:5000/api/children/mobile_login/", formData))
{
yield return www.SendWebRequest();
var response = www.downloadHandler.text;
Debug.Log(response);
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Login complete!");
}
}
}
and my python code is:
#children.route('/mobile_login', methods=['POST'])
def mobile_login():
username = request.form.get('username')
password = request.form.get('password')
remember = request.form.get('remember')
user = User.objects(username=username).first()
if user and crypt.check_password_hash(user.password, password):
login_user(user)
user.save()
token = user.get_auth_token()
res = make_response(jsonify({"user": user}), 200)
if remember:
res.set_cookie('child-auth', value=token, path='/')
return res
else:
return jsonify({"error": "unable to login"}), 401
The code is returning "{"error": "unable to login"}" and HTTP/1.1 401 Unauthorized.
I know for a fact that the username and password are correct. And I know the log in function works because my colleague is able to login from the react app he is working on.
I tried running my local host as https but that didn't work so I changed it back to http.
Any suggestions?

How to add your code to Webapp 2 framework for Google AppEngine

Sorry if this seems like a really silly question but I'm not from programming background strictly and I'm having lots of difficulty using the webapp2 framework for Google AppEngine to incorporate my code.
My code is built to log into my own email account and fetch the newest email, then return fields such as content and sender. I have tested this code and it works fine. But I have problem when using webapp 2 framework (error 500).
Could someone please tell me how to use the webapp2 framework for this case?
My python code:
import easyimap
host = "imap.gmail.com"
user = my_username
password = my_password
mailbox = "inbox"
imapper = easyimap.connect(host, user, password, mailbox)
mail1, mail2 = imapper.listup(2) # take latest 2 emails
mail1.uid #uid is email id
email_body = mail1.body
email_sender = mail1.from_addr
email_id = mail1.uid
email_receipt = mail1.to
email_cc = mail1.cc
email_list = [email_body, email_title,email_sender, email_id,
email_cc,email_receipt]
print(email_list)
Webapp2 main.py
import webapp2
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.write('Hello Natalie!')
app = webapp2.WSGIApplication([
('/', MainHandler)
], debug=True)
Something like:
# File: mailer.py - next to "main.py"
import easyimap
import webapp2
class MailerHandler(webapp2.RequestHandler):
def get(self):
host = "imap.gmail.com"
user = my_username
password = my_password
mailbox = "inbox"
imapper = easyimap.connect(host, user, password, mailbox)
mail1, mail2 = imapper.listup(2) # take latest 2 emails
mail1.uid #uid is email id
email_body = mail1.body
email_sender = mail1.from_addr
email_id = mail1.uid
email_receipt = mail1.to
email_cc = mail1.cc
email_list = [email_body, email_title,email_sender, email_id,
email_cc, email_receipt]
self.response.write(', '.join(email_list))
And main.py:
import MailerHandler from mailer
import webapp2
app = webapp2.WSGIApplication([
('/mail-handler', MailerHandler)
], debug=True)
Then call in browser http://[SERVER:PORT]/mail-handler
If you get error 500 you need to look into log in console and ask about specific issue.
Make sure you've copied the "easyimap" to the project folder (next to main.py) and that this library does not use sockets and is written in pure Python. Read this section about adding 3d party libs: https://cloud.google.com/appengine/docs/python/tools/libraries27#vendoring

Run particular Django script in background

I am developing a Gmail extracting app and using Gmail API to fetch mail from server. the problem lies in the fact that fetch time for mails is too large even though I used threading in back end framework. now I am going to implement one feature which will suggest user opting for bulk download that "once your download is ready, we will mail you" but for that i want to run download.py mentioned below in app tree in background and once the fetch is over it will get terminated.
And in the very bottom of the code i want to mail user that their download is ready but its not working though i have defined the mail server in settings.py .
download.py
import httplib2, base64
from stripogram import html2text
from oauth2client.django_orm import Storage
from apiclient.discovery import build
from oauth2client import client
from django.contrib.auth.models import User
from .models import CredentialsModel
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
from gextracto import models
from gextracto.models import UserData
from django.core.mail import EmailMessage
from django.core import mail
connection = mail.get_connection()
class ListMails(APIView):
"""
Gets a list of a specified number mail ids for a particular label
Extracts the email in the form of plain/text
The API returns all the extracted mails
"""
authentication_classes = (authentication.SessionAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def extract_headers(self, message):
"""
Extract the headers for a single mail and returns it
{To, From, Subject}
"""
needed_fields = ('From', 'To', 'Subject')
return {i['name']:i['value'] for i in message['payload']['headers'] if i['name'] in needed_fields}
def get_message_body(self, message):
"""
Get the body of an email
Recursively look for the body for different mimetypes
Returns the body as text/plain
"""
if 'payload' in message:
return self.get_message_body(message['payload'])
elif 'parts' in message:
return self.get_message_body(message['parts'][0])
else:
data = base64.urlsafe_b64decode(message['body']['data'].encode('ASCII'))
markdown_data = html2text(data)#.decode('utf-8', "replace")
data = data.replace("\n", "<br/>")
# return {markdown, html}
return {'markdown':unicode( markdown_data,"ISO-8859-1"), 'html':unicode(data,"ISO-8859-1")} if markdown_data else {'html':unicode(data,"ISO-8859-1")}
def message_content_html(self, userId, message_id, service):
"""
Make queries to get the content for a mail given its message id
Returns all the content
"""
content = {'id':message_id}
# try
message = service.users().messages().get(userId=userId, id=message_id).execute()
mimetype = message['payload']['mimeType']
if mimetype == 'text/html':
return {}
#
else:
body = self.get_message_body(message)
if body == "":
body = "<empty message>"
headers = self.extract_headers(message)
content['body'] = body
content.update(headers)
return content
def collect_mails(self, user, messages, service):
"""
Collect the content for all the mails currently downloaded
"""
all_messages = []
try:
for message in messages:
content = self.message_content_html(user.username, message['id'], service)
if content:
all_messages.append(content)
return all_messages
# return empty list if no messages were downloaded
except KeyError:
return []
def get(self, request, format=None):
"""
Handles the GET request to get all the mails for a label
Paginages through the GAPI content if required
API returns all the messages
{To, From, Subject, body}
"""
user = request.user
storage = Storage(CredentialsModel, 'id', user, 'credential')
credentials = storage.get()
http_auth = credentials.authorize(httplib2.Http())
service = build('gmail', 'v1', http=http_auth)
user_Id = user.username
label_id = request.GET['label']
# try
# call Google API with a request to get a list of all the labels
response = service.users().messages().list(userId=user_Id, labelIds=label_id, maxResults=100).execute()
all_messages = self.collect_mails(user, response['messages'], service)
if not all_messages:
return Response([])
else:
if 'nextPageToken' in response:
page_token_flag = True
# request more more mails if the download limit has not yet been satisfied
while(page_token_flag):
response = service.users().messages().list(userId=user_Id, pageToken=response['nextPageToken'], maxResults=100).execute()
all_messages.append(self.collect_mails(user, response['messages'], service))
print(all_messages)
#for x in range(0,len(all_messages)):
#b=all_messages[10]
#instance= UserData(user_id=user ,label=label_id, sender = b['From'] , subject=b['Subject'] , body=b['body'])
#instance.save()
page_token_flag = 'nextPageToken' in response
##
for x in range(0,len(all_messages)):
b=all_messages[10]
instance= UserData(user_id=user ,label=label_id, sender = b['From'] , subject=b['Subject'] , body=b['body'])
instance.save()
print ("Hi i am here!!!")
email = EmailMessage('Your Download Ready!', 'http://127.0.0.1:8000/admin/gextracto/userdata/', to=[user], connection=connection)
email.send()
connection.close()
return Response(all_messages)
Please tell me the way to run it in background. if need any other info please do ask. Thanks
Don't know the exact requirements but I'll think about Celery to run background tasks. This approach allows to manage all post-script activities in native Django manner.
Also you can think about running the Django script using cron (as manage.py command) - but it can lead to some limitations.
What about sending emails failure - believe, you don't need to close connection after sending email. Usually I use send_mail()/send_mass_mail() functions - please, check their code to get an idea.

google app engine, python , unicode, email, mail api

I'm using an open source web service python application to send email through GAE but if the name or email body contains Arabic or Hebrew characters the application throws some errors (e.g "The indicated parameters are not valid"). Therefore I need to know how to fix this issue. I have to note that I'm a Python beginner (one week since I started playing with Python).
#
import cgi
import os
import logging
import contextlib
from xml.dom import minidom
from xml.dom.minidom import Document
import exceptions
import warnings
import imghdr
from google.appengine.api import images
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from google.appengine.api import mail
import wsgiref.handlers
# START Constants
CONTENT_TYPE_HEADER = "Content-Type"
CONTENT_TYPE_TEXT = "text/plain"
XML_CONTENT_TYPE = "application/xml"
XML_ENCODING = "utf-8"
"""
Allows you to specify IP addresses and associated "api_key"s to prevent others from using your app.
Storage and Manipulation methods will check for this "api_key" in the POST/GET params.
Retrieval methods don't use it (however you could enable them to use it, but maybe rewrite so you have a "read" key and a "write" key to prevent others from manipulating your data).
Set "AUTH = False" to disable (allowing anyone use your app and CRUD your data).
To generate a hash/api_key visit https://www.grc.com/passwords.htm
To find your ip visit http://www.whatsmyip.org/
"""
AUTH = False
# END Constants
# START Exception Handling
class Error(StandardError):
pass
class Forbidden(Error):
pass
logging.getLogger().setLevel(logging.DEBUG)
#contextlib.contextmanager
def mailExcpHandler(ctx):
try:
yield {}
except (ValueError), exc:
xml_error_response(ctx, 400 ,'app.invalid_parameters', 'The indicated parameters are not valid: ' + exc.message)
except (Forbidden), exc:
xml_error_response(ctx, 403 ,'app.forbidden', 'You don\'t have permission to perform this action: ' + exc.message)
except (Exception), exc:
xml_error_response(ctx, 500 ,'system.other', 'An unexpected error in the web service has happened: ' + exc.message)
def xml_error_response(ctx, status, error_id, error_msg):
ctx.error(status)
doc = Document()
errorcard = doc.createElement("error")
errorcard.setAttribute("id", error_id)
doc.appendChild(errorcard)
ptext = doc.createTextNode(error_msg)
errorcard.appendChild(ptext)
ctx.response.headers[CONTENT_TYPE_HEADER] = XML_CONTENT_TYPE
ctx.response.out.write(doc.toxml(XML_ENCODING))
# END Exception Handling
# START Helper Methods
def isAuth(ip = None, key = None):
if AUTH == False:
return True
elif AUTH.has_key(ip) and key == AUTH[ip]:
return True
else:
return False
# END Helper Methods
# START Request Handlers
class Send(webapp.RequestHandler):
def post(self):
"""
Sends an email based on POST params. It will queue if resources are unavailable at the time.
Returns "Success"
POST Args:
to: the receipent address
from: the sender address (must be a registered GAE email)
subject: email subject
body: email body content
"""
with mailExcpHandler(self):
# check authorised
if isAuth(self.request.remote_addr,self.request.POST.get('api_key')) == False:
raise Forbidden("Invalid Credentials")
# read data from request
mail_to = str(self.request.POST.get('to'))
mail_from = str(self.request.POST.get('from'))
mail_subject = str(self.request.POST.get('subject'))
mail_plain = str(self.request.POST.get('plain'))
mail_html = str(self.request.POST.get('html'))
message = mail.EmailMessage()
message.sender = mail_from
message.to = mail_to
message.subject = mail_subject
message.body = mail_plain
if mail_html != None and mail_html != "":
message.html = mail_html
message.send()
self.response.headers[CONTENT_TYPE_HEADER] = CONTENT_TYPE_TEXT
self.response.out.write("Success")
# END Request Handlers
# START Application
application = webapp.WSGIApplication([
('/send', Send)
],debug=True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()
# END Application
mail_to = str(self.request.POST.get('to'))
mail_from = str(self.request.POST.get('from'))
mail_subject = str(self.request.POST.get('subject'))
mail_plain = str(self.request.POST.get('plain'))
mail_html = str(self.request.POST.get('html'))
I doubt you need to convert them to strings. Try without str(), it could work.

Categories