Greater Lansing Real Estate

Gmail Snooze Script – We Don’t Need No Stinkin MailboxApp

I’ll admit it. I got caught up in the MailboxApp fever and watched the little counter until I could get my hands on the app. Then I did and realized I didn’t particularly care for the interface or for giving up credentials to yet another service (though I do have 2 factor authentication setup). I like the Gmail interface. I think it’s done well. And I want control. So I asked that question that every engineer asks: “How can I do this better?”. Naturally the answer was smacking me in the face. Maybe a year ago I came across a Gmail snooze script, but didn’t really take the time to understand it or tweak it to my needs. This time was different.

Below you’ll find the setup instructions that will give you MailboxApp like functionality in something you completely control and that you can use from any email client. Just attach labels or move your messages to the any of the snooze labels and let the script do the rest. Personally, I’m using the script with a Dispatch “quick action” to easily triage my inbox.

See the “Setup” instructions in the comment block at the top of the code or refer to the images below…

gdrive-create-script

gdrive-blank-project

Paste the code from below into the script

gdrive-run-function gdrive-trigger-setup

To use the functionality provided by the script just move any email to one of the snooze labels. For example, Move to –> _Z/Tonight to have the email reappear at the time you selected (default: 5pm). These are the suggested options to use, but there are more specific labels you can use for tighter control:

  • _Z/Later
  • _Z/Midnight
  • _Z/Noon
  • _Z/Tonight
  • _Z/Tomorrow
  • _Z/This Weekend
  • _Z/Next Week
  • _Z/Next Month

I hope you like it!


/*
* Author: Mark Jacobsen (http://mjg2.net/code)
*
* This is a massively modified and more powerful GMail snooze script that mirrors much of the functionality of
* the iPhone "Mailbox" app with the added benefit of not having to hand over your credentials, and being able to 
* use from any mail client (web, Android, iPhone, etc).  If you like it or have suggestions, please drop me a line
* from my blog at http://mjg2.net/code
*
* Setup:
* 1) Fill in the values below (or just use the defaults)
* 2) Run the "setup()" function using the method drop down and run arrow
* 3) Set time based triggers for:
*      moveDailySnoozes() - Daily between Midnight to 1 am
*      moveHourlySnoozes() - Every 5 minutes
*
* Changes:
* 2013-05-06  markjacobsen.net  Fixed getLabelForHour to correctly handle am/pm thanks to "benlarge"
* 2014-02-23  markjacobsen.net  Fixed moveDailySnoozes to correctly handle the current DOW thanks to "Jeff Hirsch"
* 2014-03-24  markjacobsen.net  Added additional parseInt()s to moveHourlySnoozes
*/

// =============================================================================
// Set these values according to your needs
// =============================================================================
var TIMEZONE = "America/Detroit";  // Your timezone
var TONIGHT_HOUR = 17;  // Hour (on a 24 hour clock. ex: 17=5pm) representing when something snoozed until "Tonight" should reappear
var HOURS_UNTIL_LATER = 3;  // Number of hours when something snoozed until "Later" should appear
var REAPPEAR_LABEL = "_Action";  // Full label path to apply when a message reappears in the inbox (leave blank "" to not set a label)
var REAPPEAR_UNREAD = true;  // Decide if you want to mark a thread as unread when it reappears in the inbox

// ==========================================================================================
// I wouldn't recommend changing these values but it shouldn't hurt anything if done right :)
// ==========================================================================================
var LABEL_BASE = "_Z";  // The label to create all snooze labels under (it's suggested that you don't change this)
var LABEL_BASE_DOW = LABEL_BASE + "/zDay";
var LABEL_BASE_MO = LABEL_BASE + "/zMonth";
var LABEL_BASE_TOD = LABEL_BASE + "/zTime";

