Is Mail Seen - Unlimited Email Tracker for Gmail safe?
Mail Seen sends outgoing Gmail message details and body text to its tracking API when you click Send.
When you send a Gmail message, Mail Seen intercepts the Send button click, reads the sender, recipient, subject, timestamp, and compose body text, and adds a tracking pixel to the email. It then posts those details, including the full outgoing body content, to MailSeen's tracking API for paid users and free users under the monthly count threshold.
Who publishes itMobile Internet Limited - no other listings under this identity
Mobile Internet Limited - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Gmail send hook posts outgoing email bodies to MailSeen API
Clicking Send in Gmail, Mail Seen's content script reads the sender, recipient, subject, and body, appends a tracking pixel, and posts JSON to authapi-f6o7ittoia-uc.a.run.app/track2, whose bodyContent field carries the full message text.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You click Send in a Gmail compose window.
The click handler only runs on Gmail pages and matches Gmail's Send button classes.
The extension reads the compose fields, adds a tracking pixel, and sends the message details to its API.
Tracking is on by default when no preference is stored, unless the message contains a Gmail Drive chip.
- Sender accountalex.wu@example.com (illustrative)
Identifies which Gmail account sent the message.
- First recipientfinance-team@example.org (illustrative)
Identifies the first person or mailbox you addressed in the compose window.
- Subject lineQ3 vendor contract review (illustrative)
Shows the topic of the email you are sending.
- Send date2026-07-14 (illustrative)
Places your message in time, which can be tied to the sent email and tracking pixel.
- Tracking IDk8m4pz (illustrative)
Links the API record to the tracking pixel inserted into your outgoing email.
- Email body textHi Priya, attached are the updated payroll notes for review. (illustrative)
Includes the full text you typed in the message body before sending.
- Content-Type
- application/json
Gmail send handler reads compose fields and calls the tracking path
Readable packaged source for the same handler
components/emailTracking.jsfunction initializeEmailTracking() { document.body.addEventListener('click', handleSendButtonClick, true);}// Handle send button click eventfunction handleSendButtonClick(event) { if (event.target.matches('.T-I.J-J5-Ji.aoO.v7.T-I-atl.L3')) { event.preventDefault(); // Extract email using a more generic selector const accountEmailAnchors = Array.from(document.querySelectorAll('a[aria-label]')); let senderEmail = 'Not Found'; for (let anchor of accountEmailAnchors) { const ariaLabel = anchor.getAttribute('aria-label'); const emailMatch = ariaLabel.match(/\(([^\)]+@[^)]+)\)/); // Regex to extract email if (emailMatch) { senderEmail = emailMatch[1]; break; // Break the loop once email is found } } const subjectElement = document.querySelector('input[name="subjectbox"]'); const subject = subjectElement ? subjectElement.value : 'Not Found'; const recipientEmail = extractRecipientEmail(); let bodyElement = document.querySelector('div[contenteditable="true"].Am.Al') || document.querySelector('div.Am.Al.editable') || document.querySelector('div.aO7').firstElementChild; if (bodyElement) { // Check if the body contains the class "gmail_chip gmail_drive_chip" const containsGmailChip = bodyElement.querySelector('.gmail_chip.gmail_drive_chip'); if (containsGmailChip) { // Skip API calls, pixel attachment, and send button click for Gmail attachments } else { const randomId = Math.random().toString(36).substring(2, 8); addTrackingData(senderEmail, recipientEmail, subject, bodyElement, randomId); setTimeout(() => { addNewIndicatorToSent(); event.target.click(); // Only click the send button programmatically if the chip is not found }, 2000); } } }}// Extract recipient email from compose windowfunction extractRecipientEmail() { const emailSpans = document.querySelectorAll('div.oL.aDm.az9 span[email]'); return emailSpans.length > 0 ? emailSpans[0].getAttribute('email') : 'Not Found';}Tracking payload builder appends the pixel and posts bodyContent
Readable packaged source for the same payload path
components/emailTracking.jsfunction addTrackingData(senderEmail, recipientEmail, subject, bodyElement, randomId) { console.log('addTrackingData: Starting function with params:', { senderEmail, recipientEmail, subject, randomId }); const currentDate = new Date().toISOString().split('T')[0]; const encodedSenderEmail = encodeURIComponent(senderEmail); const encodedRecipientEmail = encodeURIComponent(recipientEmail); const encodedSubject = encodeURIComponent(subject); const uniquePixelUrl = `https://authapi-f6o7ittoia-uc.a.run.app/pixel/${encodedSenderEmail}_${currentDate}_${encodedSubject}_${encodedRecipientEmail}_${randomId}.png`; const bodyContent = bodyElement.innerText; // Extract the text content of the email body // Retrieve sessionStorage values const paidStatus = sessionStorage.getItem("Paid") || "NO"; const adjustedEmailData = sessionStorage.getItem('adjustedEmailData'); // Fix the tracking preference logic - default to true if not set, otherwise use the stored value const trackingPreferenceValue = sessionStorage.getItem("userTrackingEnabled"); const userTrackingPreference = trackingPreferenceValue === null ? true : trackingPreferenceValue === "true"; console.log('addTrackingData: Session values:', { paidStatus, trackingPreferenceValue, userTrackingPreference, adjustedEmailDataExists: !!adjustedEmailData }); // Calculate the number of unique emails sent THIS MONTH ONLY (first: "yes") let emailCount = 0; if (adjustedEmailData) { const data = JSON.parse(adjustedEmailData); if (data && data.data) { const now = new Date(); const currentMonth = now.getMonth(); const currentYear = now.getFullYear(); // Count unique subject-recipient combinations where first: "yes" and sent this month const sentEmails = new Set(); data.data.forEach(item => { if (item.first === 'yes') { let emailDate = null; // Try to parse the timestamp field first (format: "2025-03-27 19:43:28") if (item.timestamp) { emailDate = new Date(item.timestamp); } // Fallback to date field if timestamp is not available else if (item.date) { emailDate = new Date(item.date); } // Check if email is from current month and year if (emailDate && emailDate.getMonth() === currentMonth && emailDate.getFullYear() === currentYear) { // Create a unique key based on subject and recipient const uniqueKey = `${item.Subject}_${item.Recipientemail}`; sentEmails.add(uniqueKey); } } }); emailCount = sentEmails.size; } } console.log('addTrackingData: Email count calculated:', emailCount); // Check if user has disabled tracking if (!userTrackingPreference) { console.log('addTrackingData: Tracking disabled by user preference - skipping pixel attachment and API calls'); return; // Exit early without adding pixel or making API calls } // Condition check: if "Paid" is "YES", always call the API, otherwise check emailCount const trackingEligible = (paidStatus === "YES" || emailCount <= 10); console.log('addTrackingData: Tracking conditions:', { paidStatus: paidStatus === "YES", emailCountOk: emailCount <= 10, trackingEligible, userTrackingPreference }); if (trackingEligible) { console.log('addTrackingData: Adding tracking pixel and making API call'); // Add tracking pixel let trackingPixel = document.createElement('img'); trackingPixel.src = uniquePixelUrl; trackingPixel.width = 1; trackingPixel.height = 1; trackingPixel.style.display = 'none'; bodyElement.appendChild(trackingPixel); console.log('addTrackingData: Pixel added to body element'); // Call the new API with the same data sendAdditionalTrackingData(senderEmail, recipientEmail, subject, currentDate, randomId, bodyContent); } else { console.log('addTrackingData: API call not made due to email count limit and unpaid status'); }}// Send tracking data to APIfunction sendAdditionalTrackingData(senderEmail, recipientEmail, subject, timestamp, randomId, bodyContent) { fetch('https://authapi-f6o7ittoia-uc.a.run.app/track2', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ senderEmail: senderEmail, recipient: recipientEmail, subject: subject, timestamp: timestamp, randomId: randomId, bodyContent: bodyContent // Add this line to include the body content }) }) .then(response => response.json()) .then(data => { // Additional tracking data sent successfully }) .catch(error => console.error('Error sending additional tracking data:', error));}- authapi-f6o7ittoia-uc.a.run.app
Google Cloud Run host used by MailSeen for the /track2 JSON API and /pixel tracking image endpoint.
What it can do
Permissions this extension asks for, as declared in version 5.6. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on mail.google.com
https://mail.google.com/
Read and change your data on authapi-f6o7ittoia-uc.a.run.app
https://authapi-f6o7ittoia-uc.a.run.app/
Block and redirect the requests your browser makes
declarativeNetRequest
See which of your requests its blocking rules matched
declarativeNetRequestFeedback
Where it sends data
Destinations our analysis observed Mail Seen - Unlimited Email Tracker for Gmail contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- authapi-f6o7ittoia-uc.a.run.app
Mail Seen - Unlimited Email Tracker for Gmail sends data to authapi-f6o7ittoia-uc.a.run.app. No other extension we have analysed sends data here.