In this article i will explain, how to track an Email if it is opened or read by the user.We can achieve this by sending a small beacon image with the Email.
Introduction
We will send an Email by embedding a blank image with a key.We will implement a HttpModule so that when a user opens the Email,then it will request for the original image and we will send it back.At that time we will record that request and save it in Database or log it for our reference to check at what time and how many times the email is opened.
Creating Application
Lets create a web application.
Open Visual Studio.Select File >> New >> Website
Select Visual C# on left pane and select ASP.NET Empty Web Site on right pane.
Select Web Location at the bottom and select path folder by giving a name to the application, I'm giving 'EmailTracking' as application name.
Click OK and your new empty web application solution is created.
Sending Email
Add web form with the name EmailTracking
We will add a button to the web form to send an email and a label to display messages.
Add some style to the button,so that it looks better
on button click,we will write the code to send an email.In the Email, we will attach an image.
<asp:button onclick="btnTestEmail_Click" id="btnTestEmail" runat="server" text="Test Email Tracking" cssclass="greenbtn" />
string subject = "This is test mail";
string toEmail = "receiver@codeview.in";//receiver email adrress
string fromEmail = "sender@codeview.in";//sender email adrress
string content = "Hello User, <br><br>";
content += "This is a test Email<br><br>";
content += "Thank you for visiting www.codeview.in \n <br><br>";
content += @"<img src=""http://localhost:53028/images/<keyvalue>.aspx"" />";//your own url
string keyValue = "codeview"; //generate unique key here
content = content.Replace("<keyvalue>", keyValue);
new Utility().SendEmail(fromEmail, toEmail, subject, content, true);
lbl.Text = "Mail Sent Successfully";
lbl.ForeColor = System.Drawing.Color.Green;
In the above code,I’m generating a unique key and requesting for an codeview.aspx file from the images folder for the image src, where it doesn't even exist.Then, instead of returning a 404 or file not found error, we will send back the image which we we already got using HttpModule.
Here is the complete code of EmailTracking.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="EmailTracking.aspx.cs" Inherits="EmailTracking" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<style>
.greenbtn {
color: #FFFFFF;
background-color: #0b7348;
border: 1px solid transparent;
white-space: nowrap;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnTestEmail" runat="server" Text="Test Email Tracking" CssClass="greenbtn"
OnClick="btnTestEmail_Click" />
<asp:Label ID="lbl" runat="server"/>
</div>
</form>
</body>
</html>
using System;
public partial class EmailTracking : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnTestEmail_Click(object sender, EventArgs e)
{
try
{
string subject = "This is test mail";
string toEmail = "receiver@codeview.in";//receiver email adrress
string fromEmail = "sender@codeview.in";//sender email adrress
string content = "Hello User, <br><br>";
content += "This is a test Email<br><br>";
content += "Thank you for visiting www.codeview.in \n <br><br>";
content += @"<img src=""http://localhost:53028/images/<keyvalue>.aspx"" />";//your own url
string keyValue = "codeview"; //generate unique key here
content = content.Replace("<keyvalue>", keyValue);
new Utility().SendEmail(fromEmail, toEmail, subject, content, true);
lbl.Text = "Mail Sent Successfully";
lbl.ForeColor = System.Drawing.Color.Green;
}
catch (Exception ex)
{
lbl.Text = ex.Message;
lbl.ForeColor = System.Drawing.Color.Red;
}
}
}
Adding HTTP Module
Right click on solution folder and add an App_Code folder
Right click on App_Code folder and add a new class file with name 'ImageTracker'
Add the below lines of code, so that you class file should look like the same
using System;
using System.Web;
///
/// Summary description for ImageTracker
///
public class ImageTracker : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
}
}
In the Init() method, we will register the event GetImage_BeginRequest(). Now,Our code will change to
public void Init(HttpApplication context)
{
context.BeginRequest += new System.EventHandler(GetImage_BeginRequest);
}
public void GetImage_BeginRequest(object sender, System.EventArgs args)
{
}
Now we will register the HttpModule to the web.config:
<system.webserver>
<modules>
<add type="ImageTracker" name="ImageTracker" />
</modules>
</system.webserver>
Now in GetImage_BeginRequest(), we will add our code to validate and return the image, which should look like this
public void GetImage_BeginRequest(object sender, System.EventArgs args)
{
//cast the sender to a HttpApplication object
System.Web.HttpApplication application = (System.Web.HttpApplication)sender;
string url = application.Request.Path; //get the url path
string pattern = @"/images/(?<key>.*)\.aspx";
//create the regex to match for beacon images
Regex r = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (r.IsMatch(url))
{
MatchCollection mc = r.Matches(url);
if ((mc != null) && (mc.Count > 0))
{
string key = (mc[0].Groups["key"].Value);
//SaveToDB(key);
new Utility().writeLog("Mail Read - " + key + " : " + DateTime.Now.ToString());
}
//now send the REAL image to the client
application.Response.ContentType = "image/gif";
application.Response.WriteFile(application.Request.MapPath(logo));//logoFile is defined above
//end the response
application.Response.End();
}
}
Add an Images folder to the solution and add the logo to that which we need to send.Add a notepad also to the solution,so that we can log.
Here is the complete code
using System;
using System.Text.RegularExpressions;
using System.Web;
/// <summary>
/// Summary description for ImageTracker
/// </summary>
public class ImageTracker : IHttpModule
{
string logo = "~/images/codeview.png";
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new System.EventHandler(GetImage_BeginRequest);
}
public void GetImage_BeginRequest(object sender, System.EventArgs args)
{
//cast the sender to a HttpApplication object
System.Web.HttpApplication application = (System.Web.HttpApplication)sender;
string url = application.Request.Path; //get the url path
string pattern = @"/images/(?<key>.*)\.aspx";
//create the regex to match for beacon images
Regex r = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (r.IsMatch(url))
{
MatchCollection mc = r.Matches(url);
if ((mc != null) && (mc.Count > 0))
{
string key = (mc[0].Groups["key"].Value);
//SaveToDB(key);
new Utility().writeLog("Mail Read - " + key + " : " + DateTime.Now.ToString());
}
//now send the REAL image to the client
application.Response.ContentType = "image/gif";
application.Response.WriteFile(application.Request.MapPath(logo));
//end the response
application.Response.End();
}
}
}
Output
As our complete code is ready now,lets send an email to test.
When the Email is opened, then from the image src 'http://localhost:53028/images/codeview.aspx' a request is made to our application and GetImage_BeginRequest() is called. In that we will validate for the file type and our Regular Expression will grab the key name which is 'codeview'. That key is then used to save in our database file.Here rather than saving, i will log them in a text file with key name and time. Once the tracking is completed we will send our own logo.
This will work on all major Email clients.Tested on Yahoo,Gmail and MSN. In Gmail, it will work only if you place the image in a public domain folder.
Hope this article is clear enough.Feel free to comment below if you got any doubts.
Reference : www.aspnetemail.com