MailApp not sending with large number of recipients - javascript

My code takes an input of emails that looks like this:
email1#gmail.com, email2#gmail.com, email3#gmail.com ...
and tries to send them an email using the following code.
function sendEmail(form) {
var ss = SpreadsheetApp.getActive();
var body = form.body;
var bcc = form.bccfield;
var cc = form.ccfield;
var to = form.tofield;
var subject = form.subject;
var eHandle = ss.getSheetByName("Email Handling");
var sig = eHandle.getRange(10, 2).getValue();
var img = eHandle.getRange(11, 2).getValue();
var sigImage = '<img src ="' + img + '" >';
MailApp.sendEmail({
to: to,
cc: cc,
bcc: bcc,
subject: subject,
htmlBody: body.replace(/\n/g, '<br>') + sig + sigImage});
}
It seemed to always be working but now I'm trying to send to a class list of parents (about 55 at a time) and it just doesn't send anything (the code doesn't even finish). I am GSuite for Education so I should have a limit of over 1,000 recipients per day.
I'm pretty sure the only difference which now causes a problem is the number of recipients.

You are not allowed to sent an email to more than 50 recipients at a time.
Number of recipients per email is part of Quotas for Google Services.
You are only allowed to sent an email with a maximum number of 50 recipients.
An obvious workaround would be to split the recipients into two or more (depending upon the number of recipients) different emails so this hard limitation won't be violated.

Related

MailApp.sendEmail sending email to my inbox even my even not set together to get the email

I have an email script that will send out email to all emails that are in the list of a google sheet. But then, when I run the script, it is also sent to my Inbox instead of only to register into my Sent folder. Before this no issue (after being using the same script for a long time, 1+ year), it just happened a few months back.
I've found similar issue from this post but couldn't get the suggestions work, example:
To replace Mailapp.sendEmail with Gmailapp.sendEmail
Checked if I have any wrong filter in my email
Attached the script as below:
function arrayUnique(arr) {
var tmp = [];
// filter out duplicates
return arr.filter(function(item, index){
var stringItem = item.toString(); // convert row arrays to strings for comparison
tmp.push(stringItem); // push string items into temporary arrays
return tmp.indexOf(stringItem) >= index; // only return the first occurrence of the strings
})}
function sendEmail() {
var sheet = SpreadsheetApp.getActive().getSheetByName("pending list")
var sub = "Error Fix Required"
var data = sheet.getRange(3,1, sheet.getLastRow(), 5).getDisplayValues().filter(function (row){
var date = sheet.getRange(1,2).getDisplayValues()
return row[3] == date
})
var filterunique = arrayUnique(data)
var json = {}
filterunique.forEach(function (item){
if(item[2] || item[2].length > 0){
if(!json[item[2]]){
json[item[2]] = []
}
json[item[2]].push(item[0])
}
})
Object.keys(json).forEach(function(to){
var email = "{{user}}#shopee.com"
email = email.replace(/{{user}}/gi,to)
var sku = "<br><ul><li>" + json[to].join("</li><li>") + "</li></ul>"
var body = "Hi " + to +", <br><br>The following require your kind attention:" + sku + "Please go to this <a href='https://docs.google.com/spreadsheets/d/1nMKeW//'>link</a> to rectify your submissions by today 4pm.<br><br> Thanks."
MailApp.sendEmail({
to: email,
subject: sub,
htmlBody: body
});
})
}
Also attached what I received in my Inbox:
Change this:
MailApp.sendEmail({to: email,subject: sub, htmlBody: body});
to this:
GmailApp.sendEmail(emai,sub,'',{htmlBody:body});

Extracting Email Address & Name From Forwarded Emails

I'm trying to use Google Script to extract email address and name from forwarded emails that I've filed under a specific label.
The emails look like this:
From: Person A
Sent: Sunday, September 22, 2019 8:00 PM
To: Other, Email
Subject: Forwarded Email
BODY
They have all have been forwarded to this specific inbox. Therefore the headers actually include my other email address I forwarded from.
I've sorted over 2000 emails and now for each of the labels I want to extract the name of the sender (Person A) and their email address (person#gmail.com) in a spreadsheet. Preferably, I can have the first and last name in separate cells (e.g. Person | A | email address)
The code I have thus far is below:
function processInboxToSheet() {
// Have to get data separate to avoid google app script limit!
var start = 0;
var label = GmailApp.getUserLabelByName("LABEL");
var threads = label.getThreads();
var sheet = SpreadsheetApp.getActiveSheet();
var result = [];
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
var content = messages[0].getPlainBody();
// implement your own parsing rule inside
if (content) {
var tmp;
tmp = content.match(/From:\n([A-Za-z0-9\s]+)(\r?\n)/);
var name = (tmp && tmp[1]) ? tmp[1].trim() : 'No name';
tmp = content.match(/<\n([A-Za-z0-9#.]+)/);
var email = (tmp && tmp[1]) ? tmp[1].trim() : 'No email';
sheet.appendRow([name, email]);
Utilities.sleep(500);
}
}
};
I only get No name and No email as output so something is not quite working in the code. I would appreciate your help.
You are parsing the plain body, it doesn’t contain to and from. It only contains the message body. The API has methods getTo() and getFrom() that contains what you want to parse. See the API for GmailMessage for more details.

Syntax issue involving a ".replace" function

So I have a Google sheet that collects registration data from customers. Included in the data collected is a student's name, the session the student elected to attend and a credit card number. Once a submission has been made, I get a notification. Upon notification, I go to my Google sheet and charge the credit card the appropriate amount.
Once the credit card has been charged, I then want to generate a confirmation email to the customer that includes the student's name, the session the student registered to attend and the amount charged to the credit card. My code seems to work fine except when it comes to replacing curly bracket placeholders in my "template text" (i.e., {Name},{sessions} and {ChargeAmount} with the actual values which I've defined as variables.
Note: When I just replace {StudentName} with text like "Joe" it works. However, {Sessions} does not get replaced and neither does {ChargeAmount}. I think this is a syntax error.
Here's what I really want to happen but can't get to work:
var emailText = templateText.replace("{Name}",studentName);templateText.replace("{Sessions}",sessionName);templateText.replace("{ChargeAmount}",ChgAmt);
function SendEmail() {
// Fetch the email address
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange("B2");
var studentRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange("C2");
var studentName = studentRange.getValues();
var sessionRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange("D2");
var sessionName = sessionRange.getValues();
var emailAddress = emailRange.getValues();
var ChgAmt = Browser.inputBox("Charge Amount");
var templateText = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Template").getRange(1,1).getValue();
// NOTE! What I really want to do is replace {Name} with the var "studentName"... not the text "Joe", {Sessions} with the var "sessionName" and {ChargeAmount} with the var "ChgAmt". I can't this to work either! STRUGGLING!!!
var emailText = templateText.replace("{StudentName}","Joe");templateText.replace("{Sessions}","May - Session#1");templateText.replace("{ChargeAmount}","$500");
// Send Alert Email.
var subject = 'Junior Golf Clinic Registration Receipt';
var message = emailText;
MailApp.sendEmail(emailAddress, subject, message);
}
Here's the result of my existing code which does not properly pull in the values I need.
useremail#gmail.com
9:18 AM (37 minutes ago)
to me
This is the email body.
This is the amount charged to credit card {ChargeAmount}. [Not right. This should be the actual value represented by the var "ChgAmt"]
This is the student's name: Joe [this seems to work when I replace the placeholder {Name} with text like "Joe" but not when I try to replace the placeholder {Name} with the var "studentName"]
These are the sessions the student is scheduled to attend: {Sessions}
[Not right. This should be the actual sessions represented by the var "sessionName"]
Here's more information about the clinics themselves.
This line is incorrect, you're never actually storing your other replace statements.
var emailText = templateText.replace("{StudentName}","Joe");templateText.replace("{Sessions}","May - Session#1");templateText.replace("{ChargeAmount}","$500");
It should be:
var emailText = templateText.replace("{StudentName}","Joe").replace("{Sessions}","May - Session#1").replace("{ChargeAmount}","$500");
As jmcgriz notes, the problem is with the separate calls to .replace. Chaining them fixes your issue.
Here is some dummy code showing what that might look like:
function SendEmail() {
// fetch these values as you need
var studentName = 'Joe'
var sessionName = "May - Session#1";
var emailAddress = 'joe#joe.com'
var chargeAmt = "$500";
// This is what needed to change
var emailText = templateText
.replace("{StudentName}", studentName)
.replace("{Sessions}", sessionName)
.replace("{ChargeAmount}", chargeAmt);
var subject = 'Junior Golf Clinic Registration Receipt';
var message = emailText;
MailApp.sendEmail(emailAddress, subject, message);
}
SendEmail()
<script>
// Mocking MailApp for testing
const MailApp = {
sendEmail: (addr, subj, mess) =>
console.log(`Sending "${addr}" email "${subj}"\n\n${mess}`)
}
const templateText = `
This is the email body.
This is the amount charged to credit card {ChargeAmount}.
This is the student's name: {StudentName}
These are the sessions the student is scheduled to attend: {Sessions}
Here's more information about the clinics themselves.`
</script>

Email multiple rows to one recipient based on category values using Apps Script

What I'm looking for:
I am working on a spreadsheet that contains transaction information for multiple people. Some people have only 1 transaction (1 row of information) while others may have multiple transactions (rows of information). So far, the code I am working on is able send an email containing one transaction per email. However, I am having trouble figuring out how to group multiple transactions into one email. One of the column fields is "Email address" and ideally I could use that to group multiple rows. Pretty much a mail merge that can be grouped by a column in the spread sheet or by the identification of similar values.
What I've tried/what I'm thinking:
I already have the code sort by email address so that the transactions for each person are consecutive on the sheet. I am thinking that I need to loop with an if statement saying something along the lines "if the next value in the 'email address' field is the same as the previous one, add a new line in the body of the email." From what I have researched I might need to do a loop within a loop for the email body but I am not completely sure how to go about that. In the code I have, I have already somewhat formatted the email the way it should be.
Disclaimer:
I'm pretty new to coding so any help is appreciated. I am unsure how to loop in the body of the message and eventually exit once the script hits a different person. I'd like to do it all in GAS.
This is what I've got so far:
var SENT = "Y";
function sendEmails() {
//This section specifies the sheet and some definitions we are working with
var sheet =SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var lastrow = sheet.getLastRow();
var startrow = 4; // First row of data to process
var numrows = lastrow; // Number of rows to process
sheet.sort(14, true); //Sorts the sheet by email address
//This section formats the columns so they appear correctly in the html email below
var column = sheet.getRange("K4:L");
column.setNumberFormat("MM/dd/yyyy"); // Simple date format
var column = sheet.getRange("M:M");
column.setNumberFormat("#"); // Simple plain text format
var column = sheet.getRange("K4:L");
column.setNumberFormat("#"); // Simple plain text format
var column = sheet.getRange("E:E");
column.setNumberFormat("$0.00"); // Simple currency format
//This section specifies the actual data we will be working with
var datarange = sheet.getRange(startrow, 1, lastrow, 15)// Fetch the range of cells
var data = datarange.getValues();// Fetch values for each row in the Range.
//Defining column data
for (var i = 0; i < data.length; ++i) {
var col = data[i];
var firstname = col[2]; // Column starting at 0 from left to right
var expamount = col[4]; // Column starting at 0 from left to right
var subdate = col[10]; // Column starting at 0 from left to right
var trandate = col[11]; // Column starting at 0 from left to right
var reportname = col[12]; // Column starting at 0 from left to right
var emailaddress = col[13]; // Column starting at 0 from left to right
var emailsent = col[14]; //Column starting at 0 from left to right
var subject = "MinistryCard Expenses Over 90 Days"; // Subject for the email to be sent
var emailintro = // Introduction part of the email
'Hi ' + firstname + ', <br /><br />' +
'This is the introduction to the email.' +
'The related expenses are below: <br /><br/ >'
var emailtrans = //THIS IS WHERE I WOULD LIKE THE MAGIC TO HAPPEN... I THINK
'<strong>Report Name: </strong>' + reportname + ' <br /><strong>Transaction Date: </strong>' + trandate + ' <br /><strong>Transaction Amount: </strong>' + expamount +
' <br /><strong>Approval Date: </strong>' + subdate + '<br /><br />'
var emailend = // The endd of the email
'We apologize for any inconvenience this may cause. ' +
'Also, please contact us if you believe you are recieving this email in error. Thank you. <br /><br /><br />' +
'Enjoy your day, <br /><br />'
//The section below retrieves alias email address to send as
var me = Session.getActiveUser().getEmail();// Log the aliases for this Gmail account and send an email as the first one.
var aliases = GmailApp.getAliases(); // Gets the alias ministrycard#cru.org from account
Logger.log(aliases); // Logs the alias
// The section below sends the actual emails
if (emailaddress != "" && emailsent != SENT){
if (aliases.length > 0){ // Prevents sending duplicates
GmailApp.sendEmail(emailaddress, subject , emailintro + emailtrans + emailend, {'from': aliases[0],'replyto': 'ministrycard#cru.org', htmlBody : emailintro + emailtrans + emailend});
sheet.getRange(startrow + i, 15).setValue(SENT);
SpreadsheetApp.flush(); // Make sure the cell is updated right away in case the script is interrupted
}} else { }}}
There are multiple solutions. Here's mine:
declare a nextEmail variable before the main for loop begins.
var nextEmail = '';
at the beginning of the loop, set nextEmail to the email in the next row:
if (i < data.length - 1) {
nextEmail = data[i+1][13]//looks at next row, 13th column
} else {//catch if i is the maximum row
nextEmail = ''
}
add another conditional that checks that the next email address is not the same before sending the email
if (emailaddress != "" && emailsent != SENT && nextEmail != emailaddress){
You didn't seem to specify what parts of the message you want to change each time and what parts you want to stay the same, but I'm assuming you want to change only emailtrans.
now, instead of declaing a new variable emailtrans each time it loops around, declare emailtrans before the loop as an empty string...
var emailtrans = ''
...and instead append the big string to emailtrans
emailtrans +=
'<strong>Report Name: </strong>' + reportname + ' <br /><strong>Transaction Date: </strong>' + trandate + ' <br /><strong>Transaction Amount: </strong>' + expamount +
' <br /><strong>Approval Date: </strong>' + subdate + '<br /><br />';
and then set emailtrans to an empty string right after you send the email, inside of the if statement.
emailtrans = ''
There are a few things you didn't ask about but I still think should be addressed. You probably would have caught a lot of this if only you tested whatever you've got, even if it's incomplete, to make sure it did what you want before asking for help.
SENT variable should probably be declared within the function (good practice)
numrows is only equal to lastrow if startrow is zero. Set numrows to lastrow - startrow and use numrows instead of lastrow when you declare datarange.
You sort the whole sheet based on column M, but your script only collect data from row 4 onward. Depending on your labels in rows 1-3, the sorting might place some emails in rows 1-3 and your labels in row 4 and onward. Instead, I'm guessing you only want to sort the range containing the emails, so do a .sort() on that range instead of the whole sheet.
Putting in semicolons where you define emailintro, emailtrans, and emailend in multiple lines is probably a good idea.
I could be wrong, but it seems the html tags aren't formatted right. <br /><br /> wouldn't insert a break ... they would just end two breaks?
Declaring a variable inside a for loop is bad practice. Declare it outside the loop beforehand, and set it (thing = value), not declare it (var thing = value), inside the loop.
Hope this helps.

Google Scripts: Pull Google Document Based on User ID / Email

Good Morning Stack!
I was looking for some advice for some expanded functionality on a Google Script that helps me track and process absence requests. The process is as follows:
A user submits their form responses
The form responses are stored on a spreadsheet
A google doc, pre-created, is pulled and the values from the spreadsheet are implanted in the document.
The document is converted to a PDF
That PDF is automatically emailed to me.
However, some work policies have changed and I now need this form to have a signature that is unique to the person filling the form. In the past we simply printed the resulting PDF and had the person sign off on it.
I know I do not have the technicality to add on any sort of Electronic Signature functionality, nor is emailing that PDF to them an option as it doesn't create a fillable PDF (and my users don't really know how to digitally sign items anyways)
So what I was thinking is to create a form unique to each of the 15-20 users of this process and instead of a getFileByID, have the script check the Google Users account / email and pull the file created for them and stored in my drive instead.
As follows is my current, functional, script. How could I make this work?
function onFormSubmit(e) {
var Last_Name = e.values[2];
var First_Name = e.values[3];
var Middle_Initial = e.values[4];
var Work_Location = e.values[5];
var Job_Title = e.values[6];
var Contact_Number = e.values[7];
var Start = e.values[8];
var End = e.values[9];
var Time = e.values[10];
var Reason = e.values[11];
var D = new Date();
var copyId = DriveApp
.getFileById("1sdfjlsdf55asdfnk565enasdfnsnsd2")
.makeCopy("AbsenceRequest" + Last_Name + Start).getId();
var copyDoc = DocumentApp.openById(copyId)
var copyBody = copyDoc.getActiveSection();
copyBody.replaceText('keyLastName', Last_Name);
copyBody.replaceText('keyFirstName', First_Name);
copyBody.replaceText('keyMiddleInitial', Middle_Initial);
copyBody.replaceText('keyWorkLocation', Work_Location);
copyBody.replaceText('keyJobTitle', Job_Title);
copyBody.replaceText('keyContactNumber',Contact_Number);
copyBody.replaceText('keyStart', Start);
copyBody.replaceText('keyEnd', End);
copyBody.replaceText('keyTime', Time);
copyBody.replaceText('keyDate', D);
copyDoc.saveAndClose();
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
var Email = "email#email.org" + "," + "email#email.org";
var Subject = "Absence Request"
var Body = "This is an absence request"
MailApp.sendEmail(Email, Subject, Body, {attachments: pdf});
DriveApp.getFileById(copyId).setTrashed(true);
}

Categories

Resources