Email verification is essential for any app that needs to confirm users control the address they registered with. Here's a complete Flask implementation.
The Flow
- User registers with email
- Generate secure token, store with expiry
- Send confirmation email with token link
- User clicks link → verify token → activate account
Token Generation
import secrets, hashlib
from datetime import datetime, timedelta
def generate_token():
token = secrets.token_urlsafe(32)
expires = datetime.utcnow() + timedelta(hours=24)
return token, expires
def store_token(db, user_id, token, expires):
hashed = hashlib.sha256(token.encode()).hexdigest()
db.execute(
"INSERT INTO email_tokens (user_id, token_hash, expires_at) VALUES (?,?,?)",
(user_id, hashed, expires.isoformat())
)
db.commit()
Sending the Verification Email
from flask_mail import Message
def send_verification(user_email, token):
link = url_for('verify_email', token=token, _external=True)
msg = Message('Confirm your email', recipients=[user_email])
msg.html = f'Click to confirm: {link}
'
mail.send(msg)
Verification Route
@app.route('/verify/')
def verify_email(token):
hashed = hashlib.sha256(token.encode()).hexdigest()
row = db.execute(
"SELECT * FROM email_tokens WHERE token_hash=?", (hashed,)
).fetchone()
if not row:
return "Invalid token", 400
if datetime.fromisoformat(row['expires_at']) < datetime.utcnow():
return "Token expired", 400
db.execute("UPDATE users SET verified=1 WHERE id=?", (row['user_id'],))
db.execute("DELETE FROM email_tokens WHERE token_hash=?", (hashed,))
db.commit()
return redirect('/dashboard')
Security Notes
- Always hash tokens before storing — treat them like passwords
- Set short expiry (24 hours maximum)
- Delete token after successful verification
- Rate-limit resend requests
- Use HTTPS for verification links
Reliable email delivery for verification emails — see ZeroPhantom tools →