// =============================================================================
// =============================================================================
// Do NOT change anything below here
// =============================================================================
// =============================================================================
var LABEL_LATER = LABEL_BASE + "/Later";
var LABEL_MIDNIGHT = LABEL_BASE + "/Midnight";
var LABEL_NOON = LABEL_BASE + "/Noon";
var LABEL_TONIGHT = LABEL_BASE + "/Tonight";
var LABEL_TOMORROW = LABEL_BASE + "/Tomorrow";
var LABEL_THIS_WEEKEND = LABEL_BASE + "/This Weekend";
var LABEL_NEXT_WEEK = LABEL_BASE + "/Next Week";
var LABEL_NEXT_MONTH = LABEL_BASE + "/Next Month";


function setup() {
  GmailApp.createLabel(LABEL_BASE);
  GmailApp.createLabel(LABEL_BASE_DOW);
  GmailApp.createLabel(LABEL_BASE_MO);
  GmailApp.createLabel(LABEL_BASE_TOD);
  GmailApp.createLabel(LABEL_NEXT_WEEK);
  GmailApp.createLabel(LABEL_NEXT_MONTH);
  GmailApp.createLabel(LABEL_LATER);
  GmailApp.createLabel(LABEL_MIDNIGHT);
  GmailApp.createLabel(LABEL_NOON);
  GmailApp.createLabel(LABEL_TONIGHT);
  GmailApp.createLabel(LABEL_TOMORROW);
  GmailApp.createLabel(LABEL_THIS_WEEKEND);
  GmailApp.createLabel(getLabelForDayOfWeek("Sunday"));
  GmailApp.createLabel(getLabelForDayOfWeek("Monday"));
  GmailApp.createLabel(getLabelForDayOfWeek("Tuesday"));
  GmailApp.createLabel(getLabelForDayOfWeek("Wednesday"));
  GmailApp.createLabel(getLabelForDayOfWeek("Thursday"));
  GmailApp.createLabel(getLabelForDayOfWeek("Friday"));
  GmailApp.createLabel(getLabelForDayOfWeek("Saturday"));
  
  // Time of day Labels
  for (var i = 0; i <= 23; ++i) {
    GmailApp.createLabel(getLabelForHour(i));
  }
  
  // Month Labels
  for (var i = 0; i <= 11; ++i) {
    GmailApp.createLabel(getLabelForMonth(i));
  }
}

function test(){
  Logger.log(getLabelForHour(0));
  Logger.log(getLabelForHour(12));
  Logger.log(getLabelForHour(13));
  Logger.log(getLabelForHour(23));
}

function getLabelForHour(hr){
  var ampm = "am";
  if (hr > 12)
  {
    hr -= 12;
    ampm = "pm";
  }
  else if (hr == 12)
  {
    ampm = "pm";
  }
  else if (hr == 0)
  {
    hr = 12;
    ampm = "am";
  }
  return LABEL_BASE_TOD + "/" + parseInt(hr) + ampm;
}

function getLabelForMonth(mo){
  var tmp;
  
  if (mo == -1){
    tmp = new Date();
  }else{
    tmp = new Date(2000, mo, 1);
  }
  return LABEL_BASE_MO + "/"  + Utilities.formatDate(tmp, TIMEZONE, "MMMMM");
}

function getLabelForDayOfWeek(dow){
  return LABEL_BASE_DOW + "/" + dow;
}


