EDIT 2022: This method works, but please use it at your own risk. I had this auto-reply feature running successfully for close to a year. Today I logged in to Google Voice to find my account had been suspended. My assumption is that it is due to the auto-replies being sent via Google Scripts. Perhaps it perceives this as spam. Be aware that I rarely receive texts, so I was not sending many auto-replies, maybe one every week or so, so even at that minimal level, it might cause issues to your account. There is an appeal process, but not sure how that will work.
EDIT2: They reviewed my appeal and in less than 24 hours re-instated the account. I was very transparent in the appeal, and mentioned I was sending auto-replies via Google Scripts to inform friends of my unavailability. It appears sending any sort of auto-replies is against their TOS, and might flag your account at some point, so be aware.
I had the same issue you're describing; it's because Canned Responses and Vacation Responders are sent to the return address found in the SMTP envelope (displayed as the Return-Path in the headers), rather than the 'from' value.
Luckily, I found a different tutorial: llyang's google voice auto-reply tutorial. This awesome little tutorial uses Google Apps Script to accomplish the task. It is super simple, and the entire process only takes about 5 minutes to get up and running, even if you have never used Google Apps Scripts before (I had not..). I have tested it out and it works! It's currently running on my google voice account. Give it a shot!
Below is a summary of llyang's tutorial, along with the script code (with some minor modifications) which can be pasted directly in to Google Apps Script. Feel free to go directly to the tutorial and check it out there instead.
Strategy:
Set up your Google Voice account to forward message to your Gmail account (set up to get an email any time someone texts you.)
In the Gmail account the GV texts get forwarded to, create a label called 'autoreply'.
Now, in that same gmail account, create a filter that assigns all the incoming text message emails to the 'autoreply' label created in Step 2. (Example filter - match all emails with the subject "New text message from", or whatever it displays for you...)
Create a script on Google Apps Script which circulates through all emails in the 'autoreply' label in your Gmail account, and responds to the unread ones (code below). (To do this: go to Google Apps Script (make sure you are logged in!). Click the "New Project" button to the left. An editor will open up with a skeleton function. Delete it, and paste in the code below...). About the script and how it works: the script circulates through unread emails in the 'autoreplay' label. It parses the 'from' data from the email header (the value which ends in the desired txt.voice.google.com
, rather than the grandcentral.bounces.google.com
one that the canned response sends to). When it sends the email reply, it will send it to that 'from' value (avoiding the problem that vacation auto-replies in Gmail experience...). After responding to the email, the script marks the email as read, that way it isn't caught the next time the script runs.. Important: Make sure script.google.com is logged in to the correct Google account - the one associated with the GMAIL account where the GV texts are being forwarded to.
once you've saved the script, run the script once (you can use the little 'run' button on the editor) so you can grant any required permissions to the script. (You must grant it permissions to read and respond to your emails; if you run it manually, google apps script will automatically prompt you for this.)
Create a trigger to make the new script run every minute. (To do this - go back to the main dashboard on Google Apps Script. Click the 3 dots which appear to the right for the row the project displays on. Select 'Trigger' from the drop-down menu. A new page appears; click 'Add Trigger' on bottom right of the page. A small screen will pop up which will allow you to select options for the trigger). There's various options for configuring your project trigger - you can make it run every minute continuously, you can make it run based on a calendar range (so if you're on vacation for example...) up to you.
If you ever want to turn off the auto-responses, just modify the project and delete the trigger.
Below is my own variation of llyang's code; it can be pasted directly in to the editor in Step 4 (just make sure to modify the variable 'blackList', to include your own numbers). This is based on his strategy, but with a few modifications. I've also added the ability to exclude (blacklist) certain numbers from receiving auto-replies - this is important, because many businesses/etc., send their own auto-replies to unexpected texts. You might want to exclude them, or you could end up in an endless loop of auto-replies. (Example - notifications from shipping services like Fedex - if you send an auto-response to their texts, you will get an auto-response back saying "invalid", you will respond to that, etc..)
If you find my code confusing, I'd encourage you to check out llyang's tutorial, to see if you find it more pleasing.
P.S. - If you wish to see console output (console.log lines) in Google Apps Script, you can run the script manually by pressing the little run button above the editor - the console output will appear beneath the editor.
/**
* CODE TO PASTE INTO EDITOR IN STEP 4
*
* you should modify the following 3 variables:
* (1) labelName (2) AUTOREPLYMSG, (3) blackList
*
* everything else can remain as it is.
*
*/
/**
* ---> (1) labelName
*
* Name of the label you created in STEP 2
* (if your label is nested, add "/" for each level of nesting -
* ex: 'gvtexts/autoreply'. If it's not nested, it's just
* whatever you named the label.)
*/
var labelName = "autoreply";
/**
* ---> (2) AUTOREPLYMSG
*
* The message you want to send in the auto-replies
*/
var AUTOREPLYMSG = "AUTO-REPLY: I'm on vacation. Talk to you later!";
/**
* ---> (3) blackList
*
* Any numbers you do NOT want auto-replies sent to
*
* Write numbers as they appear in the "From" header of the text message emails
* Example:
* A "From" header:
* "My Friend" <[email protected]>
* The sender's number in that header is:
* 14025555555
* So if you want to exclude this sender from receiving autoreplies,
* add "4025555555", or some substring of that, to this array
*/
var blackList = ["18005555555", "28777", "4025555555"];
/** REMAINING CODE STAYS THE SAME **/
// hash maps to keep track if you've already replied to a sender, or if they're excluded from auto-replies
var repliedToMap = {};
var canAutoReplyToSenderMap = {};
function autoReplier() {
// get GmailLabel object for the label set up in Step 2.
var labelObj = GmailApp.getUserLabelByName(labelName);
// get all email threads in the label
var labelThreads = labelObj.getThreads();
var numUnreadThreads = labelObj.getUnreadCount();
var labelThread;
var messages;
var message;
var fromStr;
// iterate through the threads in the label until you've found all
// the unread ones (the unread threads contain the new text messages)
var numUnreadThreadsFound = 0;
for (var gg = 0; gg < labelThreads.length; gg++) {
if (numUnreadThreadsFound === numUnreadThreads) {
// no more new text messages - you're done
break;
}
// get next thread in label
labelThread = labelThreads[gg];
// check if any unread emails (new text messages) in thread
if (labelThread.isUnread()) {
numUnreadThreadsFound++;
// get all email messages in the thread
messages = labelThread.getMessages();
for (var ii = 0; ii < messages.length; ii++) {
message = messages[ii];
if (message.isUnread()) {
// get 'From' String from email header
fromStr = message.getFrom();
console.log("'From' header of email: " + fromStr);
// get sender's number from the 'From' string
var sender = getSenderNumber(fromStr);
console.log("sender's phone number: " + sender);
if (sender === null) {
throw new Error("issue getting sender number");
} else {
// check if sender's number excluded from auto-replies (in blackList array)
if(canAutoReplyToSender(sender)) {
// sender not blacklisted. Check if already replied to them
if (!(sender in repliedToMap)) {
console.log("sending auto-reply to sender " + fromStr);
MailApp.sendEmail(fromStr, "Auto Reply", AUTOREPLYMSG);
/**
* IMPORTANT:: mark that you've replied to this sender,
* or you could end up sending them multiple replies
* (multiple threads can exist for a single sender,
* so you could encounter same sender in a later iteration)
*/
repliedToMap[sender] = true;
}
}
// any remaining messages in thread are from the same number; skip them
break;
}
}
}
// mark all msgs in thread as read, or will keep replying every time script runs
labelThread.markRead();
}
}
}
/**
* Takes 'From' String of email header and returns sender's phone number.
* Example:
* String of 'From' header:
* "(402) 555-5555 <[email protected]>"
* returns: "14025555555"
*/
function getSenderNumber(fromHeader) {
var fromRegex = /.*<\d+\.(\d+)\[email protected].*/;
var senderInfo = fromHeader.match(fromRegex);
if (senderInfo === null) {
throw new Error("Couldn't extract sender's number "
+ " from 'from' string of email:\n"
+ fromHeader
+ "\n(Has header format changed?)");
} else {
return senderInfo[1]; // found sender's phone number
}
}
/**
* checks if a sender can receive auto-replies (not blacklisted)
* hash result as number may be queried multiple times
*
* var sender <String> (the number you want to check, i.e. "18005555555")
* returns <Boolean>: true if not in blackList, false if in blackList
*/
function canAutoReplyToSender(sender) {
if(!(sender in canAutoReplyToSenderMap)) {
// haven't yet checked this number against blacklist entries
// check if any entries in blackList are substrings
var canAutoReplyToSender = true;
for (var jj = 0; jj < blackList.length; jj++) {
/**
* note : if the following comparison is failing
* for you only a single entry in the blackList,
* make sure you do not have any invisible trailing char in your String.
* I've found if I copy/paste a number directly from the
* Google Voice website, it often includes a trailing
* char at the end of the String which does not appear
* in the editor. As a result, this comparison would fail.
* You can check for this by going to that string, and
* hitting backspace between the last number in the String
* and your final quote on the String - if the String
* appears the same even after the backspace, you have
* just deleted this trailing char. Now the String should work.
*/
if (sender.indexOf(blackList[jj]) > -1) {
console.log("Sender " + sender + " black listed from receiving auto-replies.");
canAutoReplyToSender = false;
break;
}
}
canAutoReplyToSenderMap[sender] = canAutoReplyToSender;
}
var canSend = canAutoReplyToSenderMap[sender];
console.log("Can send auto-replies to " + sender + " ? " + canSend);
return canSend;
}
Hope this helps. I have this running and it's working great for me.
EDIT: I have twice run in to a strange "bug" with the blackList that I want to make others aware of. Sometimes I'd noticed, even though a number was in my blackList
array, texts from that number were still receiving autoreplies. I would go back and check the number, and it was typed in the array correctly. I finally realized what was happening - sometimes when I copy/paste a number directly from Google Voice's website in to the script, it's retaining a trailing character which doesn't show up in the Google scripts editor. As a result, it appears as though you have the correct number in the array, but in reality, you've got an invisible trailing character; the if comparison in canAutoReplyToSender()
for that black list entry then fails when the sender has come from that number, and an autoreply ends up being sent. I'm not sure what this extra character is. It's not a trailing whitespace, because if I add trim() in the comparison statement (i.e., if (sender.indexOf(blackList[jj].trim()) > -1
) it still fails. Similarly, it does not appear to be a newline character either, as regex replacing all newlines also has no effect. If this happens to you, here is what I've had to do: for the problem String in blackList
, go to the end of the String (between last number of the String and your end quote around the string, i.e., for string "5555555554"
, go between 4
and "
), then hit backspace. This will delete the trailing character, even though the String itself will appear the same. Now the string will work. I suppose the best thing to do, would be to have the script handle this - look at the last character on the String, and if it's not a number, delete it, but to be honest I don't have the time at the moment, so just adding this comment.