Improved version of the old "Emails" quick search functionality in Gmail, one click to view all emails you've sent or received from any address
// ==UserScript== // @name Fix Gmail Email Search // @namespace https://github.com/gserafini/fix-gmail-email-search-userscript/ // @version 1.5.1 // @description Improved version of the old "Emails" quick search functionality in Gmail, one click to view all emails you've sent or received from any address // @author Gabriel Serafini // @license MIT // @donate If you like this, PayPal a little love to [email protected] (or https://paypal.me/SerafiniStudios ) // @screenshot https://raw.githubusercontent.com/gserafini/fix-gmail-email-search-userscript/master/fix-gmail-email-search-screenshot.png // @icon https://raw.githubusercontent.com/gserafini/fix-gmail-email-search-userscript/master/SearchEmails_icon.png // @match *://mail.google.com/* // @match *://contacts.google.com/* // @match *://gmail.com/* // @grant none // ==/UserScript== // Changelog: // v1.5.1 - Bug fix: Fixed @match directive for contacts.google.com to support // Google Workspace accounts with /u/1/ paths (hovercards now work on all accounts) // v1.5.0 - Major rewrite: Removed jQuery dependency, now uses pure vanilla JavaScript // No longer requires separate TrustedHTML bypass script // Uses native DOM methods (createElement, createElementNS) instead of innerHTML // Smaller, faster, and bypasses TrustedTypes restrictions without workarounds (function() { 'use strict'; // Add styles using textContent (no TrustedTypes issues) var style = document.createElement('style'); style.textContent = '.email_search_icon { outline: none; position: relative; z-index: 0; padding: 0 4px; margin: 0; top: 2px; cursor: pointer; } ' + '.email_search_icon svg { fill: #600; } ' + '.email_search_icon svg:hover { fill: #f00; }'; document.head.appendChild(style); // Create search icon element using DOM methods (no innerHTML) function createEmailSearchIcon(emailAddress) { var span = document.createElement('span'); span.className = 'email_search_icon'; span.title = 'Click to search for all emails with ' + emailAddress; span.setAttribute('email', emailAddress); // Create SVG using createElementNS var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('focusable', 'false'); svg.setAttribute('height', '1em'); svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('width', '1em'); var path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path1.setAttribute('d', 'M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'); var path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path2.setAttribute('d', 'M0 0h24v24H0z'); path2.setAttribute('fill', 'none'); svg.appendChild(path1); svg.appendChild(path2); span.appendChild(svg); return span; } // Check if element already has icon function hasIcon(element) { var prev = element.previousElementSibling; return prev && prev.classList.contains('email_search_icon'); } function insertEmailSearchIcons() { // Find Gmail email elements (.gD class) var gdElements = document.querySelectorAll('.gD'); for (var i = 0; i < gdElements.length; i++) { var el = gdElements[i]; if (!hasIcon(el)) { var email = el.getAttribute('email'); if (email) { var gdIcon = createEmailSearchIcon(email); el.parentNode.insertBefore(gdIcon, el); } } } // Find mailto links (excluding contenteditable divs) var mailtoLinks = document.querySelectorAll('a[href^="mailto:"]'); for (var j = 0; j < mailtoLinks.length; j++) { var link = mailtoLinks[j]; // Skip if inside contenteditable div var inEditable = link.closest('div[contenteditable="true"]'); if (!inEditable && !hasIcon(link)) { var href = link.getAttribute('href'); var emailAddr = href.replace('mailto:', ''); var mailtoIcon = createEmailSearchIcon(emailAddr); link.parentNode.insertBefore(mailtoIcon, link); } } } // Poll periodically for newly created elements setInterval(insertEmailSearchIcons, 300); // Handle click events using event delegation document.addEventListener('click', function(event) { var target = event.target; // Find closest .email_search_icon (handles clicks on SVG children) var icon = target.closest('.email_search_icon'); if (!icon) return; event.stopPropagation(); var email = icon.getAttribute('email'); if (window.self === window.top) { // Main window - perform search var searchInput = document.querySelector('input[name="q"]'); var searchButton = document.querySelector('button[aria-label="Search mail"]'); if (searchInput && searchButton) { searchInput.value = email; searchButton.click(); } } else { // Iframe (hovercard) - send message to parent window.parent.postMessage('searchForEmail=' + email, '*'); } }); // Listen for messages from iframe (hovercard) if (window.self === window.top) { window.addEventListener('message', function(event) { if (event.origin === 'https://contacts.google.com' && typeof event.data === 'string' && event.data.indexOf('searchForEmail=') !== -1) { var email = event.data.replace('searchForEmail=', ''); var searchInput = document.querySelector('input[name="q"]'); var searchButton = document.querySelector('button[aria-label="Search mail"]'); if (searchInput && searchButton) { searchInput.value = email; searchButton.click(); } } }); } })();