function moveDailySnoozes() {
  var dow, dom, mo;
  
  // Move anything that was snoozed until tomorrow
  moveSnoozesToInbox(LABEL_TOMORROW);
  
  dow = Utilities.formatDate(new Date(), TIMEZONE, "EEEE");
  dom = Utilities.formatDate(new Date(), TIMEZONE, "d");
  
  // Move anything that was snoozed until this DOW
  moveSnoozesToInbox(getLabelForDayOfWeek(dow));
  
  if ((dow == "Sunday") || (dow == "Saturday")){
    // If something was snoozed until this weekend, that should be moved too
    moveSnoozesToInbox(LABEL_THIS_WEEKEND);
  }
           
  // Move anything for "next week" to the DOW it should come off snooze (i.e. the current DOW).
  // This works and doesn't move the messages pre-maturely because we moved
  // msgs for the DOW, prior to this and this functions should only fire
  // once a day
  moveSnoozes(LABEL_NEXT_WEEK, getLabelForDayOfWeek(dow));
  
  if (dom == 1){
    // Move anything snoozed until "next month" or
    // specifically for the current month on the 1st day
    // of a new month
    moveSnoozesToInbox(getLabelForMonth(-1));
    moveSnoozesToInbox(LABEL_NEXT_MONTH);
  }
}

function moveHourlySnoozes() {
  var curHour, curHourLabel, hourForLater, curDateTime;
 
  curHour = Utilities.formatDate(new Date(), TIMEZONE, "H");
  curHourLabel = getLabelForHour(curHour);
  
  moveSnoozes(LABEL_NOON, getLabelForHour(12));
  moveSnoozes(LABEL_MIDNIGHT, getLabelForHour(0));
  
  if (parseInt(curHour) == parseInt(TONIGHT_HOUR)){
    moveSnoozesToInbox(LABEL_TONIGHT);
  }
  
  moveSnoozesToInbox(curHourLabel);
  
  hourForLater = parseInt(parseInt(curHour) + HOURS_UNTIL_LATER);
  if (hourForLater >= 24){
    hourForLater = parseInt(hourForLater - 24);
  }
  moveSnoozes(LABEL_LATER, getLabelForHour(hourForLater));
}


function moveSnoozesToInbox(oldLabelName) {
  var oldLabel, page, reappearLabel;
  oldLabel = GmailApp.getUserLabelByName(oldLabelName);
  page = null;
  // Get threads in "pages" of 100 at a time
  while(!page || page.length == 100) {
    page = oldLabel.getThreads(0, 100);
    if (page.length > 0) {
      GmailApp.moveThreadsToInbox(page);
      oldLabel.removeFromThreads(page);
      if (REAPPEAR_LABEL != ""){
        reappearLabel = GmailApp.getUserLabelByName(REAPPEAR_LABEL);
        reappearLabel.addToThreads(page);
      }
      if (REAPPEAR_UNREAD == true){
        GmailApp.markThreadsUnread(page);
      }
    }     
  }
}


function moveSnoozes(oldLabelName, newLabelName) {
  var oldLabel, newLabel, page;
  oldLabel = GmailApp.getUserLabelByName(oldLabelName);
  newLabel = GmailApp.getUserLabelByName(newLabelName);
  page = null;
  // Get threads in "pages" of 100 at a time
  while(!page || page.length == 100) {
    page = oldLabel.getThreads(0, 100);
    if (page.length > 0) {
      newLabel.addToThreads(page);
      oldLabel.removeFromThreads(page);
    }     
  }
}

Weekly Round-Up: 3/3/13 to 3/9/13

The Weekly Round-Up is a once weekly collection of my #1Aday daily shares. Hope you find something of interest!

Mon 3/4
Thorin Klosowski @kingthor on: How to Get Anything You Want with Minimal Negotiation – http://markjacobsen.net/l/1744

Tue 3/5
Shit Happens… to Mr. Money Mustache’s House – http://markjacobsen.net/l/1745

Wed 3/6
Been meaning to post this for a while about my favorite charity: @charitywater – http://markjacobsen.net/l/1746

Thu 3/7
Leo @zen_habits on the: Discomfort Zone: How to Master the Universe – http://markjacobsen.net/l/1747

Fri 3/8
Craig Ballantyne @craigballantyne gives you: 12 Rules to Live By – http://markjacobsen.net/l/1748

Principles, Priorities, and Values – oh my!

Lately I’ve been thinking about the important things to me. What my “principles”, “priorities”, or “values” are. I’m sure I could spout off a number of things, but here are the big ideas that come to mind.

