Flask API: E-mail Support

Introduction:

The ability to send emails to either the users of your application or to yourself is a very nice feature to have in your web application. This blog post will demonstrate how to incorporate the sending of emails to users when they create a new account. how to confirm users’ email address.

This blog post introduces to the Flask extension called Flask-Mail which make sending email very easy in Flask.

Before we get into the configuration steps, I’d like to point out an optional step: creating a new email address for your web application. I’ve found it very convenient to create a new Gmail email address for each web application that I’m building. This will allow you to have a separate email account, not just your personal email account, for sending out notifications to your users.

At this point, it’s also important to understand what is Flask-mail and what flask-mail do means if you are not already aware of it.

https://flask-mail.readthedocs.io/en/latest/

Now let’s get started with requirements installation

Installing Flask-Mail:

Install with pip:

pip install Flask-Mail 
pip install smtplib

Step 1:Configuring Flask-Mail

Now we setup our default email configuration. we can change this as per requirement.


app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME']='This is sender email'
app.config['MAIL_PASSWORD']= '*********'
app.config['MAIL_USE_TLS']=False
app.config['MAIL_USE_SSL']=True

We also need to initialize anMail object, as this will be the object that will connect to the SMTP server and send the emails for us.

from flask_mail import Mail

app = Flask(__name__)
mail = Mail(app)

we also need to import some more library. which library is used in our code. we used pymongo library because we do this as user verification level.


from flask import Flask,request,abort,jsonify
from flask_mail import Mail,Message
from flask_pymongo import PyMongo , pymongo
from smtplib import SMTP
import uuid

app = Flask(__name__)
mail=Mail(app)
app.config["MONGO_URI"] = "mongodb://localhost:27017/sendmails"
mongo = PyMongo(app)

Step 2:Make route

Set up a Message object in a Python function mapped by URL route (‘/register’).



@app.route("/register",methods=["POST"])
def email_register():
if not request.json:
abort(500)

user_id = uuid.uuid4().hex
name = request.json.get("name")
username = request.json.get("username")
email = request.json.get("email")
password = request.json.get("password")

user = mongo.db.exam_results.insert_one({
"user_id": user_id,
"name":name,
"username": username,
"email": email,
"password": password
}).inserted_id

if email and username and name and password is not None:
msg = Message('You are registered',
sender='[email protected]',recipients=[email])
msg.body = "Confirm your email"
mail.send(msg)
return "you are registered"

return jsonify(str(user))

Note:

Before the run our code we need to do one thing that the built-in security features in Gmail service may block this login attempt. You may have to decrease the security level. Please log in to your Gmail account and visit  https://myaccount.google.com/lesssecureapps  link to decrease the security.

Allow less secure apps:On is default disable do this enable.

Let’s send an email!

we do this by Postman.

and we get a registered mail.

This finishes our basic email api. At this stage, it’s important to sink your head in what you read about and try different things.

Here is the entire final code for reference


from flask import Flask,request,abort,jsonify
from flask_mail import Mail,Message
from flask_pymongo import PyMongo , pymongo
from smtplib import SMTP
import uuid

app = Flask(__name__)
mail=Mail(app)
app.config["MONGO_URI"] = "mongodb://localhost:27017/sendmails"
mongo = PyMongo(app)


app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME']='this is sender email'
app.config['MAIL_PASSWORD']= '*******'
app.config['MAIL_USE_TLS']=False
app.config['MAIL_USE_SSL']=True

Mail = Mail(app)

#Api for registration
@app.route("/register",methods=["POST"])
def email_register():
if not request.json:
abort(500)

user_id = uuid.uuid4().hex
name = request.json.get("name")
username = request.json.get("username")
email = request.json.get("email")
password = request.json.get("password")

user = mongo.db.exam_results.insert_one({
"user_id": user_id,
"name":name,
"username": username,
"email": email,
"password": password
}).inserted_id

if email and username and name and password is not None:
msg = Message('You are registered', sender='[email protected]',recipients=[email])
msg.body = "Confirm your email"
mail.send(msg)
return "you are registered"

return jsonify(str(user))


if __name__ == '__main__':
app.run(debug = True)

Step 3:Update the current app

First, let’s add the fieldconfirmed to our database. And this field default is False.


user = mongo.db.user.insert_one({
"user_id": user_id,
"name":name,
"username": username,
"email": email,
"password": pbkdf2_sha256.hash(password),
"confirmed":False
}).inserted_id

