A Manifest V3 browser-side logging and interaction automation library for Snov.io that detects email elements in real time and converts them into actionable mailto: workflows.
Note
This project is implemented as a Chrome Extension content-script package, but its core runtime behavior functions like a focused DOM interaction/logging library embedded into https://app.snov.io/*.
This tool is part of the AdTech Automation Suite. Check out the companion extension:
| Project | Type | Description |
|---|---|---|
| Snov.io Addon: Blocklist Highlighter | Chrome Extension | Real-time visual flagging of blacklisted or bounced emails |
| Snov.io Addon: Click-to-Compose | Chrome Extension | Instantly converts static email text into clickable mailto: links |
- Features
- Tech Stack & Architecture
- Getting Started
- Testing
- Deployment
- Usage
- Configuration
- License
- Contacts & Community Support
- Real-time DOM scanning for Snov.io email UI nodes (
.long-email-width). - Deterministic click hijacking of static email text into
mailto:handlers. - Built-in lightweight runtime logging via
console.logfor extension activation and click events. - Mutation-aware processing through
MutationObserverfor SPA and async-rendered content. - Duplicate-processing prevention using
data-hijackedtagging on processed nodes. - UX affordances for interactable nodes:
- Pointer cursor for clickable discoverability.
- Consistent branded accent color (
#6d53de). - Contextual hover title with recipient preview.
- Strict host scoping to
https://app.snov.io/*to reduce permission surface. - Zero external runtime dependencies (plain JavaScript content script).
- Chrome Extension Manifest V3 compatibility.
- Internal-tooling-friendly architecture with predictable load timing (
document_end).
Tip
Because processing is idempotent (dataset.hijacked guard), the observer can run continuously without repeatedly binding listeners to the same element.
- Language: JavaScript (ES6+ syntax in browser context).
- Platform: Google Chrome Extension APIs via Manifest V3.
- Runtime Model: Content script injection on matching host patterns.
- Browser APIs:
document.querySelectorAllMutationObserverwindow.location.href(mailto:redirect)HTMLElement.dataset, inline style mutation, and event listeners
Snov.io-addon_2/
├── content.js # Core library logic: detection, hijacking, observer loop, click logging
├── manifest.json # Extension metadata, host permissions, content script registration
├── icons/
│ └── icon128.png # Extension icon asset
├── LICENSE # Apache 2.0 license
└── README.md # Project documentation
-
Content-script-only architecture
- Keeps execution close to target DOM.
- Eliminates background-message complexity for this use case.
-
Mutation-driven refresh strategy
- Supports dynamic Snov.io views where nodes arrive after initial page load.
- Avoids brittle one-time initialization patterns.
-
Debounced reprocessing (
setTimeout)- Coalesces multiple rapid DOM mutations into one pass.
- Reduces unnecessary query work in high-change interfaces.
-
Element-level idempotency marker
- Uses
data-hijacked="true"to prevent duplicate handlers. - Keeps algorithm predictable even under frequent rerenders.
- Uses
-
Protocol-native integration (
mailto:)- Delegates compose experience to user’s default mail client.
- Avoids third-party API coupling.
flowchart TD
A[Page load at app.snov.io] --> B[content.js injected at document_end]
B --> C[hijackEmailText scans .long-email-width nodes]
C --> D{Element already data-hijacked?}
D -- Yes --> E[Skip]
D -- No --> F[Validate text contains @]
F --> G[Apply clickable styles and title]
G --> H[Attach capture click listener]
H --> I[Mark data-hijacked=true]
I --> J[User clicks email element]
J --> K[Log click event to console]
K --> L[Redirect to mailto:address]
B --> M[MutationObserver watches body subtree]
M --> N[Debounced re-run of hijackEmailText]
N --> C
Important
The extension intentionally intercepts click behavior (preventDefault and stopPropagation) in capture mode to ensure consistent compose handoff from complex nested UI widgets.
- Google Chrome (or Chromium-based browser supporting Manifest V3).
- Git (for cloning the repository).
- Optional for local quality checks:
- Node.js 18+
- npm 9+
- Clone the repository:
git clone https://github.com/OstinUA/Snov.io-addon_2.git
cd Snov.io-addon_2- Load extension in Chrome:
chrome://extensions/ -> enable Developer mode -> Load unpacked -> select this folder
- Open
https://app.snov.io/and verify behavior:- Email text elements become clickable.
- Click opens default mail client compose window.
Warning
This extension only activates on https://app.snov.io/*. It will not execute on other domains.
This repository does not ship a formal unit/integration test harness yet, but the following commands provide a practical validation baseline.
# JavaScript syntax validation (built-in)
node --check content.js
# Optional linting (requires Node.js + npm)
npx eslint content.js
# Optional extension manifest linting
npx web-ext lint --source-dir .- Reload the unpacked extension in
chrome://extensions/. - Open
https://app.snov.io/. - In DevTools Console, confirm startup log:
Snov Email-Click: Active
- Click a transformed email node and verify:
- Console event log is emitted.
mailto:compose flow is triggered.
For CI pipelines (GitHub Actions, GitLab CI, Jenkins), run:
node --check content.js
npx eslint content.js
npx web-ext lint --source-dir .This project is deployed as an unpacked internal extension or packaged Chrome extension artifact.
- Distribute repository folder to internal users.
- Users load via Chrome Developer Mode (
Load unpacked). - Update by pulling latest Git commit and reloading extension.
- Use Chrome extension packaging tooling to build
.crx(for controlled internal channels). - Keep
manifest.jsonversion updated for release tracking.
- Trigger quality gates on pull requests (
node --check, lint, manifest validation). - Enforce semantic version bump in
manifest.jsonfor release PRs. - Archive release artifacts with commit hash and extension version metadata.
Caution
If you add broader host permissions in future releases, perform a security review before publishing or distributing internally.
// Detect target email nodes
const emailElements = document.querySelectorAll('.long-email-width');
emailElements.forEach((emailEl) => {
if (emailEl.dataset.hijacked) return; // Skip already processed elements
const emailText = emailEl.innerText.trim();
if (!emailText.includes('@')) return; // Basic guard for email-like values
emailEl.style.cursor = 'pointer';
emailEl.style.color = '#6d53de';
emailEl.title = `Write email: ${emailText}`;
emailEl.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
console.log(`Email clicked -> Mailto: ${emailText}`);
window.location.href = `mailto:${emailText}`; // Delegate to OS/client mail handler
}, true);
emailEl.dataset.hijacked = 'true';
});let timeout;
const observer = new MutationObserver(() => {
clearTimeout(timeout);
timeout = setTimeout(hijackEmailText, 500); // Debounced rescanning on DOM churn
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
hijackEmailText(); // Initial pass- Install extension in Developer Mode.
- Navigate to Snov.io lead/contact views.
- Click converted email values to initiate compose immediately.
- Use browser console logs for quick behavioral diagnostics.
| Field | Description | Current Value |
|---|---|---|
manifest_version |
Extension manifest standard | 3 |
name |
Display name in browser extensions page | Snov.io addon_2dev |
version |
Release/version identifier | 1.2.0 |
description |
Extension summary | Click the copy icon to instantly compose an email... |
host_permissions |
Allowed origin scope | https://app.snov.io/* |
content_scripts.matches |
Injection URL pattern | https://app.snov.io/* |
content_scripts.run_at |
Script execution timing | document_end |
| Parameter | Location | Purpose | Default |
|---|---|---|---|
| CSS selector | content.js |
Target email text elements | .long-email-width |
| Accent color | content.js |
Visual clickable indication | #6d53de |
| Debounce window | content.js |
Mutation processing delay | 500ms |
| Guard attribute | content.js |
Prevent duplicate listeners | data-hijacked |
This project currently uses no .env variables and no startup CLI flags. Configuration is static and controlled through manifest.json and constants in content.js.
Note
For enterprise-grade configurability, consider introducing build-time environment injection (e.g., selector overrides, debug mode toggles, style theme values).
Licensed under the Apache License 2.0. See LICENSE for the full text.
If you find this tool useful, consider leaving a star on GitHub or supporting the author directly.