Setting Up a Recruiter Auto-reply Bot

If you’re a software engineer, you’re likely familiar with unsolicited emails from recruiters. Most are probably template emails. Some of them are funny, some are thoughtful, and some of them ask you to move 3000 miles, take a 50% pay cut, and code in a language you don’t know.

Impact

Recruiter emails have a measurable impact on productivity. If I were to hand-write a response to each one (taking 2 minutes), and I got 1 recruiter email a day, that’s 12 hours of work, or more than one full work day of each year… gone.

Even if I ignore these emails, it still takes time to triage them. If you ignore recruiters, they commonly keep emailing you 3, 4, even 5 times. Muting the thread helps with some, but not all, of these cases.

Gmail has a “canned responses” feature. I’ve used this in the past, but it still requires manual work, which gets tiring.

So—while fully acknowledging that ignoring recruiters comes from a place of immense privilege—I need to find a way to minimize their time drain on my life, while at the same time not being a jerk.

Important: never be a jerk to recruiters.

Using Apps Script

I decided to create a Google Apps Script to send an automatic reply to any thread with the label Recruiters. The Gmail API makes this pretty easy.

This script:

Here’s the full script:

function init() {
  // Whether to actually send emails, or just log.
  const LIVE_MODE = false; // TODO change this to true when ready to go live.

  const myEmail = Gmail.Users.getProfile('me').emailAddress;
  if (!myEmail || myEmail.indexOf('@') === -1) {
    throw new Error('Error fetching my email.');
  }
  log('My email: '+myEmail);

  // Fetch threads.
  const start = 0;
  const max = 10;

  var threads = GmailApp.search('label:Recruiters after:2019/05/30', start, max);
  log('Fetched '+threads.length+' threads');

  threads.forEach(function(thread) {
    const messages = thread.getMessages();
    const firstMessage = messages[0];
    const lastMessage = messages[messages.length-1];

    log('=================== New thread');
    log('First message:');
    log('from: '+firstMessage.getFrom());
    log('Last message:');
    log('subject: '+lastMessage.getSubject());
    log('from: '+lastMessage.getFrom());
    log('sent: '+lastMessage.getDate()+' ('+
      daysSince(lastMessage.getDate(), Date.now())+' days ago)');

    // Skip threads where I've already replied to any message.
    const hasReplied = messages.some(function(message) {
      return message.getFrom().indexOf(myEmail) !== -1;
    });
    if (hasReplied) {
      log('Already replied once, skipping...');
      return;
    }

    if (!LIVE_MODE) {
      log('--- Would have replied to email here ---');
    }

    const replyBody = createReplyBody('Jeff'); // TODO replace your name here.
    lastMessage.reply(replyBody);
    log('Reply sent!');
  });
}

function log(msg) {
  // Log to both Logger and console. Logger for development, console for
  // Stackdriver logging.
  Logger.log(msg);
  console.log(msg);
}

function createReplyBody(name) {
  return ["Hi there,\n\n",
    "Thanks for reaching out. I sincerely appreciate your consideration, ",
    "however I am currently not looking for new opportunities.\n\n",
    "Regards,\n",
    name,
  ].join('');
}

// Takes two Unix timestamps in milliseconds.
function daysSince(dateA, dateB) {
  return Math.round(Math.abs((dateA - dateB)/(24*60*60*1000)));
}

How to Use This Yourself

Steps to set this up for yourself:

  1. Open up my script.
  2. Make a copy (File > Make a copy).
  3. Replace your name (see 2nd TODO comment).
  4. Turn the Gmail API on: Resources > Advanced Google Services > Gmail API (click ‘on’).
  5. In the Select function dropdown, select init and run the script.
  6. Open up the logs (Ctrl + Enter) to verify it ran properly.
  7. Add a time-based trigger. I run mine every 2 hours.
  8. When ready, set LIVE_MODE to true and save.

All set! Now tag recruiter emails with the label Recruiters and let the bot do the rest of the work.

Contents (top)