purpose of the add this field is only for registered user verification. if a user clicks on the registration confirmation link then the confirmed field value is updated to true else is still false.

Step 4: Add email confirmation

Generate confirmation

For the generate email confirmation token, we need to import some more library. The email confirmation should contain a unique URL that a user simply needs to click in order to confirm his/her account.


from itsdangerous import URLSafeTimedSerializer,SignatureExpired

here SignatureExpired is import for the exception handling.if token is expired

Step 5: Update register route

we update some changes in our current register code.


@app.route("/register",methods=["POST"])
def email_register():
if not request.json:
abort(500)

user_id = uuid.uuid4().hex
name = request.json.get("name")
username = request.json.get("username")
email = request.json.get("email")
password = request.json.get("password")

user = mongo.db.user.insert_one({
"user_id": user_id,
"name":name,
"username": username,
"email": email,
"password": pbkdf2_sha256.hash(password),
"confirmed":False
}).inserted_id

if email and username is not None:
token = s.dumps(email, salt='email-confirm')
msg = Message('confirm email', sender='[email protected]',recipients=[email])
link = url_for('confirm_email', token=token, _external=True)
msg.body = 'Confirmation link is {}'.format(link)
mail.send(msg)
return "registration confirmation link is send"

return jsonify(str(user))

Step 6: Handle Email Confirmation

Next, let’s add a new route to handle the email confirmation:


@app.route('/confirm_email/<token>')
def confirm_email(token):
try:
email = s.loads(token, salt='email-confirm', max_age=3600)
except SignatureExpired:
return "Token is expired"
user= mongo.db.user.update({"email": email},
{ "$set":{ "confirmed":True}})
return "you are registered"

if __name__ == '__main__':
app.run(debug = True)

Now run the code in windows by this -

set FLASK_APP=file name
flask run

and run in linux/ubuntu

export FLASK_APP=file name
flask run

now lets run the our code .First we register an user.

we register a user and get in response “registration confirmation link is send” . We get a link on registered email.

Now we confirm the our registered email address. For the email confirmation we use our another route ‘/confirm_email/ .

after the link confirmation we get response you are registered.now we check our confirmation status in database.

see here our confirmed status is true.. that means we successfully confirmed our account.

Here is the entire final code for reference .


from flask import Flask,request,abort,jsonify,url_for
from flask_mail import Mail,Message
from flask_pymongo import PyMongo , pymongo
from smtplib import SMTP
import uuid
from bson.json_util import dumps
from itsdangerous import URLSafeTimedSerializer,SignatureExpired
from passlib.hash import pbkdf2_sha256

app = Flask(__name__)
mail=Mail(app)
app.config["MONGO_URI"] = "mongodb://localhost:27017/sendmails"
mongo = PyMongo(app)


app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME']='this is sender email'
app.config['MAIL_PASSWORD']= '*******'
app.config['MAIL_USE_TLS']=False
app.config['MAIL_USE_SSL']=True

Mail = Mail(app)
s = URLSafeTimedSerializer('Thisisecret')


#Api for registration
@app.route("/register",methods=["POST"])
def email_register():
if not request.json:
abort(500)

user_id = uuid.uuid4().hex
name = request.json.get("name")
username = request.json.get("username")
email = request.json.get("email")
password = request.json.get("password")

user = mongo.db.user.insert_one({
"user_id": user_id,
"name":name,
"username": username,
"email": email,
"password": pbkdf2_sha256.hash(password),
"confirmed":False
}).inserted_id

if email and username and name and password is not None:
token = s.dumps(email, salt='email-confirm')
msg = Message('confirm email', sender='[email protected]',recipients=[email])
link = url_for('confirm_email', token=token, _external=True)
msg.body = 'Confirmation link is {}'.format(link)
mail.send(msg)
return "registration confirmation link is send"

return jsonify(str(user))


#Api for email confirmation
@app.route('/confirm_email/<token>')
def confirm_email(token):
try:
email = s.loads(token, salt='email-confirm', max_age=3600)
except SignatureExpired:
return "Token is expired"
user= mongo.db.user.update({"email": email}, { "$set":{ "confirmed":True}})
return "you are registered"

if __name__ == '__main__':
app.run(debug = True)

excellence-social-linkdin
excellence-social-facebook
excellence-social-instagram
excellence-social-skype