Bulk Save Gmail Attachments with Mail.app and Automator February 16th, 2018

This is my first post in quite a while! I wanted to share a little tool I put together to address a problem I’m sure many of us have faced. My Gmail account was nearing its quota, so I wanted to download all the photos and movies attached to the older emails before I went and deleted all the older stuff to make space.

There is no way to do this natively in Gmail, and the only other solutions I could find for bulk saving Gmail attachments were browser add-ons and Office macros that I didn’t feel comfortable running against my Google account. So, I developed a workflow using Mail.app, Automator, and a bit of AppleScript (see below). Yes, this is a heavily Mac-centric solution, but you use the tools that are available to you, right?

  1. Configure Mail.app to sync with your Gmail account
  2. Start Automator and select New Workflow
  3. Drag the “Get Selected Mail Items” action from the Library over to the workflow area. Make sure “messages” is selected in the drop down menu next to “Get selected”.
  4. Drag the “Run AppleScript action from the Library to the workflow area. Paste the following code into the text box of the script action:
    on run {input, parameters}
        set attachmentsFolder to ((path to desktop folder) & "Gmail Attachments") as text
        tell application "Finder"
            if not (exists folder attachmentsFolder) then
                display dialog "Folder doesn't exist: " & attachmentsFolder
            end if
        end tell
        tell application "Mail"
            repeat with eachMessage in input
                set {year:y, month:m, day:d, time:t} to date received of eachMessage
                set hr to t div hours
                set min to t mod hours div minutes
                set sec to t mod minutes
                set datestr to (y * 10000 + m * 100 + d) as string
                set timestr to (hr * 10000 + min * 100 + sec) as string
                repeat with eachAttachment in eachMessage's mail attachments
                    set originalName to name of eachAttachment
                    set savePath to attachmentsFolder & ":" & datestr & "-" & timestr & "-" & originalName
                    save eachAttachment in file savePath   
                end repeat
            end repeat
        end tell
    end run

    Note: this code assumes you have a writable folder called ~/Desktop/Gmail Attachments. You can change that path if you so desire.

  5. In Mail.app, highlight the messages you want to extract the attachments from. You can, for example, search for messages older than a particular date, or those that have JPEG attachments, etc.
  6. Back in Automator, click “Run” in the top right corner or hit Cmd+R. This will start the workflow which will go through each attachment from each highlighted message, and save it with a time-stamped filename based on the date and time the message was received.

Hopefully this is helpful. Leave me a comment if you have any feedback.

Play Dark Castle on OS X and Windows October 11th, 2015

This is an update to a post from a few years ago on playing Dark Castle in Windows. I had the urge to play Dark Castle last week, but I needed to update the archive to contain the Macintosh emulator for Mac OS X as well.

Emulator Files: 2015-Dark-Castle.zip

Inside the archive you’ll find images for Dark Castle and Beyond Dark Castle, two of my absolute favorite games to play in the mid 80s on old Macintoshes like the Mac Plus. Follow the steps below to enjoy these games on modern OSes.

  1. Unzip the archive.
  2. Run the Mini vMac.exe or Mini vMac.app executable, depending on your OS. Mini vMac is is a Mac Plus emulator which is freely distributed. Mini vMac requires a ROM image from a Macintosh Plus to run, which I’ve provided as well.
  3. Once you’ve started Mini vMac, you are effectively running a Mac Plus with no operating system installed. I created a disk image with System 6 already installed. Go to File > Open Disk Image within Mini vMac and open the file Disk603.dsk or drag the file into the Mini vMac window.
  4. Now that System 6 is up and running, we need a hard drive available to install software and save data to. Just like the previous step drag the included file, hfs10M.DSK into the vMac window to mount the 10M hard disk image I pre-loaded with the Dark Castle software.
  5. Run the Dark Castle executable to start the game. For Beyond Dark Castle, mount the BDCImage.hfv file and run the game from there.


I bet you can hear the game sounds already 🙂 Enjoy!

