{"id":25,"date":"2024-11-01T03:41:08","date_gmt":"2024-11-01T03:41:08","guid":{"rendered":"https:\/\/smtprelay.monster\/blog\/?p=25"},"modified":"2026-04-09T12:55:25","modified_gmt":"2026-04-09T12:55:25","slug":"a-complete-guide-to-setting-up-mail-tracking-in-coldemailingjet","status":"publish","type":"post","link":"https:\/\/smtprelay.monster\/blog\/a-complete-guide-to-setting-up-mail-tracking-in-coldemailingjet\/","title":{"rendered":"A Complete Guide to Setting Up Mail Tracking in ColdEmailingJet"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\"><\/h1>\n\n\n\n<p>Mail tracking is a vital component of cold emailing, providing valuable insights into recipient engagement. ColdEmailingJet gives you the tools to embed tracking information into your emails, but you are responsible for setting up your own tracking infrastructure. This guide walks you through the entire process.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How Mail Tracking Works<\/h2>\n\n\n\n<p>ColdEmailingJet <strong>does not<\/strong> host tracking infrastructure. Instead, it embeds tracking data (like recipient email addresses) into your email links. You set up your own tracking server (Cloudflare Worker + D1 database) to capture and log recipient interactions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Complete Flow<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>1. You set up Cloudflare Worker + D1 Database\n2. ColdEmailingJet inserts {email.email} tag into your tracking links\n3. Email sent \u2192 Recipient clicks link \u2192 Request hits YOUR Worker\n4. Worker logs data (email, IP, country, user agent) to D1 database\n5. Worker serves age verification page (bot detection)\n6. Human passes verification \u2192 Redirected to final offer page<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Part 1: Setting Up Cloudflare Worker &amp; D1 Database<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Create a D1 Database<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Log into your <strong>Cloudflare Dashboard<\/strong><\/li>\n\n\n\n<li>Navigate to <strong>Workers &amp; Pages<\/strong> \u2192 <strong>D1<\/strong><\/li>\n\n\n\n<li>Click <strong>Create Database<\/strong><\/li>\n\n\n\n<li>Name it (e.g., <code>tracking_db<\/code>)<\/li>\n\n\n\n<li>Click <strong>Create<\/strong><\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Create the Database Table<\/h3>\n\n\n\n<p>Run this SQL in your D1 console:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE TABLE email_events (\n    id INTEGER PRIMARY KEY AUTOINCREMENT,\n    email TEXT,\n    ip TEXT,\n    country TEXT,\n    user_agent TEXT,\n    language TEXT,\n    created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n);<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Create a Cloudflare Worker<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Go to <strong>Workers &amp; Pages<\/strong> \u2192 <strong>Create Application<\/strong> \u2192 <strong>Create Worker<\/strong><\/li>\n\n\n\n<li>Name your worker (e.g., <code>tracking-worker<\/code>)<\/li>\n\n\n\n<li>Click <strong>Deploy<\/strong> then <strong>Edit Code<\/strong><\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Worker Code<\/h3>\n\n\n\n<p>Here&#8217;s a complete worker that:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Captures email from URL parameters<\/li>\n\n\n\n<li>Logs IP, country, user agent, and language<\/li>\n\n\n\n<li>Serves an age verification page<\/li>\n\n\n\n<li>Detects bots before redirecting<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>export default {\n  async fetch(request, env, ctx) {\n    try {\n      const url = new URL(request.url);\n      const pathname = url.pathname;\n\n      if (request.method !== \"GET\") {\n        return new Response(\"Method not allowed\", { status: 405 });\n      }\n\n      \/\/ Extract email from URL parameters\n      const email = url.searchParams.get(\"email\") || \n                    url.searchParams.get(\"addr\") || \n                    url.searchParams.get(\"mail\") || \n                    \"no_email\";\n\n      \/\/ Tracking endpoint - logs data and redirects\n      if (pathname === \"\/track\") {\n        if (isValidEmail(email)) {\n          const ip = request.headers.get(\"CF-Connecting-IP\") ||\n                     request.headers.get(\"x-forwarded-for\") || \"unknown\";\n          const userAgent = request.headers.get(\"user-agent\") || \"unknown\";\n          const country = request.headers.get(\"CF-IPCountry\") || \"unknown\";\n          const language = request.headers.get(\"Accept-Language\")?.split(',')&#91;0] || \"unknown\";\n\n          \/\/ Save to D1 database (async, don't block redirect)\n          ctx.waitUntil(\n            env.DB.prepare(\n              `INSERT INTO email_events (email, ip, country, user_agent, language)\n               VALUES (?, ?, ?, ?, ?)`\n            ).bind(email, ip, country, userAgent, language).run()\n          );\n        }\n\n        \/\/ Redirect to final destination\n        return Response.redirect(\"https:\/\/your-final-offer-page.com\", 302);\n      }\n\n      \/\/ Age verification landing page\n      const object = await env.R2html.get(\"landing_page.html\");\n      if (!object) {\n        return new Response(\"Page not found\", { status: 404 });\n      }\n\n      let html = await object.text();\n      html = html.replace(\/{{EMAIL}}\/g, escapeHtml(email));\n\n      return new Response(html, {\n        headers: { \"Content-Type\": \"text\/html; charset=utf-8\" }\n      });\n\n    } catch (err) {\n      return new Response(\"Error: \" + err.message, { status: 500 });\n    }\n  }\n};\n\nfunction isValidEmail(email) {\n  return \/^&#91;^\\s@]+@&#91;^\\s@]+\\.&#91;^\\s@]+$\/.test(email);\n}\n\nfunction escapeHtml(str) {\n  return str.replace(\/&#91;&amp;&lt;&gt;]\/g, function(m) {\n    if (m === '&amp;') return '&amp;amp;';\n    if (m === '&lt;') return '&amp;lt;';\n    if (m === '&gt;') return '&amp;gt;';\n    return m;\n  });\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Bind D1 Database to Worker<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Go to your Worker \u2192 <strong>Settings<\/strong> \u2192 <strong>Variables<\/strong><\/li>\n\n\n\n<li>Under <strong>D1 Database Bindings<\/strong>, click <strong>Add binding<\/strong><\/li>\n\n\n\n<li>Variable name: <code>DB<\/code><\/li>\n\n\n\n<li>Select your D1 database<\/li>\n\n\n\n<li>Click <strong>Save<\/strong><\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Step 6: Upload HTML Landing Page to R2<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create an R2 bucket (e.g., <code>tracking-assets<\/code>)<\/li>\n\n\n\n<li>Upload your <code>landing_page.html<\/code> file<\/li>\n\n\n\n<li>Bind R2 to your Worker as <code>R2html<\/code><\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Part 2: Bot Detection on Landing Page<\/h2>\n\n\n\n<p>Your HTML landing page should verify the user is human before redirecting. Here&#8217;s the key logic:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Bot Detection Techniques<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Technique<\/th><th>How It Works<\/th><\/tr><\/thead><tbody><tr><td><strong>Mouse Movement Detection<\/strong><\/td><td>Button only enables after mouse\/touch interaction<\/td><\/tr><tr><td><strong>Countdown Timer<\/strong><\/td><td>Forces a 3-5 second wait (bots rarely wait)<\/td><\/tr><tr><td><strong>Hidden Trap Link<\/strong><\/td><td>Bot that crawls all links gets caught<\/td><\/tr><tr><td><strong>Shadow DOM<\/strong><\/td><td>Hides verification logic from simple scrapers<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Sample Landing Page Structure<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;Age Verification&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;img id=\"previewImage\"&gt;\n    &lt;h1&gt;You must be 18+ to enter&lt;\/h1&gt;\n    &lt;div id=\"buttonContainer\"&gt;&lt;\/div&gt;\n    &lt;a href=\"\/trap\" style=\"display:none\"&gt;Hidden trap for bots&lt;\/a&gt;\n\n    &lt;script&gt;\n        const email = \"{{EMAIL}}\";\n        let humanDetected = false;\n        let countdownFinished = false;\n\n        \/\/ Detect human interaction\n        window.addEventListener(\"mousemove\", () =&gt; markHuman(), { once: true });\n        window.addEventListener(\"touchstart\", () =&gt; markHuman(), { once: true });\n        window.addEventListener(\"keydown\", () =&gt; markHuman(), { once: true });\n\n        function markHuman() {\n            humanDetected = true;\n            enableButtonIfReady();\n        }\n\n        \/\/ Countdown timer\n        let countdown = 3;\n        const interval = setInterval(() =&gt; {\n            countdown--;\n            if (countdown &lt;= 0) {\n                clearInterval(interval);\n                countdownFinished = true;\n                enableButtonIfReady();\n            }\n            button.textContent = `Wait ${countdown}s`;\n        }, 1000);\n\n        function enableButtonIfReady() {\n            if (humanDetected &amp;&amp; countdownFinished) {\n                button.disabled = false;\n                button.textContent = \"ENTER\";\n                button.onclick = () =&gt; {\n                    window.location.href = `\/track?email=${encodeURIComponent(email)}`;\n                };\n            }\n        }\n    &lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Part 3: Configuring Tracking Links in ColdEmailingJet<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Create Your Tracking Link Template<\/h3>\n\n\n\n<p>In your email content, insert tracking links using the <code>{email.email}<\/code> tag:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;your-worker.yourdomain.com\/track?email={email.email}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Using Different URL Parameters<\/h3>\n\n\n\n<p>ColdEmailingJet supports multiple parameter names:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Parameter<\/th><th>Usage<\/th><\/tr><\/thead><tbody><tr><td><code>?email=<\/code><\/td><td>Standard email parameter<\/td><\/tr><tr><td><code>?addr=<\/code><\/td><td>Alternative parameter name<\/td><\/tr><tr><td><code>?mail=<\/code><\/td><td>Another alternative<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;your-worker.com\/track?addr={email.email}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Adding Custom Fields<\/h3>\n\n\n\n<p>You can also include custom fields from your contact list:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;your-worker.com\/track?email={email.email}&amp;name={email.FirstName}&amp;campaign=camp_123<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Where to Put the Tracking Link<\/h3>\n\n\n\n<p>Place the tracking link in your email content:<\/p>\n\n\n\n<p><strong>HTML Email Example:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;a href=\"https:\/\/your-worker.com\/track?email={email.email}\"&gt;\n    Click Here to Claim Your Offer\n&lt;\/a&gt;<\/code><\/pre>\n\n\n\n<p><strong>Text Email Example:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Claim your offer: https:\/\/your-worker.com\/track?email={email.email}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Part 4: Testing Your Setup<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Test the Complete Flow<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Send a test email<\/strong> to yourself<\/li>\n\n\n\n<li><strong>Click the tracking link<\/strong> in the email<\/li>\n\n\n\n<li><strong>Verify the database record<\/strong> appears in your D1 database:<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT * FROM email_events ORDER BY created_at DESC LIMIT 10;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Expected Results<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Step<\/th><th>Expected Behavior<\/th><\/tr><\/thead><tbody><tr><td>Link click<\/td><td>Worker logs IP, email, country to D1<\/td><\/tr><tr><td>Landing page<\/td><td>Shows age verification with countdown<\/td><\/tr><tr><td>Human verification<\/td><td>Button enables after mouse move + timer<\/td><\/tr><tr><td>Final click<\/td><td>Redirects to your offer page<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Summary Checklist<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Task<\/th><th>Done<\/th><\/tr><\/thead><tbody><tr><td>Create Cloudflare D1 database<\/td><td>\u2610<\/td><\/tr><tr><td>Create database table<\/td><td>\u2610<\/td><\/tr><tr><td>Create Cloudflare Worker<\/td><td>\u2610<\/td><\/tr><tr><td>Deploy worker code<\/td><td>\u2610<\/td><\/tr><tr><td>Bind D1 to worker<\/td><td>\u2610<\/td><\/tr><tr><td>Upload landing page to R2<\/td><td>\u2610<\/td><\/tr><tr><td>Bind R2 to worker<\/td><td>\u2610<\/td><\/tr><tr><td>Add bot detection to landing page<\/td><td>\u2610<\/td><\/tr><tr><td>Insert <code>{email.email}<\/code> tag in ColdEmailingJet links<\/td><td>\u2610<\/td><\/tr><tr><td>Test with real email<\/td><td>\u2610<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Key Takeaways<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>ColdEmailingJet<\/strong> only embeds tracking data into links &#8211; it does NOT host tracking<\/li>\n\n\n\n<li><strong>You<\/strong> must set up Cloudflare Worker + D1 database to capture clicks<\/li>\n\n\n\n<li><strong>Bot detection<\/strong> requires mouse\/touch events and countdown timers on your landing page<\/li>\n\n\n\n<li>Use <code>{email.email}<\/code> tag to insert recipient addresses into your tracking links<\/li>\n<\/ul>\n\n\n\n<p>With this setup, you have complete control over your tracking data while ColdEmailingJet handles the email delivery and personalization.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mail tracking is a vital component of cold emailing, providing valuable insights into recipient engagement. ColdEmailingJet gives you the tools to embed tracking information into your emails, but you are responsible for setting up your own tracking infrastructure. This guide walks you through the entire process. How Mail Tracking Works ColdEmailingJet does not host tracking &#8230; <a title=\"A Complete Guide to Setting Up Mail Tracking in ColdEmailingJet\" class=\"read-more\" href=\"https:\/\/smtprelay.monster\/blog\/a-complete-guide-to-setting-up-mail-tracking-in-coldemailingjet\/\" aria-label=\"Read more about A Complete Guide to Setting Up Mail Tracking in ColdEmailingJet\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-25","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/smtprelay.monster\/blog\/wp-json\/wp\/v2\/posts\/25","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/smtprelay.monster\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/smtprelay.monster\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/smtprelay.monster\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/smtprelay.monster\/blog\/wp-json\/wp\/v2\/comments?post=25"}],"version-history":[{"count":8,"href":"https:\/\/smtprelay.monster\/blog\/wp-json\/wp\/v2\/posts\/25\/revisions"}],"predecessor-version":[{"id":2499,"href":"https:\/\/smtprelay.monster\/blog\/wp-json\/wp\/v2\/posts\/25\/revisions\/2499"}],"wp:attachment":[{"href":"https:\/\/smtprelay.monster\/blog\/wp-json\/wp\/v2\/media?parent=25"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/smtprelay.monster\/blog\/wp-json\/wp\/v2\/categories?post=25"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/smtprelay.monster\/blog\/wp-json\/wp\/v2\/tags?post=25"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}