Family
My family is the most important thing in the world to me. I will do anything within my power for my wife and kids. What is the purpose of life without someone or a cause to love?

Goals
Goals keep us moving forward. They give us something to strive for. But don’t confuse a want with a goal. Remember, goals are SMART: Specific, Measurable, Attainable, Relevant, and Time-bound.

Planning
A dream without a plan is only a wish upon a star, but beware analysis paralysis. Use planning to achieve your goals. And remember, plans change. Change with them.

Disciplined Action
This is where you walk the walk. Achieving any goal or carrying out any plan is primarily a matter of disciplined action. It’s making the hard choices. Doing things you don’t want to do. Doing as you say. Being a role-model.

Routine
The easiest way to maintain disciplined action is through routine. Routine isn’t a dirty word or meant in a negative way. Some might call it a ritual.

Spontaneity (White Space)
Of course once you have planned your disciplined actions and made them a routine it’s amazing how much time you can find for other things. Once you know where the unmovable objects are it’s easy to find the space between. Remember to keep white space in your schedule. You can’t plan everything and if you try to you will drive yourself and those around you crazy. Schedule your priorities. Don’t schedule your life.

Weekly Round-Up: 2/24/13 to 3/2/13

The Weekly Round-Up is a once weekly collection of my #1Aday daily shares. Hope you find something of interest!

Mon 2/25
Derek Khanna @dkhanna11: The Law Against Unlocking Cellphones Is Anti-Consumer, Anti-Business, & Anti-Common Sense – http://markjacobsen.net/l/1739

Tue 2/26
Joshua Fields Millburn @JFM says: Here, Have an Organ – http://markjacobsen.net/l/1740

Wed 2/27
Former sex trafficking victim shines light on dark underworld of Super Bowl – http://markjacobsen.net/l/1741

Thu 2/28
Leo @zen_habits gives: Advice to My Kids – http://markjacobsen.net/l/1742

Fri 3/1
Marelisa Fabrega @Marelisa on: The Ten Habits of Zen to Done – http://markjacobsen.net/l/1743

Weekly Round-Up: 2/17/13 to 2/23/13

The Weekly Round-Up is a once weekly collection of my #1Aday daily shares. Hope you find something of interest!

Tue 2/19
Gretchen Rubin @gretchenrubin asks: Do You Find Yourself Falling for These 12 Familiar Myths about Clutter? – http://markjacobsen.net/l/1735

Wed 2/20
Leo @zen_habits on: The 7 Habits of Calmness – http://markjacobsen.net/l/1736

Thu 2/21
An oldie but a goodie – Paul Graham @paulg on: Maker’s Schedule, Manager’s Schedule – http://markjacobsen.net/l/1737

Fri 2/22
Alan Henry @halophoenix on: How to Work an On Call Job and Keep Your Sanity – http://markjacobsen.net/l/1738

Weekly Round-Up: 2/11/13 to 2/17/13

The Weekly Round-Up is a once weekly collection of my #1Aday daily shares. Hope you find something of interest!

Tue 2/12
14 Photographs That Shatter Your Image of Famous People – http://markjacobsen.net/l/1711

Wed 2/13
Use a “daily do” list to remember and execute the little things – http://markjacobsen.net/l/1712

Thu 2/14
Why You Should Want to Pay for Software, Instagram Edition – While the dust up may be over this is still important – http://markjacobsen.net/l/1714

Fri 2/15
My 10 Essential Email Habits by @zen_habits – http://markjacobsen.net/l/1734

Setting up the ultimate console

If you’ve been coding for any time, chances are you’ve become acquainted with the command line. While some love it and some hate it I think it’s wonderful for getting things done quickly. Unfortunately, the windows command line is crap. With that said I finally got fed up and asked that most important programmer question of “How do I get a better command line”?