Simple Local Web servers November 27th, 2013

I’ve had this post saved as a draft for two years, so I finally decided to clean it up a little and publish it in case anyone else finds the information useful.

In web development, for both client and server testing, it’s often very useful to have a local web server running in order to serve test cases. This post outlines a few quick and easy ways to run a local web server that don’t involve installing Apache or nginx and all their dependencies.

The simplest way I know of to get a local web server is with netcat:

brandon@dexter:~$ nc -l 8000

Then, when you hit the URL http://localhost:8000 in your browser, you will see the request show up on the terminal where netcat is running:

GET / HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:6.0a1) Gecko/20110513 Firefox/6.0a1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cache-Control: max-age=0

You can then type an arbitrary response back to the browser, terminating the stream with Ctrl+C:

HTTP/1.1 200 OK
Content-Type: text/html

Hello <b>world</b>

The hello world HTML page shows up in your browser as you would expect. You could just as easily use an existing file on your filesystem as input for the response:

brandon@dexter:~$ nc -l 8000 < http_response_file.txt

Another option to consider, especially if you already have test cases or other static content ready to serve, is Python’s SimpleHTTPServer class. You don’t even need to write a script to run one of these servers locally:

brandon@dexter:~$ python -m SimpleHTTPServer 8000
Serving HTTP on port 8000 ...d

This time, hitting http://localhost:8000 in your browser will bring up a directory listing with your current working directory as the document root. Your requests are also logged on your Python terminal:
localhost - - [16/May/2011 14:55:36] "GET / HTTP/1.1" 200 -

On a separate but related note, you can get a local SMTP testing server, which only logs to the console and doesn’t actually send mail, by running:

$ sudo python -m smtpd -c DebuggingServer -n localhost:25

---------- MESSAGE FOLLOWS ----------
Content-Type: multipart/alternative;
MIME-Version: 1.0
Subject: Veracode report for 2013-10-24
From: python.script@example.com
To: recipient@example.org

Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

= Plain text version =
Hello world!

Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

<h1>HTML Version</h1>
<p>Hello <b>world</b>!</p>

------------ END MESSAGE ------------

Standing on the Shoulders of Giants October 15th, 2013

I recently created a new theme for my personal site*, and was struck anew by how many Open Source Software packages this site is built on top of.  To name a few of the essential ones:

In other words, every layer of the Web stack, which I use every day for fun and for profit, is powered by Open Source Software.  It would be beyond impossible to deploy a website today with rich, interactive experiences without these fundamental pillars.  I owe so much to Linux, Open Source, and Open Standards, and it is only right that I acknowledge this fact.

* Many thanks, also, to David Goines, who graciously allowed me to use his artwork in the new site design.

Moving to GitHub March 8th, 2011

GitHub is an amazing tool which holds a lot of promise for pushing open source software development forward. I say that because they make the process of forking someone else’s repository and then merging your changes (with their permission, of course) back into the master repo as simple as a few mouse clicks. I, for example, contributed a patch that made jQuery CSP-compatible which was later pulled into the jQuery trunk.

Since GitHub has become the industry standard for sharing code, I’ve started the process of moving all of my open source tools to a repository there. So far, I have only moved my Python CIDR block converter, but the rest should follow soon!

Update to CSP Bookmarklet January 20th, 2011

It was pointed out to me that my CSP bookmarklet was using a feature added in ECMAScript 5, Object.keys, and thus did not work in older browsers. I added a bit of code to address this:

Object.keys = Object.keys || function(obj) {
  var keys = [];
  for (var key in obj) {
    if (obj.hasOwnProperty(key))
  return keys;

Browsers that don’t natively support Object.keys will now have that functionality added when the bookmarklet runs. Go ahead, give it a try: Recommend CSP

As before, the full source is posted for you to browse as well.

East Bay Psychotherapist
Licensed Clinical Social Worker provides psychotherapy and counseling services for couples and individuals in the East Bay Area.