def test_printException(): with app.app_context(): # printException((mes="An Unknown Error Occured",level="error",err=None)) assert utils.printException(mes="Not an error") == "Not an error" # create an acutal error with pytest.raises(Exception): try: if nothing == True: pass except Exception as e: mes = utils.printException(mes="Should Be error", err=e) assert "NameError" in mes
def edit(article_handle='0'): setExits() g.title = "Article" articles = Article(g.db) #import pdb; pdb.set_trace() rec_id = cleanRecordID(article_handle) rec = articles.get(article_handle) if not rec and not rec_id == 0: flash('Could not find that artcle') return redirect(g.homeURL) if rec_id == 0: rec = articles.new() #Is there a form? if request.form: #import pdb; pdb.set_trace() articles.update(rec,request.form) if valid_form(rec): if request.form['publication_date']: # convert to a date time rec.publication_date = getDatetimeFromString(request.form['publication_date']) try: articles.save(rec) g.db.commit() return redirect(g.homeURL) except Exception as e: g.db.rollback() flash(printException("Error when attepting to save article.",e)) return render_template('news/article_edit.html',rec=rec)
def edit(rec_id=None): setExits() g.title = "Edit {} Record".format(g.title) role = Role(g.db) rec = None if rec_id == None: rec_id = request.form.get('id', request.args.get('id', -1)) rec_id = cleanRecordID(rec_id) #import pdb;pdb.set_trace if rec_id < 0: flash("That is not a valid ID") return redirect(g.listURL) if not request.form: """ if no form object, send the form page """ if rec_id == 0: rec = role.new() else: rec = role.get(rec_id) if not rec: flash("Unable to locate that record") return redirect(g.listURL) else: #have the request form #import pdb;pdb.set_trace() if rec_id and request.form['id'] != 'None': rec = role.get(rec_id) else: # its a new unsaved record rec = role.new() role.update(rec, request.form) if validForm(rec): #update the record role.update(rec, request.form) # make names lower case rec.name = request.form['name'].lower().strip() try: role.save(rec) g.db.commit() except Exception as e: g.db.rollback() flash( printException( 'Error attempting to save ' + g.title + ' record.', "error", e)) return redirect(g.listURL) else: # form did not validate pass # display form return render_template('role/role_edit.html', rec=rec)
def email_admin(subject=None, message=None): """ Shortcut method to send a quick email to the admin """ try: app_config = get_app_config() if subject == None: subject = "An alert was sent from {}".format( app_config['SITE_NAME']) if message == None: message = "An alert was sent from {} with no message...".format( app_config['SITE_NAME']) return send_message( None, subject=subject, body=message, ) except Exception as e: flash(printException("Not able to send message to admin.", str(e)))
def edit(rec_handle=None): setExits() g.title = "Edit {} Record".format(g.title) #import pdb;pdb.set_trace() user = User(g.db) rec = None request_rec_id = cleanRecordID( request.form.get('id', request.args.get('id', -1))) is_admin = g.admin.has_access(g.user, User) no_delete = not is_admin session_roles = session["user_roles"] #roles of currnet user new_password = '' confirm_password = '' user_roles = ['user'] # default roles = Role(g.db).select() include_inactive = True if not is_admin: g.listURL = g.homeURL # Non admins can't see the list include_inactive = False if rec_handle != None: pass #rec_handle has to come from admin() at this point elif rec_handle == None and g.user != None and request_rec_id == -1: rec_handle = g.user else: rec_handle = request_rec_id if rec_handle < 0: flash("That is not a valid User ID") return redirect(g.listURL) if not request.form: """ if no form object, send the form page """ if rec_handle != g.user and not is_admin: flash("You do not have access to that area") return redirect(g.homeURL) elif rec_handle == 0: rec = user.new() else: rec = user.get(rec_handle, include_inactive=include_inactive) if not rec: flash("Unable to locate user record") return redirect('/') user_roles = get_user_role_names(rec) else: #have the request form #import pdb;pdb.set_trace() is_new_user = False if rec_handle and request.form['id'] != 'None': rec = user.get(rec_handle, include_inactive=include_inactive) user_roles = get_user_role_names(rec) else: # its a new unsaved record is_new_user = True rec = user.new() user.update(rec, request.form) if validForm(rec): #Are we editing the current user's record? editingCurrentUser = '' if (g.user == rec.username): if 'new_username' in request.form: editingCurrentUser = request.form['new_username'].strip() else: editingCurrentUser = g.user else: if (g.user == rec.email): editingCurrentUser = request.form['email'].strip() #update the record user.update(rec, request.form) set_username_from_form(rec) set_password_from_form(rec) try: user.save(rec) # update the user roles if 'roles_select' in request.form: #delete all the users current roles user.clear_roles(rec.id) for role_name in request.form.getlist('roles_select'): #find the role by name role = Role(g.db).select_one( where='name = "{}"'.format(role_name)) if role: user.add_role(rec.id, role.id) # if the username or email address are the same as g.user # update g.user if it changes if (editingCurrentUser != ''): setUserStatus(editingCurrentUser, rec.id) g.db.commit() except Exception as e: g.db.rollback() flash( printException( 'Error attempting to save ' + g.title + ' record.', "error", e)) return redirect(g.listURL) if is_new_user == True and rec.email: from takeabeltof.mailer import send_message # send an email to welcome the new user full_name = '{} {}'.format(rec.first_name, rec.last_name).strip() context = { 'rec': rec, 'full_name': full_name, } to_address_list = [(full_name, rec.email)] sent, msg = send_message( to_address_list, subject="Welcome to {{config.SITE_NAME}}", context=context, html_template='user/email/welcome.html', text_template='user/email/welcome.txt', ) if not sent: flash('The welcome message could not be sent. Error: {}'. format(msg)) return redirect(g.listURL) else: # form did not validate, give user the option to keep their old password if there was one #need to restore the username user.update(rec, request.form) if 'new_username' in request.form: rec.username = request.form[ 'new_username'] #preserve user input # preserve the selected roles #import pdb;pdb.set_trace() if 'roles_select' in request.form: user_roles = request.form.getlist('roles_select') #and password new_password = request.form.get('new_password', '') confirm_password = request.form.get('confirm_password', '') # display form return render_template( 'user/user_edit.html', rec=rec, no_delete=no_delete, is_admin=is_admin, user_roles=user_roles, roles=roles, session_roles=session_roles, new_password=new_password, confirm_password=confirm_password, )
def register(): """Allow people to sign up thier own accounts on the web site""" setExits() g.title = "Account Registration" g.editURL = url_for('.register') g.listURL = '/' # incase user cancels user = User(g.db) rec = user.new() from takeabeltof.mailer import send_message from app import app is_admin = False user_roles = None roles = None no_delete = True success = True help = render_markdown_for("user/new_account_help.md", mod) if 'confirm' in request.args: #Try to find the user record that requested registration rec = user.select_one(where='access_token = "{}"'.format( request.args.get('confirm', '')).strip()) if rec and rec.access_token_expires > time(): if rec.active == 1: success = "active" else: success = "waiting" #inform the admin to = [(app.config['MAIL_DEFAULT_SENDER'], app.config['MAIL_DEFAULT_ADDR'])] confirmURL = "{}://{}{}?activate={}".format( app.config['HOST_PROTOCOL'], app.config['HOST_NAME'], url_for('.activate'), rec.access_token) deleteURL = "{}://{}{}?delete={}".format( app.config['HOST_PROTOCOL'], app.config['HOST_NAME'], url_for('.delete'), rec.access_token) context = { 'rec': rec, 'confirmURL': confirmURL, 'deleteURL': deleteURL } subject = 'Activate Account Request from - {}'.format( app.config['SITE_NAME']) html_template = 'user/email/admin_activate_acct.html' text_template = None send_message(to, context=context, subject=subject, html_template=html_template, text_template=text_template) return render_template('user/registration_success.html', success=success) else: flash("That registration request has expired") return redirect('/') if not request.form: pass else: if validForm(rec): #update the record user.update(rec, request.form) rec.active = 0 # Self registered accounts are inactive by default set_password_from_form(rec) set_username_from_form(rec) rec.access_token = get_access_token() rec.access_token_expires = time() + (3600 * 48) try: user.save(rec) #Send confirmation email to user full_name = '{} {}'.format(rec.first_name, rec.last_name).strip() to = [(full_name, rec.email)] context = {'rec': rec, 'confirmation_code': rec.access_token} subject = 'Signup Success' html_template = 'user/email/registration_confirm.html' text_template = 'user/email/registration_confirm.txt' send_message(to, context=context, subject=subject, html_template=html_template, text_template=text_template) #inform the admin to = [(app.config['MAIL_DEFAULT_SENDER'], app.config['MAIL_DEFAULT_ADDR'])] deleteURL = "{}://{}{}?delete={}".format( app.config['HOST_PROTOCOL'], app.config['HOST_NAME'], url_for('.delete'), rec.access_token) context = { 'rec': rec, 'deleteURL': deleteURL, 'registration_exp': datetime.fromtimestamp( rec.access_token_expires).strftime('%Y-%m-%d %H:%M:%S') } subject = 'Unconfirmed Account Request from - {}'.format( app.config['SITE_NAME']) html_template = 'user/email/admin_activate_acct.html' text_template = None send_message(to, context=context, subject=subject, html_template=html_template, text_template=text_template) g.db.commit() except Exception as e: g.db.rollback() mes = "An error occured while new user was attempting to register" printException(mes, "error", e) # Send email to the administrator to = [(app.config['MAIL_DEFAULT_SENDER'], app.config['MAIL_DEFAULT_ADDR'])] context = {'mes': mes, 'rec': rec, 'e': str(e)} body = "Signup Error\n{{context.mes}}\n{{context.e}}\nrec:\n{{context.rec}}" send_message(to, context=context, body=body, subject=mes) success = False return render_template('user/registration_success.html', success=success) else: #validation failed user.update(rec, request.form) return render_template('user/user_edit.html', rec=rec, no_delete=no_delete, is_admin=is_admin, user_roles=user_roles, roles=roles, help=help)
def get_jump_data(): try: mes = 'No message Yet...' from takeabeltof.database import Database db = Database(working_path + "/" + app.config['DATABASE_PATH']).connect() init_tables(db) # creates tables if needed # Use this to determine if bikes have been off the system too long (getting recharged?) last_sighting_limit = (local_datetime_now() - timedelta(hours=2)).isoformat(sep=' ') #size=10 #network = 165 size = app.config['JUMP_REQUEST_SIZE'] network = app.config['JUMP_NETWORK_ID'] shapes_list = get_shape_list() if not shapes_list: # most likely the json files don't exist or are in the wrong place alert_admin("Error: No shape files were found when trying to get shapes_list in jump.get_data") # I now have 2 Jump accounts to use for polling the server, so I can poll more often # if the minutes are odd, or even... if (local_datetime_now().minute % 2 == 0): #even row = 0 else: #odd row = 1 username = app.config['JUMP_LOGIN'][row][0] password = app.config['JUMP_LOGIN'][row][1] url = 'https://app.socialbicycles.com/api/bikes.json?page=1&per_page={}&network_id={}'.format(size,network) request_data = requests.get(url,auth=(username,password)).json() if "error" in request_data or 'items' not in request_data: # {"error":"Not Authenticated","code":401} db.close() mes = """An error occured while attempting to import Jump Bike data. Time: {} Error: {}""".format(local_datetime_now().isoformat(),str(request_data)) alert_admin(mes) return "Error received while accessing Jump Data: {}".format(str(request_data)) observations = request_data['items'] retrieval_dt = local_datetime_now() sightings = Sighting(db) bikes = Bike(db) trips = Trip(db) new_data = {'sighting':0, 'bike': 0, 'trip': 0, 'available': 0,} avail_city_data = {} for ob in observations: lng = ob['lng'] = ob['current_position']['coordinates'][0] lat = ob['lat'] = ob['current_position']['coordinates'][1] ob['retrieved'] = retrieval_dt sql = 'jump_bike_id = {}'.format(ob['id']) bike = bikes.select_one(where=sql) new_data['available'] += 1 city = get_city(shapes_list,lng,lat) if city in avail_city_data: avail_city_data[city] += 1 else: avail_city_data[city] = 1 if not bike: # A new bike... bike = bikes.new() bike.jump_bike_id = ob.get('id',None) bike.name = ob.get('name',None) bikes.save(bike) new_data['bike'] += 1 sightings.save(new_sighting(sightings,ob,shapes_list)) new_data['sighting'] += 1 continue #Get the last time we saw this bike where = 'jump_bike_id = {}'.format(bike.jump_bike_id) order_by = 'id desc' # should be by datetime, but there are issues sight = sightings.select_one(where=where, order_by=order_by) if not sight: #This should really never happen... sightings.save(new_sighting(sightings,ob,shapes_list)) new_data['sighting'] += 1 continue if long_time_no_see(datetime.strptime(sight.retrieved,'%Y-%m-%d %H:%M:%S.%f')): #This bike has been off getting service sight = new_sighting(sightings,ob,shapes_list,returned_to_service=1) sightings.save(sight) #print('Returned to service: {}'.format(sight)) new_data['sighting'] += 1 continue # Seeing the bike again so how far has it moved distance = miles_traveled(lng, lat, sight.lng, sight.lat) if distance >= 0.128: #bike moved at least 1/8 mile origin_id = sight.id sight = new_sighting(sightings,ob,shapes_list) sightings.save(sight) #print('New Trip Sighting: {}'.format(sight)) new_data['sighting'] += 1 # Make a trip trip = new_trip(trips,bike.jump_bike_id,origin_id,sight.id,distance) trips.save(trip) #print('New Trip : {}'.format(sight)) new_data['trip'] += 1 else: #too short a move, Just update the sighting record sightings.save(update_sighting(ob,sight)) #end ob loop # record the number of available bikes if new_data['available'] > 0: for city in avail_city_data.keys(): avail = AvailableBikeCount(db).new() avail.bikes_available = avail_city_data[city] avail.city = city avail.retrieved = retrieval_dt avail.day_number = day_number() AvailableBikeCount(db).save(avail) db.commit() mes = 'At {}; New Data added: Available: {}, Sightings: {}, Bikes: {}, Trips: {}'.format(local_datetime_now().isoformat(),new_data['available'],new_data['sighting'],new_data['bike'],new_data['trip']) return(mes) except Exception as e: try: if db: db.rollback() except Exception as e: mes = """Could not connect to db while attempting to import Jump Bike data. Error: {} """.format(str(e)) mes = printException(mes,"error",e) alert_admin(mes) return mes mes = """An error occured while attempting to import Jump Bike data. Error: {} """.format(str(e)) mes = printException(mes,"error",e) alert_admin(mes) return mes
def contact(): setExits() g.title = 'Contact Us' from app import app from takeabeltof.mailer import send_message rendered_html = render_markdown_for('contact.md', mod) show_form = True context = {} success = True passed_quiz = False mes = "No errors yet..." if request.form: #import pdb;pdb.set_trace() quiz_answer = request.form.get('quiz_answer', "A") if quiz_answer.upper() == "C": passed_quiz = True else: flash("You did not answer the quiz correctly.") if request.form['email'] and request.form['comment'] and passed_quiz: context.update({'date': datetime_as_string()}) for key, value in request.form.items(): context.update({key: value}) # get best contact email to = [] # See if the contact info is in Prefs try: from users.views.pref import get_contact_email contact_to = get_contact_email() if contact_to: to.append(contact_to) except Exception as e: printException( "Need to update home.contact to find contacts in prefs.", "error", e) try: admin_to = None if not to: to = [ ( app.config['CONTACT_NAME'], app.config['CONTACT_EMAIL_ADDR'], ), ] if app.config['CC_ADMIN_ON_CONTACT']: admin_to = ( app.config['MAIL_DEFAULT_SENDER'], app.config['MAIL_DEFAULT_ADDR'], ) if admin_to: to.append(admin_to, ) except KeyError as e: mes = "Could not get email addresses." mes = printException(mes, "error", e) if to: #we have at least a to address, so continue pass else: success = False if success: # Ok so far... Try to send success, mes = send_message( to, subject="Contact from {}".format(app.config['SITE_NAME']), html_template="home/email/contact_email.html", context=context, reply_to=request.form['email'], ) show_form = False else: context = request.form flash('You left some stuff out.') if success: return render_template('contact.html', rendered_html=rendered_html, show_form=show_form, context=context, passed_quiz=passed_quiz) handle_request_error(mes, request, 500) flash(mes) return render_template('500.html'), 500
def get_gbfs_data(): try: #import pdb;pdb.set_trace() mes = 'No message Yet...' raw_data = "No data fetched yet" #just a place-holder for now db = g.db shapes_list = get_shape_list() if not shapes_list: # most likely the json files don't exist or are in the wrong place alert_admin( "Error: No shape files were found when trying to get shapes_list in jump.get_data" ) # Get free bike status feed url url = get_free_bike_url() if not url: mes = """No Free bike status URL while attempting to import Jump Bike data for {}. Time: {} URL: {}""".format(app.config['JUMP_NETWORK_NAME'], local_datetime_now().isoformat(), str(url)) alert_admin(mes) raw_data = requests.get(url).text if "error" in raw_data or '"bikes":' not in raw_data: # Not sure what an error looks like mes = """An error occured while attempting to import Jump Bike data from {}. Time: {} Error: {}""".format(url, local_datetime_now().isoformat(), raw_data) alert_admin(mes) return mes #convert data from json try: request_data = json.loads(raw_data) except: # alert on conversion error mes = """An error occured while attempting to convert json data in "get_gbfs_data()". Time: {} Error: {}""".format(local_datetime_now().isoformat(), raw_data) alert_admin(mes) return mes #Are there any bikes? if not request_data['data']['bikes']: mes = """No bikes were retrievd in "get_gbfs_data()" step 2. Time: {} Error: {}""".format(local_datetime_now().isoformat(), str(request_data)) alert_admin(mes) return mes3 #got data! observations = request_data['data']['bikes'] retrieval_dt = local_datetime_now() sightings = Sighting(db) bikes = Bike(db) trips = Trip(db) new_data = { 'sighting': 0, 'bike': 0, 'trip': 0, 'available': 0, } avail_city_data = {} # Temporary to only send email once per retireval found_a_different_vehicle = '' for ob in observations: # Jump added a new property for vehicle type. We are only interested in bikes if ob.get("jump_vehicle_type", "bike") != "bike": # Alert me when we see a vehicle type I don't recognize temp_veh = ob.get("jump_vehicle_type", "None") if found_a_different_vehicle != temp_veh: found_a_different_vehicle = temp_veh mes = """Received response with vehicle type of '{}'. Time: {} Data: {} """.format(temp_veh, local_datetime_now().isoformat(), ob) alert_admin(mes) lng = ob['lon'] lat = ob['lat'] ob['retrieved'] = retrieval_dt # the bike_id for jump is prepended with 'bike_' so we need to strip that off bike_id = ob.get('bike_id', None) if not bike_id: mes = """bike_id not in data. Time: {}""".format(local_datetime_now().isoformat(), ) alert_admin(mes) continue pos = ob['bike_id'].find('_') if pos > 0: ob['bike_id'] = ob['bike_id'][pos + 1:] # jump has a custom field 'jump_ebike_battery_level' with a '%' sign. Drop the sign batt_pct = ob.get('jump_ebike_battery_level', None) if batt_pct: pos = batt_pct.find("%") if pos > 0: ob['jump_ebike_battery_level'] = batt_pct[:pos] sql = 'jump_bike_id = {}'.format(ob['bike_id']) bike = bikes.select_one(where=sql) new_data['available'] += 1 city = get_city(lng, lat, shapes_list) if city in avail_city_data: avail_city_data[city] += 1 else: avail_city_data[city] = 1 if not bike: # A new bike... bike = bikes.new() bike.jump_bike_id = ob['bike_id'] bike.name = ob.get('name', None) bike.vehicle_type = ob.get("jump_vehicle_type", None) bikes.save(bike) new_data['bike'] += 1 sightings.save(new_sighting(sightings, ob, shapes_list)) new_data['sighting'] += 1 # no need to look for previous sightings continue #Get the last time we saw this bike where = 'jump_bike_id = {}'.format(bike.jump_bike_id) order_by = 'id desc' # should be by datetime, but there are issues sight = sightings.select_one(where=where, order_by=order_by) if not sight: #This should really never happen... sightings.save(new_sighting(sightings, ob, shapes_list)) new_data['sighting'] += 1 continue #import pdb;pdb.set_trace() # sight.retrieved is a string so try to convert it to a datetime # Because some dates were stored as time zone aware and some not, just truncat it to seconds prev_sighting_date = datetime.strptime(sight.retrieved[:19], '%Y-%m-%d %H:%M:%S') if long_time_no_see(make_tz_aware(prev_sighting_date)): #This bike has been off getting service sight = new_sighting(sightings, ob, shapes_list, returned_to_service=1) sightings.save(sight) #print('Returned to service: {}'.format(sight)) new_data['sighting'] += 1 continue # Seeing the bike again so how far has it moved distance = miles_traveled(lng, lat, sight.lng, sight.lat) if distance >= 0.128: #import pdb;pdb.set_trace() #bike moved at least 1/8 mile origin_id = sight.id sight = new_sighting(sightings, ob, shapes_list) sightings.save(sight) #print('New Trip Sighting: {}'.format(sight)) new_data['sighting'] += 1 # Make a trip trip = new_trip(trips, bike.jump_bike_id, origin_id, sight.id, distance) trips.save(trip) #print('New Trip : {}'.format(sight)) new_data['trip'] += 1 else: #too short a move, Just update the sighting record sightings.save(update_sighting(ob, sight)) #end ob loop # record the number of available bikes if new_data['available'] > 0: for city in avail_city_data.keys(): avail = AvailableBikeCount(db).new() avail.bikes_available = avail_city_data[city] avail.city = city avail.retrieved = retrieval_dt avail.day_number = day_number() AvailableBikeCount(db).save(avail) db.commit() mes = 'At {}; New Data added: Available: {}, Sightings: {}, Bikes: {}, Trips: {}'.format( local_datetime_now().isoformat(), new_data['available'], new_data['sighting'], new_data['bike'], new_data['trip']) # Update the home page cache with the new data render_home_page_to_cache(force=True) return (mes) except Exception as e: try: mes_data_response = raw_data except: mes_data_response = "No Data Retrieved" mes = """An un-caught error occured while attempting to fetch bike data. Error: {} Data Retrived: {} """.format(str(e), mes_data_response) mes = printException(mes, "error", e) alert_admin(mes) return mes
def send_message(to_address_list=None, **kwargs): """Send an email with the parameters as: to_address_list=[list of tuples (recipient name,recipient address)]=None If the to_address_list is not provided, mail will be sent to the admin -- all templates must use 'context' as their only context variable **kwargs: context = {a dictionary like object with data for rendering all emails} = {} body = <text for body of email> = None body_text_is_html = <True | False> = False text_template=<template to render as plain text message> = None html_template=<template to render as html message> = None subject=<subject text (will be rendered with the current context>)>= a default subject subject_prefix=<some text to prepend to the subject: = '' from_address=<from address> = app.config['MAIL_DEFAULT_ADDR'] from_sender=<name of sender> = app.config['MAIL_DEFAULT_SENDER'] reply_to_address=<replyto address> = from_address reply_to_name=<name of reply to account> = from_sender On completion returns a tuple of: success [True or False] message "some message" """ #import pdb;pdb.set_trace() app_config = get_app_config( ) #update the settings. this also recreates the mail var in app with new settings context = kwargs.get('context', {}) body = kwargs.get('body', None) body_is_html = kwargs.get('body_is_html', None) text_template = kwargs.get('text_template', None) html_template = kwargs.get('html_template', None) subject_prefix = kwargs.get('subject_prefix', '') try: admin_addr = app_config['MAIL_DEFAULT_ADDR'] admin_name = app_config['MAIL_DEFAULT_SENDER'] except KeyError as e: mes = "MAIL Settings not found" mes = printException(mes, 'error', e) return (False, mes) from_address = kwargs.get('from_address', admin_addr) from_sender = kwargs.get('from_sender', admin_name) reply_to = kwargs.get('reply_to', from_address) subject = subject_prefix + ' ' + kwargs.get( 'subject', 'A message from {}'.format(from_sender)) if not text_template and not html_template and not body: mes = "No message body was specified" printException(mes, "error") return (False, mes) if not to_address_list or len(to_address_list) == 0: #no valid address, so send it to the admin to_address_list = [ (admin_name, admin_addr), ] with mail.record_messages() as outbox: sent_cnt = 0 err_cnt = 0 err_list = [] result = True for who in to_address_list: #import pdb;pdb.set_trace() name = "" address = "" body_err_head = "" if type(who) is tuple: if len(who) == 1: # extend whp who = who[0] + (who[0], ) name = who[0] address = who[1] else: address = who #assume its a str name = who if not looksLikeEmailAddress(address) and looksLikeEmailAddress( name): # swap values temp = address address = name name = temp if not looksLikeEmailAddress(address): # still not a good address... address = admin_addr name = admin_name if not body: body = "" body_err_head = "Bad Addres: {}\r\r".format(who, ) subject = render_template_string(subject.strip(), context=context) #Start a message msg = Message(subject, sender=(from_sender, from_address), recipients=[(name, address)]) #Get the text body verson if body: if body_is_html: msg.html = render_template_string("{}{}".format( body_err_head, body, ), context=context) else: msg.body = render_template_string("{}{}".format( body_err_head, body, ), context=context) if html_template: msg.html = render_template(html_template, context=context) if text_template: msg.body = render_template(text_template, context=context) msg.reply_to = reply_to try: mail.send(msg) sent_cnt += 1 except Exception as e: mes = "Error Sending email" printException(mes, "error", e) err_cnt += 1 err_list.append("Error sending message to {} err: {}".format( who, str(e))) # End Loop if sent_cnt == 0: mes = "No messages were sent." result = False else: mes = "{} messages sent successfully.".format(sent_cnt) if err_cnt > 0: mes = mes + " {} messages had errors.\r\r{}".format( err_cnt, err_list) return (result, mes)