That search led me to an open source application called appropriately enough: Console. When I first opened it up and started playing around I have to admit my first reaction was “meh”. Then I asked that import question again, “How can this be made better”? A little Googling and experimentation later I got things working to my satisfaction.

So, here for your one-stop quick-reference is how to setup the ultimate console for Windows…

Assumptions

  • You access the console for all different platforms (not just Windows)
  • You already have putty and its utilities downloaded – and are familiar with their use
  • You already have installed cygwin – and are familiar with its use

Installation

  1. Download Console and extract the contents to the folder of your choice
  2. Download ANSICON and extract the following files to the same directory you extracted Console to.
    • ANSI32.dll
    • ANSI64.dll
    • ansicon.exe

Great, now you have Console installed, but this is the configuration I use to make it really rock.

Configuration

These can all be found under “Edit -> Settings”

  • Appearance
    • Custom color: Change it to an awsome green
  • Appearance -> More…
    • Uncheck “Show toolbar”
    • Select “Alpha” under “Window transparency” and set “Active window” to 25 and “Inactive window” to 40
  • Behavior
    • Check “Copy on select”
    • Uncheck “Clear selection on copy”
  • Hotkeys
    • Set “New Tab 1” to “Ctrl+T”
    • Set “Copy selection” to “Ctrl+C”
    • Set “Paste” to “Ctrl+V”
  • Hotkeys -> Mouse
    • Set “Copy/clear selection” to “None”
    • Set “Select text” to “Left”
    • Set “Paste text” to “Right”
    • Set “Context menu” to “Middle”

Tab Configuration

Now that you have your console looking pretty and being functional, lets hook it into putty and cygwin. You can do this configuration under “Edit -> Settings -> Tabs”. Obviously, the directories you’ve chosen for things will be different (change to your values).

Cygwin: Add a tab and set the shell to:

C:\cygwin\bin\bash.exe --login -i

Putty: Add a tab and set the shell to:

C:\apps\Console2\ansicon.exe "C:\apps\Putty\plink.exe" -load "aSavedSessionName"

Reference

console

 

How to list all environment variables

Often times you can find useful information in your environment variables, but since it’s something you don’t have to do everyday it’s easy to forget. Here’s a refresher:

Windows
First bring up a command prompt, then run the following…

set

To see the value of a single environment variable:

echo %ENVVAR%

Linux
Run the following from a terminal to see all environment variables…

printenv

To see the value of a single environment variable:

echo $ENVVAR

The Best iPhone Apps

Despite what Apple may think, they don’t create the world’s greatest apps. I love my iPhone, but to really get the best experience outside of jailbreaking (work frowns on that) there are a handful of apps I use almost daily. Since I had a friend recently ask me about some of them I thought you, dear reader, may also find my “insight” useful. So in the interest of creating an up-to-date list of what i consider to be essential iPhone apps, I’ve created a page dedicated to The Best iPhone Apps!

Hit up the page for all my recommended iPhone apps, but here’s the top 3…

Toodledo
After trying just about every single to-do and task list manager under the sun, the one I keep coming back to is Toodledo.
Drafts
Far and away the best note taking and all purpose app
Fantastical
I wasn’t sure it would be worth it, but this app is so much better than the Apple calendar.

Hope you find something useful.

Google Chrome Keyboard Shortcuts for Tabs

So I hope by now everyone knows that Ctrl+T opens a new tab in Chrome, but I always forget these shortcuts so hope they help trigger your memory too…

  • Ctrl+T = Open a new tab
  • Ctrl+W = Close the current tab
  • Ctrl+1 through Ctrl+8 = Go to the tab at the specified position in the window
  • Ctrl+9 = Go to the last tab in the window
  • Ctrl+Tab = Go to the next tab in the window
  • Ctrl+Shirt+Tab = Go to the previous tab in the window

Note: Yes, these all appear to work in FireFox too. I’m just partial to Chrome.