Enhancing Gmail browsing

I use pretty often emacs-w3m to read technical HTML docs within Emacs. When you’re programming, reading manuals, blogs or tutorials without leaving your operating system editor is all but convenient.

Browsing EmacsWikiActually, emacs-w3m does a very, very good job rendering even moderately complex sites, and i’ve been known to use it as my default browser. It is not limited to plain text (Emacs groks images these days), has tabs (shameless plug: take a look at my w3m-session package to add session management) and renders tables and other HTML constructs nicely. And of course, navigating sites like the Emacs wiki without leaving Emacs is just the way to go. Besides, if you don’t like how a page looks in emacs-w3m, opening it in your graphical browser is just a keystroke away (C-h w w3m-view-url-with-external-browser to discover it).

Gmail's login pageI also have usually open a tab with my Gmail account, to quickly check my email every now and then. As you can see in the screenshot on the right, emacs-w3m renders Gmail pages very decently (hint: you’ll need to activate cookies to use Gmail, by setting the variable w3m-use-cookies to a non-nil value). But of course the Gmail page i visit more frequently is the Spam tab, and the operation i want to perform more frequently in there is to mark all the mails and press ‘Delete Forever’. But alas, w3m does not support javascript, and the handy ‘Select All’ link is missing. Obviously, tabbing your way to every single spam mail to select it would be a pain, and one is tempted to follow the advice at the top of the page about a better Gmail experience.

GmailBut wait, this is not your regular browser. We’re inside Emacs, and in here, when we need something, we usually just hack it and keep on working. After all, what we need to do is quite simple: look for occurrences of ‘[ ]’ in the buffer, click them, and leave the pointer over the ‘Delete forever’ button, ready to send all our spam where it deserves. As it happens, our life is even easier thanks to the functions provided by emacs-w3m. w3m-form-goto-next-field allows easy navigation inside a form, and w3m-view-this-url will perform a click for us. So here we go: let’s write an Elisp command that looks for unmarked checkboxes and clicks them:

  (defun jao-w3m-gmail-mark-all ()
    (when (search-forward "[ ]" nil t)
      (backward-char 4)
      (while (looking-at " \\\\]")

That’s it. After evaluating this definition, we just M-x jao-w3m-gmail-mark-all to mark all our mails. Of course, a keyboard shortcut will come in handy:

  (define-key w3m-mode-map (kbd "C-ck") 'jao-w3m-gmail-mark-all)

and now we only need to press C-ck to get the job done. While we’re at it, it would be nice if typing a prefix would unmark mails instead of marking it, wouldn’t it? Well, that only needs a few tweaks in our original definition:

  (defun jao-w3m-gmail-mark-all (unmark)
    (interactive "P")
    (when (search-forward (if unmark "[*]" "[ ]") nil t)
      (backward-char 4)
      (while (looking-at (if unmark "\\\\*\\\\]" " \\\\]"))

Now, C-ck will mark, and C-uC-ck will unmark.

As you can see, the limit is just your imagination. For instance, when i’m reading non-spam, i usually mark some mails for deletion. Then i need to go to the ‘More actions…’ menu, select the ‘Delete’ operation and press ‘Go’. Hmm, a bit of a chore. Elisp to the rescue:

  (defun jao-w3m-gmail-delete ()
    (when (search-forward "[More Actions" nil t)
      (search-forward "Trash")

Admittedly, these little extensions are far from earth-shattering, but i think that they illustrate quite well what having an extensible system means. You control your environment and adapt it to your particular needs, often building upon functionality provided either by the system or by some other extension library. Another nice example of extensibility at work is my w3m-session package: i wanted persistent sessions, so i wrote an extension. And it was easy, thanks to the nice work of the emacs-w3m hackers and, let’s not forget, the dynamic nature of Elisp.

In addition, the programmer in me finds tweaks like this a continuous source of fun. You know, that fuzzy warm feeling… but i digress. Happy hacking!

10 Responses to “Enhancing Gmail browsing”

  1. kamen Says:

    Nice hack – especially for people who use emacs-w3m as much as possible (as you correctly point out, it’s just the quickest, easiest way to browse something from within Emacs… And many of us hate to leave the editor)

    I was wondering whether the “Delete all spam messages” button is also Javascript and not plain HTML – since that would void the need for Elisp intervention here.

    But anyway, thanks for the advice – I just came accross this blog through the Planet Emacsen channel, and I think I’ll be browsing this for a while, it looks really interesting.



  2. engtech Says:

    You have a blog devoted to learning how to use emacs?

    I love you.

    Sorry for the comment spam, but I wanted to say you have a new subscriber.

  3. Amit Patel Says:

    Gmail automatically garbage collects all the spam; you’ll save time by completely ignoring the spam folder. But it’s a neat Emacs trick nevertheless 🙂

  4. guille Says:

    very nice! and congratulations for the blog!

    just an insignificat typo, i think the define-key lacks a backslash on
    the C-ck:

    (define-key w3m-mode-map (kbd “\C-ck”) ‘jao-w3m-gmail-mark-all)



  5. Vimal Says:

    I am using emacs, and this w3m-mode doesnt work properly for gmail, for me 😦

    I also put the like: (setq w3m-use-cookies t) .. But it says “Your browser’s cookie functionality is turned off” in the webpage while logging in to gmail …

    Could you send me your configuration file? Or help me with the configuration?

    Thanks 🙂

  6. Kevin Says:

    I made some functions for my own most used actions, bound to “y” and “x”

    (defun w3m-gmail-archive ()
    "Go to the archive-button in Gmail"
    (when (search-forward "Location: http://mail.google.com/mail/" 40 t)
    (search-forward "Archive" nil t)

    (defun w3m-gmail-next-markable ()
    "Go to and mark first/next email in Gmail"
    (let ((start (point)))
    (when (and (search-forward "Location: http://mail.google.com/mail/" 40 t)
    (re-search-forward "\\[[ *]\\]" nil t))
    (let ((first (point)))
    (if (> first start)
    (goto-char first)
    (backward-char 2))
    (goto-char start)
    (unless (looking-at "[ *]\\]")
    (when (looking-at "[ *]\\]") (w3m-view-this-url))))))

    These work pretty much like x and y in javascript-gmail; although you
    have to press RET after doing
    w3m-gmail-archive. w3m-gmail-next-markable finds and marks the first markable
    email, or marks the email of the current line (so that you can use “j”
    and “k” to move up and down and mark emails with “x”). Using it while
    editing an email will select the “include original text”-checkbox
    though, so don’t do that 😉

  7. Sunil Patel Says:


    I never even thought elisp’ing emacs-w3m they way you did!…this opens up a whole new world of possibilities for me here…..interesting indeed….post more snippets if you have them for other web sites other than gmail…..I wish I could do Google Reader through emacs-w3m, but I think it requires JavaScript…

  8. Ben Says:

    Awesome! I stumbled on this page while looking for javascript for w3m
    for the exact reason that I want to be able to “Mark All” in gmail.
    Thanks for the handy tips.


  9. msingh Says:

    is there a way to use gmail keyboard shortcuts in w3m?

  10. Andy Norris Says:


    Keyboard shortcuts that work on specific sites and are not built into the browser are implemented in JavaScript. Since w3m doesn’t support JavaScript, the only way to support these shortcuts is to reimplement equivalent functionality in elisp, as in this example.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: