Greasy Fork is available in English.

Gmail Sender Shield

Gmail Sender Shield enhances your Gmail experience by displaying sender domains and icons for quick identification and offering tools to highlight untrusted emails.

  1. // ==UserScript==
  2. // @name Gmail Sender Shield
  3. // @name:es Gmail Escudo de Correos
  4. // @namespace http://tampermonkey.net/
  5. // @version 1.6
  6. // @description Gmail Sender Shield enhances your Gmail experience by displaying sender domains and icons for quick identification and offering tools to highlight untrusted emails.
  7. // @description:es Gmail Escudo de Correos mejora tu experiencia en Gmail mostrando los dominios e íconos de los remitentes para una identificación rápida y ofreciendo herramientas para resaltar correos no confiables.
  8. // @author IgnaV
  9. // @match https://mail.google.com/*
  10. // @icon https://ssl.gstatic.com/ui/v1/icons/mail/rfr/gmail.ico
  11. // @license MIT
  12. // @grant GM_setValue
  13. // @grant GM_getValue
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. if (window.self !== window.top) return;
  20.  
  21. const userId = window.location.href.match(/\/u\/(\d+)\//)[1];
  22.  
  23. const addIcon = GM_getValue('addIcon', true);
  24. const addDomain = GM_getValue('addDomain', true);
  25. let allowedCommonDomains = GM_getValue('allowedDomains', []);
  26. let allowedUserDomains = GM_getValue('allowedUserDomains', {});
  27.  
  28. let userDomains = allowedUserDomains[userId] || [];
  29. allowedUserDomains[userId] = userDomains;
  30.  
  31. GM_setValue('addIcon', addIcon);
  32. GM_setValue('addDomain', addDomain);
  33. GM_setValue('allowedUserDomains', allowedUserDomains);
  34.  
  35. let allowedDomains = allowedCommonDomains.concat(userDomains);
  36. const hasDomains = allowedDomains.length !== 0;
  37.  
  38.  
  39. const channel = new BroadcastChannel('mi-canal');
  40. channel.onmessage = (event) => {
  41. refreshAllowedDomains();
  42. updateAllDomainStates();
  43. console.log('Mensaje recibido:', event.data);
  44. };
  45.  
  46. if (!addIcon && !addDomain && !hasDomains) return;
  47.  
  48. const processedElements = new Set();
  49.  
  50. function refreshAllowedDomains() {
  51. allowedCommonDomains = GM_getValue('allowedDomains', []);
  52. allowedUserDomains = GM_getValue('allowedUserDomains', {});
  53. userDomains = allowedUserDomains[userId] || [];
  54. allowedDomains = allowedCommonDomains.concat(userDomains);
  55. }
  56.  
  57. function addDomainContainer(element, email) {
  58. const domain = extractDomain(email);
  59. const domainContainer = document.createElement('div');
  60. domainContainer.className = 'domain-container';
  61. domainContainer.onclick = () => domainContainerEvent(domainContainer, email);
  62. updateDomainState(domainContainer, email);
  63.  
  64. addIconToContainer(domainContainer, domain);
  65. addDomainToContainer(domainContainer, domain);
  66. element.appendChild(domainContainer);
  67. return domainContainer;
  68. }
  69.  
  70. function updateDomainState(container, email) {
  71. const domain = extractDomain(email);
  72. container.classList.remove('not-allowed-domain', 'allowed-domain');
  73. if (allowedDomains.includes(email) || allowedDomains.includes(domain)) {
  74. container.classList.add('allowed-domain');
  75. } else {
  76. container.classList.add('not-allowed-domain');
  77. }
  78. }
  79.  
  80. function domainContainerEvent(domainContainer, email) {
  81. event.preventDefault();
  82. event.stopPropagation();
  83.  
  84. const domain = extractDomain(email);
  85.  
  86. let message;
  87. if (userDomains.includes(domain)) {
  88. userDomains.splice(userDomains.indexOf(domain), 1);
  89. allowedCommonDomains.push(domain);
  90. message = `+ Empresa (Todas las cuentas)`;
  91. } else if (allowedCommonDomains.includes(domain)) {
  92. allowedCommonDomains.splice(allowedCommonDomains.indexOf(domain), 1);
  93. userDomains.push(email);
  94. message = `+ Correo (Esta cuenta)`;
  95. } else if (userDomains.includes(email)) {
  96. userDomains.splice(userDomains.indexOf(email), 1);
  97. allowedCommonDomains.push(email);
  98. message = `+ Correo (Todas las cuentas)`;
  99. } else if (allowedCommonDomains.includes(email)) {
  100. allowedCommonDomains.splice(allowedCommonDomains.indexOf(email), 1);
  101. message = `Eliminado`;
  102. } else {
  103. userDomains.push(domain);
  104. message = `+ Empresa (Esta cuenta)`;
  105. }
  106.  
  107. allowedUserDomains[userId] = userDomains;
  108. GM_setValue('allowedUserDomains', allowedUserDomains);
  109. GM_setValue('allowedDomains', allowedCommonDomains);
  110. refreshAllowedDomains();
  111.  
  112. updateAllDomainStates();
  113.  
  114. showTooltip(domainContainer, message);
  115.  
  116. setTimeout(() => channel.postMessage(message), 200);
  117. };
  118.  
  119. function updateAllDomainStates() {
  120. const nameElements = document.querySelectorAll('.bA4, .bAK, .bAp');
  121. nameElements.forEach((element) => {
  122. const emailElement = element.querySelector('[email]');
  123. if (!emailElement) return;
  124.  
  125. const email = emailElement.getAttribute('email');
  126. const domain = extractDomain(email);
  127. const domainContainer = element.querySelector('.domain-container');
  128.  
  129. if (domainContainer) {
  130. updateDomainState(domainContainer, email);
  131. } else {
  132. addDomainContainer(element, email);
  133. }
  134. });
  135. }
  136.  
  137. function showTooltip(element, message) {
  138. const tooltip = document.createElement('span');
  139. tooltip.className = 'custom-tooltip';
  140. tooltip.textContent = message;
  141.  
  142. element.appendChild(tooltip);
  143. setTimeout(() => {
  144. if (element.contains(tooltip)) {
  145. element.removeChild(tooltip);
  146. }
  147. }, 3000);
  148. }
  149.  
  150. function addIconToContainer(domainContainer, domain) {
  151. const icon = document.createElement('img');
  152. icon.src = `https://www.google.com/s2/favicons?domain=${domain}`;
  153. icon.className = 'domain-icon';
  154. domainContainer.appendChild(icon);
  155. }
  156.  
  157. function addDomainToContainer(domainContainer, domain) {
  158. const domainSpan = document.createElement('span');
  159. domainSpan.className = 'domain-text';
  160. domainSpan.textContent = domain;
  161. domainContainer.appendChild(domainSpan);
  162. }
  163.  
  164. function addStyles(addIcon, addDomain, hasDomains) {
  165. const style = document.createElement('style');
  166. style.type = 'text/css';
  167. let css = ``;
  168. if (addIcon || addDomain) {
  169. css += `
  170. .bA4, .bAK, .bAp {
  171. padding-top: 9px;
  172. }
  173. .domain-container {
  174. display: flex;
  175. align-items: center;
  176. margin-top: -4px;
  177. font-size: 10px;
  178. color: #888;
  179. width: fit-content;
  180. height: 11px;
  181. padding: 1px 2px;
  182. }
  183. .domain-container:hover {
  184. background-color: #b1b1b1;
  185. }
  186. .domain-container.not-allowed-domain:hover {
  187. background-color: #e5afaf;
  188. }
  189. `;
  190. }
  191. if (addIcon) {
  192. css += `
  193. .domain-icon {
  194. width: 10px;
  195. height: 10px;
  196. margin-right: 3px;
  197. }
  198. `;
  199. }
  200. if (addDomain) {
  201. css += `
  202. .domain-text {
  203. white-space: nowrap;
  204. overflow: hidden;
  205. text-overflow: ellipsis;
  206. font-size: 10px;
  207. color: #888;
  208. color: inherit; /* Hereda el color del contenedor */
  209. }
  210. `;
  211. }
  212. if (hasDomains) {
  213. css += `
  214. .not-allowed-domain {
  215. background-color: #f8d7da;
  216. color: #721c24;
  217. }
  218. .allowed-domain {
  219. background-color: transparent;
  220. color: inherit;
  221. }
  222. .custom-tooltip {
  223. position: absolute;
  224. background-color: #000;
  225. color: #fff;
  226. padding: 4px;
  227. border-radius: 4px;
  228. font-size: 12px;
  229. white-space: nowrap;
  230. z-index: 1000;
  231. top: 40px;
  232. opacity: 0;
  233. transition: opacity 0.3s ease-in-out;
  234. }
  235. .custom-tooltip:has(+ .custom-tooltip) {
  236. display: none;
  237. }
  238. .domain-container:hover .custom-tooltip {
  239. opacity: 1;
  240. }
  241. `;
  242. }
  243. style.appendChild(document.createTextNode(css));
  244. document.head.appendChild(style);
  245. }
  246.  
  247. addStyles(addIcon, addDomain, hasDomains);
  248.  
  249. function addDomainBelowName() {
  250. const nameElements = document.querySelectorAll('.bA4, .bAK, .bAp');
  251.  
  252. nameElements.forEach((element) => {
  253. if (processedElements.has(element)) return;
  254.  
  255. const emailElement = element.querySelector('[email]');
  256. if (!emailElement) return;
  257.  
  258. const email = emailElement.getAttribute('email');
  259. const domain = extractDomain(email);
  260.  
  261. const domainElement = addDomainContainer(element, email);
  262.  
  263. processedElements.add(element);
  264. });
  265. }
  266.  
  267. function extractDomain(email) {
  268. const domainParts = email.split('@')[1].split('.');
  269. if (domainParts[domainParts.length - 2] === 'com') {
  270. return domainParts.slice(-3).join('.');
  271. }
  272. return domainParts.slice(-2).join('.');
  273. }
  274.  
  275. const observer = new MutationObserver((mutations) => {
  276. mutations.forEach(() => {
  277. addDomainBelowName();
  278. });
  279. });
  280.  
  281. observer.observe(document.body, {
  282. childList: true,
  283. subtree: true
  284. });
  285.  
  286. window.addEventListener('load', () => {
  287. addDomainBelowName();
  288. });
  289. })();