Build an Email Tracker App with Flask & Telegram | Get Instant Email Read Notifications on Telegram
raunit - in OthersCreate an email tracker app using Flask to send read notifications to Telegram. Learn Base64 decoding, IP-based location tracking, and how to deploy with Docker effortlessly.
In this tutorial, we'll walk through building an email tracker app using Flask, where you can track when an email is opened and get instant Telegram notifications about it.
Link to the Github repository is provided below.1. Setting Up Your Flask Application
We begin by creating a Flask application. Flask is a lightweight Python web framework that helps us create the API for our email tracking system. Install Flask using:
pip install flask PyYAML requestsor
pip install -r requirements.txt
2. Decoding the Base64-encoded Email
Advantages of Base64 Encoding:
- Obfuscation: It hides the email address from direct view in the URL, making it harder for casual observers or crawlers to detect the email.
- Prevents Direct Harvesting: Since the email is encoded, it is harder for automated scrapers to collect email addresses directly from your URLs.
Disadvantages:
- Easily Reversible: Base64 encoding is not a secure method. Anyone with access to the URL or a slight knowledge of Base64 encoding can decode it back to the original email address without any effort.
- No Privacy Protection: Since Base64 is not encryption, it offers no real privacy for the email address itself. If the tracker is intercepted or monitored, the email address can easily be decoded.
Better Approaches for Protecting Email:
- Easily Reversible: Base64 encoding is not a secure method. Anyone with access to the URL or a slight knowledge of Base64 encoding can decode it back to the original email address without any effort.
- No Privacy Protection: Since Base64 is not encryption, it offers no real privacy for the email address itself. If the tracker is intercepted or monitored, the email address can easily be decoded.
Better Approaches for Protecting Email:
If you want to protect the email address and prevent it from being exposed, consider using one of the following methods:
1. URL Hashing
Instead of encoding the email address, you can hash it using a secure hashing algorithm like SHA-256. This way, the email is not stored or exposed in any way, but you can still track it uniquely.
https://yourdomain.com/track/hashed-email
This method ensures that the email is not directly visible in the URL but still allows for unique tracking.
2. Use Tokens
You can generate a token for each email and store the actual email in a secure database. The URL can then include the token, and upon receiving the request, you map the token back to the email.
https://yourdomain.com/track/<token>
The token is securely stored in your database, and only the server knows which email corresponds to which token.
3. JWT (JSON Web Token)
For added security, you could use JWT to encode the email along with some metadata, but it’s important to ensure the JWT is signed to prevent tampering.
Conclusion:
Base64 encoding is better than nothing but should not be relied on for privacy or security. It’s mostly for obfuscation, not protection. If you are serious about protecting the email address and improving privacy, it's better to use more secure techniques like tokenization or hashing.
email = base64.b64decode(email_id).decode('utf-8') if not is_valid_email(email): return jsonify({"error": "Invalid email address"}), 400
3. Tracking the IP Address and Location
Once the email is opened, we can retrieve the IP address from the X-Forwarded-For header, which gives us the real IP of the user who opened the email. Using the ipinfo.io API, we fetch the location details.
response = requests.get(f'https://ipinfo.io/{ip_address}/json') location_data = response.json()
4. Sending Telegram Notifications
After gathering location data, we'll send a Telegram notification using the Telegram Bot API. This allows you to get real-time notifications on your Telegram channel whenever someone opens your email.
message = f"📧 Email Opened!\\nEmail ID: {decoded_email}\\nIP Address: {ip_address}" response = requests.post(url, json=data)
5. Creating the Tracking Pixel
Finally, we create a tiny 1x1 pixel GIF that acts as a tracker. This pixel is embedded in the email. When the email is opened, the browser will make a request to your server, triggering the tracking logic.
pixel.write(b'\x47\x49\x46\x38\x39\x61...') # 1x1 pixel GIF
6. Deploying Your App with Docker
The Dockerfile is also provided in the github repo. To make your email tracker app production-ready, we can containerize it using Docker. Here's a simple Dockerfile for your Flask app:
FROM python:3.9.6-slim RUN pip install -r requirements.txt COPY . /app WORKDIR /app CMD ["python", "app.py"]
Conclusion
You now have a fully functional email tracker app that sends notifications to Telegram when an email is opened. By using Flask, Telegram Bot API, and Docker, you can easily deploy and scale this application. You can use Render.com to deploy it for free or some other hosting service. Happy tracking!
How to Get Your Telegram Chat ID
To send messages to your Telegram chat from your bot, you need to know your Telegram Chat ID. Here’s how you can find it:
- First, start a conversation with your bot on Telegram.
- Use this URL to get your chat ID from your Telegram bot: https://api.telegram.org/bot<your-bot-token>/getUpdates Replace `<your-bot-token>` with the actual token you received from BotFather.
- Once you visit the URL, it will return a JSON response. Look for the `chat` object, and find the `id` field. This is your chat ID.
- Alternatively, you can use a Telegram bot like `@userinfobot` to directly get your chat ID by typing `/start` in the bot’s chat.
Example Response
Here’s an example of what the response might look like when you visit the `getUpdates` URL:
{
"ok": true,
"result": [
{
"update_id": 123456789,
"message": {
"message_id": 1,
"from": {
"id": 987654321,
"is_bot": false,
"first_name": "John",
"last_name": "Doe",
"username": "johndoe",
"language_code": "en"
},
"chat": {
"id": 123456789,
"first_name": "John",
"last_name": "Doe",
"username": "johndoe",
"type": "private"
},
"date": 1617026852,
"text": "Hello, bot!"
}
}
]
}
In this example, the `chat id` is 123456789. You can use this value in your mail tracker app now.
import base64
import os
import re
from datetime import datetime
from io import BytesIO
import requests
import yaml
from flask import Flask, send_file, request, jsonify
app = Flask(__name__)
EMAIL_REGEX = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
TELEGRAM_BOT_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN')
TELEGRAM_CHAT_ID = os.environ.get('TELEGRAM_CHAT_ID')
def is_valid_email(email):
return re.match(EMAIL_REGEX, email) is not None
def create_tracking_pixel():
pixel = BytesIO()
pixel.write(
b'\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\x00\x00\x00\x21\xf9\x04\x01\x00\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3b')
pixel.seek(0)
return pixel
def send_telegram_notification(email_id, ip_address, location_data):
url = f'https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage'
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
message = (
f"📧 Email Opened!\n"
f"Email ID: {email_id}\n"
f"IP Address: {ip_address}\n"
f"Time: {timestamp}"
f"\n\nLocation Data: {location_data}"
)
data = {
'chat_id': TELEGRAM_CHAT_ID,
'text': message,
'parse_mode': 'HTML'
}
try:
response = requests.post(url, json=data)
return response.json()
except Exception as e:
print(f"Error sending Telegram notification: {e}")
return None
@app.route('/<email_id>')
def track_email(email_id):
decoded_email = ""
try:
email = base64.b64decode(email_id).decode('utf-8')
decoded_email = email
if not is_valid_email(decoded_email):
return jsonify({"error": "Invalid email address"}), 400
except Exception as e:
return jsonify({"error": "Invalid email address"}), 400
ip_address = request.headers.get('X-Forwarded-For', request.remote_addr)
location_data = {}
try:
response = requests.get(f'https://ipinfo.io/{ip_address}/json')
if response.status_code == 200:
data = response.json()
location_data = {
"IP": ip_address,
"City": data.get("city", "Unknown"),
"Region": data.get("region", "Unknown"),
"Country": data.get("country", "Unknown"),
"Postal Code": data.get("postal", "Unknown"),
"Coordinates": data.get("loc", "Unknown"),
"ISP": data.get("org", "Unknown"),
"Time Zone": data.get("timezone", "Unknown"),
}
except Exception as e:
print(f"Error fetching location: {e}")
location_data_yaml = yaml.dump(location_data, default_flow_style=False)
send_telegram_notification(decoded_email, ip_address, location_data_yaml)
tracking_pixel = create_tracking_pixel()
return send_file(
tracking_pixel,
mimetype='image/gif',
as_attachment=False
)
if __name__ == '__main__':
app.run(debug=False, host='0.0.0.0', port=5000)
Sample Video of How It Works
Watch this video to understand how to track who opened your email when and from where.
raunit
Technical Writer at CodingKaro