I'm using this code from Greg Baugues (https://www.twilio.com/blog/2016/02/send-sms-from-a-google-spreadsheet.html) to send texts in bulk using Google sheets and Twilio.
I want to tell sendSMS and/or sendAll to skip existing sheet entries where 'sent' appears in the relevant cell, so as to allow the sheet to function as a database as well as a mere messaging machine.
Any ideas?
(The XXX entries are simply to anonymize my Twilio account and phone number).
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [ {name: "Send text msg to client", functionName:
"sendAll"}, ];
ss.addMenu("Text", menuEntries);
}
function sendSms(to, body) {
var messages_url = "https://api.twilio.com/2010-04-
01/Accounts/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages.json";
var payload = {
"To": to,
"Body" : body,
"From" : "+XXXXXXXXXX"
};
var options = {
"method" : "post",
"payload" : payload
};
options.headers = {
"Authorization" : "Basic " +
Utilities.base64Encode
("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
};
UrlFetchApp.fetch(messages_url, options);
}
function sendAll() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow() - 1;
var dataRange = sheet.getRange(startRow, 1, numRows, 4)
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
try {
response_data = sendSms(row[1], row[2]);
status = "sent";
} catch(err) {
Logger.log(err);
status = "error";
}
sheet.getRange(startRow + Number(i), 4).setValue(status);
}
}
function myFunction() {
sendAll();
}
You need to edit your sendAll() function so that it tests the value of the status column to decide if it should skip that row or not.
Use this:
function sendAll() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow() - 1;
var dataRange = sheet.getRange(startRow, 1, numRows, 4)
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
try {
if (row[3] != "sent") {
response_data = sendSms(row[1], row[2]);
status = "sent";
}
} catch(err) {
Logger.log(err);
status = "error";
}
sheet.getRange(startRow + Number(i), 4).setValue(status);
}
}
This works (thanks Andy):
function sendAll() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow() - 1;
var dataRange = sheet.getRange(startRow, 1, numRows, 5)
var data = dataRange.getValues();
for (i in data) {
var status;
var row = data[i];
if (row[3] !== "sent") {
try {
response_data = sendSms(row[1], row[2]);
status = "sent";
} catch(err) {
Logger.log(err);
status = "error";
}
}
sheet.getRange(startRow + Number(i), 4).setValue(status);
}
}
Related
The code below works perfectly and sends the email I need it to send on an "OnChange" trigger. However, it sends an email for EVERY checked box in row 7 which is overload, it just needs to send an email for newly checked boxes.
Any advice on how to add a condition in the below code for this?
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Service');
var data = sheet.getDataRange().getValues();
for (var i = data.length - 1; i >= 1; i--) {
if (sheet.getRange(i,7).isChecked()){
var name = sheet.getRange(i,1).getValue();
var last = sheet.getRange(i,2).getValue();
var body = name + " " + last
var subject = 'New Service Item in Stock'
MailApp.sendEmail('me#mycompany.com', subject, body);
}
}
}
I haven't tried anything because there is nothing I could find online to get me in the right direction.
https://i.stack.imgur.com/cKfLv.png
Try unchecking them after you send them:
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Service');
var data = sheet.getDataRange().getValues();
for (var i = data.length - 1; i >= 1; i--) {
if (sheet.getRange(i, 7).isChecked() && sheet.getRange(i,8).getValue() != "Sent") {
var name = sheet.getRange(i, 1).getValue();
var last = sheet.getRange(i, 2).getValue();
var body = name + " " + last
var subject = 'New Service Item in Stock'
MailApp.sendEmail('me#mycompany.com', subject, body);
sheet.getRange(i, 8).setValue("Sent");
}
}
}
Performance improvement:
function sendEmails() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('Service');
var vs = sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).getValues();
vs.forEach((r, i) => {
if (sh.getRange(i + 2, 7).isChecked() && r[7] == "Sent") {
let body = `${r[0]} ${r[1]}`;
let subject = "New Service Item in Stock";
MailApp.sendEmail('me#mycompany.com', subject, body);
sh.getRange(i, 8).setValue("Sent");
}
});
}
I have an issue with this google sheet macro. Error message is: Exception: Range not found
I am trying to perform this script in order to copy recipient string (that can change according to data in P2 cell.
Can you help me?
Thanks
function macro()
{
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange("A2:L1000");
var data = dataRange.getValues();
for (i in data)
{
var rowData = data[i];
var recipient = rowData[0];
var parameter1 = rowData[1];
if (parameter1 == "OK")
{
sheet.getRange('P2').activate();
sheet.getRange(recipient).copyTo(sheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
}
}
}
Perhaps this is what you want:
function macro() {
var sh = SpreadsheetApp.getActiveSheet();
var rg = sh.getRange("A2:L1000");
var data = rg.getValues();
data.forEach((r,i)=>{
if(r[1] == "OK") {
sh.getRange(r[0]).copyTo(sh.getRange(i + 2, 16),SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
}
})
}
I have made something like this but it is only copy/paste first row (copy B2 to P2 works fine).
If I try to copy B3 to P2 it does not work..
function macro()
{
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange("A2:L1000");
var data = dataRange.getValues();
for (i in data)
{
var rowData = data[i];
var parameter1 = rowData[10];
if (parameter1 == "OK")
{
sheet.getRange('P2').activate();
sheet.getRange("B" +(i+2)).copyTo(sheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
}
}
}
I'm experiencing an error called code 500. The script works fine if I'm using it in the owner account, but if I'm going to open the file as a user/editor, the code 500 error shows. Here is the link to the sample spreadsheet that I'm working on. I tried asking here but seems like it is a little complicated so I created a new single spreadsheet so that it can be easily identified the error.
Here's the code
function doGet(e) {
this[e.parameter.run](e.parameter.sheetName || null);
return ContentService.createTextOutput('It worked!');
}
function HideRows() {
const activeSheet = SpreadsheetApp.getActiveSheet();
const url = ScriptApp.getService().getUrl();
UrlFetchApp.fetch(url + "?run=script_HideRows&sheetName=" + activeSheet.getSheetName(), {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}});
// DriveApp.getFiles() // This is used for automatically detecting the scope of "https://www.googleapis.com/auth/drive.readonly". This scope is used for the access token.
}
function showRows() {
const url = ScriptApp.getService().getUrl();
UrlFetchApp.fetch(url + "?run=script_showRows", {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}});
Browser.msgBox(url + "?run=script_showRows");
}
var startRow = 6;
var colToCheck = 2;
// This script is the same with your "HideRows".
function script_HideRows() {
var sheetNames = ["MS_Q1", "MS_Q2", "MS_Q3", "MS_Q4", "SUMMARY"]; // Please set the sheet names here. In this case, 4 sheets are used.
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.getSheets().forEach(sheet => {
var sheetName = sheet.getSheetName();
if (sheetNames.includes(sheetName)) {
if (sheetName == "SUMMARY") { // When the sheet is "SUMMARY", the start row is changed.
startRow = 7;
}
var numRows = sheet.getLastRow();
var elements = sheet.getRange(startRow, colToCheck, numRows).getValues();
for (var i=0; i < elements.length; i++) {
if (shouldHideRow(sheet, i, elements[i][0])) {
sheet.hideRows(startRow + i);
}
}
// Hide the rest of the rows
var totalNumRows = sheet.getMaxRows();
if (totalNumRows > numRows)
sheet.hideRows(numRows+1, totalNumRows - numRows);
}
});
}
// This script is the same with your "showRows".
function script_showRows() {
// set up spreadsheet and sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// var ss = SpreadsheetApp.getActiveSpreadsheet(),
var sheets = ss.getSheets();
for(var i = 0, iLen = sheets.length; i < iLen; i++) {
// get sheet
var sh = sheets[i];
// unhide columns
var rCols = sh.getRange("1:1");
sh.unhideColumn(rCols);
// unhide rows
var rRows = sh.getRange("A:A");
sh.unhideRow(rRows);
}
};
function shouldHideRow(ss, rowIndex, rowValue) {
if (rowValue != '') return false;
if (ss.getRange(startRow + rowIndex, colToCheck, 1, 1).isPartOfMerge()) return false;
if (ss.getRange(startRow + rowIndex + 1, colToCheck, 1, 1).isPartOfMerge()) return false;
return true;
}
First, comment out this
// this [e.parameter.run] (e.parameter.sheetName || null);
Second, avoid this
const url = ScriptApp.getService().getUrl();
replace to
const url = 'https://script.google.com/macros/s/ABCD1234/exec';
Third, publish the web app for all user accessing every time you change code
The next code works for me fine
function doGet(e) {
return ContentService.createTextOutput('It worked!');
}
function HideRows() {
const activeSheet = SpreadsheetApp.getActiveSheet();
const url =
'https://script.google.com/macros/s/ABCD1234/exec';
var response = UrlFetchApp.fetch(
url + '?run=script_HideRows&sheetName=' + activeSheet.getSheetName(),
{
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
muteHttpExceptions: true,
}
);
Browser.msgBox(response);
}
I have this Macro to send emails to some people. The problem is that it pastes the table in values, not in table format. I need to paste the table as a table.
function Mails() {
var values = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var filas= values[0][1];
var columnas= values[1][0];
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName("Enviar"));
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange(2,4,filas,columnas);
var data = dataRange.getValues();
for (i in data) {
var rowData = data[i];
var emailAddress = sheet.getRange(1, 3).getValue();
var destinatario = rowData[0];
var sigla1 = sheet.getRange(2,4,filas,columnas).getValues();
var mensaje = 'Estimado ' + destinatario + ',\n\n' + sigla1 ;
var asunto = 'Mensajes Pendientes';
MailApp.sendEmail(emailAddress, asunto, mensaje);
}
}
function onOpen () {
var spreadsheet = SpreadsheetApp.getActive();
var menuItems = [
{name: 'Send Emails', functionName: 'Mails'}
];
spreadsheet.addMenu('Enviar Emails', menuItems);
}
The problem is this line var sigla1 = sheet.getRange(2,4,filas,columnas).getValues();
I have to paste it as a table, not in values. How can i do that?
Thanks
I'am trying with this code now.. but it doesn't function..
function Mails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName("Enviar"));
var sheet = SpreadsheetApp.getActiveSheet();
var values = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var filas= values[0][1];
var columnas= values[1][0];
var recipient = sheet.getRange(1, 3).getValue();
var subject = 'Estimado';
var vA=SpreadsheetApp.getActive().getSheetByName('Enviar').getDataRange().getValues();
var html="<style>th,td{border:1px solid black;}<table>";
for(var i=0;i<vA.length;i++) {
html+="<tr>";
for(var j=0;i<vA[i].length;j++) {
if(i==0) {
html+=Utilities.formatString('<th>%s</th>', vA[i][j]);
}else{
html+=Utilities.formatString('<td>%s</td>', vA[i][j]);
}
}
html+="</tr>";
}
GmailApp.sendEmail(recipient, subject, null, {htmlBody:html})
}
function onOpen () {
var spreadsheet = SpreadsheetApp.getActive();
var menuItems = [
{name: 'Send Emails', functionName: 'Mails'}
];
spreadsheet.addMenu('Enviar Emails', menuItems);
}
Here you have an image of what i need to send via email.
The rows change with the data, so the table depend of how many operations are in the day..
Html Table into Email
function sendHtmlTableViaEmail() {
var vA=SpreadsheetApp.getActive().getSheetByName('name').getDataRange().getValues();
var html="<style>th,td{border:1px solid black;}<table>";
for(var i=0;i<vA.length;i++) {
html+="<tr>";
for(var j=0;i<vA[i].length;j++) {
if(i==0) {
html+=Utilities.formatString('<th>%s</th>', vA[i][j]);
}else{
html+=Utilities.formatString('<td>%s</td>', vA[i][j]);
}
}
html+="</tr>";
}
//You have to add the code for recipient and subject
GmailApp.sendEmail(recipient, subject, null, {htmlBody:html})
}
i've made script for coping the details with the help of id column which will common in both sheets this code is not copying any detail
function myFunction()
{
}
function onOpen() {
var subMenus = [
{name:"Generate farnchise username", functionName: "approveRequests"},
];
SpreadsheetApp.getActiveSpreadsheet().addMenu("Custom Functions", subMenus);
}
function approveRequests() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
sheet = ss.getActiveSheet(),
sheetName = sheet.getName(),
data = sheet.getDataRange().getValues();
if (sheetName == "g6-live-properties") {
var range = sheet.getActiveRange(),
startRow = range.getRowIndex(),
numRows = range.getNumRows(),
numCols = range.getNumColumns()
if (numCols == 3) {
if (data.length > 1) {
var values = range.getValues(),
nextSheet = ss.getSheetByName("11-Apr-60+"),
lastRow = nextSheet.getLastRow();
nextSheet.getRange(lastRow+1,1,numRows,3).setValues(values);
sheet.deleteRows(startRow,numRows);
}
}
}
}