I have written a script which has a trigger to run every hour, it searches my emails and extracts the data, turns it to a PDF and locates it in a folder if the subject equals "xxxx", it overwrites data in the folder if it already exists.. I would like to add in a new if function where it will only pick up emails for the current day and not history (to save efficiency of the script and data)
function saveGmailAsPDF2() {
var gmailLabels = 'xxxxx';
var driveFolder = DriveApp.getFolderById("folder url");
var threads = GmailApp.search("subject:" + gmailLabels,0,20);
if (threads.length > 0) {
/* Google Drive folder where the Files would be saved */
var folders = DriveApp.getFoldersByName(driveFolder);
var folder = folders.hasNext() ?
folders.next() : DriveApp.createFolder(driveFolder);
/* Gmail Label that contains the queue */
var label = GmailApp.getUserLabelByName(gmailLabels) ?
GmailApp.getUserLabelByName(gmailLabels) : GmailApp.createLabel(driveFolder);
for (var t=0; t<threads.length; t++) {
threads[t].removeLabel(label);
var msgs = threads[t].getMessages();
var html = "";
var subject = threads[t].getFirstMessageSubject();
var previousdoc = driveFolder.getFilesByName(subject + ".pdf"); //gets name of csv, if exists in drive then move to trash before creating new file
if (previousdoc.hasNext()) {
previousdoc.next().setTrashed(true);}
/* Append all the threads in a message in an HTML document */
for (var m=0; m<msgs.length; m++) {
var msg = msgs[m];
html += "From: " + msg.getFrom() + "<br />";
html += "To: " + msg.getTo() + "<br />";
html += "Date: " + msg.getDate() + "<br />";
html += "Subject: " + msg.getSubject() + "<br />";
html += "<hr />";
html += msg.getBody().replace(/<img[^>]*>/g,"");
html += "<hr />";}
/* Convert the Email Thread into a PDF File */
var tempFile = DriveApp.createFile("temp.html", html, "text/html");
folder.createFile(tempFile.getAs("application/pdf")).setName(subject + ".pdf");
tempFile.setTrashed(true);}}}
Explanation:
There is a function getLastMessageDate() that gives the date of a thread's most recent message. You can compare that against the date of today and if they match execute the rest of the code.
Since you use a for loop: for (var t=0; t<threads.length; t++)
I think the condition if (threads.length > 0) is redundant because for loop won't run anyway if threads.length equals 0.
Because of the latter, I transferred the folder creation part of your code into the loop itself and execute it only when the last day of the thread is equal to today. But I leave this part for you to decide.
I can't test your code but this should work:
function saveGmailAsPDF2() {
var gmailLabels = 'xxxxx';
var driveFolder = DriveApp.getFolderById("folder url");
var threads = GmailApp.search("subject:" + gmailLabels,0,20);
// new code
const today = new Date();
const ss = SpreadsheetApp.getActive();
const timezone = ss.getSpreadsheetTimeZone();
const today_dt = Utilities.formatDate(today, timezone, 'yyyy-MM-dd');
///////////
for (var t=0; t<threads.length; t++) {
// new code
var lastMessageDate = threads[t].getLastMessageDate();
var thread_dt = Utilities.formatDate(lastMessageDate, timezone, 'yyyy-MM-dd');
if(today_dt==thread_dt){
///////////
/* Google Drive folder where the Files would be saved */
var folders = DriveApp.getFoldersByName(driveFolder);
var folder = folders.hasNext() ?
folders.next() : DriveApp.createFolder(driveFolder);
/* Gmail Label that contains the queue */
var label = GmailApp.getUserLabelByName(gmailLabels) ?
GmailApp.getUserLabelByName(gmailLabels) : GmailApp.createLabel(driveFolder);
threads[t].removeLabel(label);
var msgs = threads[t].getMessages();
var html = "";
var subject = threads[t].getFirstMessageSubject();
var previousdoc = driveFolder.getFilesByName(subject + ".pdf"); //gets name of csv, if exists in drive then move to trash before creating new file
if (previousdoc.hasNext()) {
previousdoc.next().setTrashed(true);}
/* Append all the threads in a message in an HTML document */
for (var m=0; m<msgs.length; m++) {
var msg = msgs[m];
html += "From: " + msg.getFrom() + "<br />";
html += "To: " + msg.getTo() + "<br />";
html += "Date: " + msg.getDate() + "<br />";
html += "Subject: " + msg.getSubject() + "<br />";
html += "<hr />";
html += msg.getBody().replace(/<img[^>]*>/g,"");
html += "<hr />";}
/* Convert the Email Thread into a PDF File */
var tempFile = DriveApp.createFile("temp.html", html, "text/html");
folder.createFile(tempFile.getAs("application/pdf")).setName(subject + ".pdf");
tempFile.setTrashed(true);}}}
Related
I am trying to get all the values in column L which is indexed as column 11(var check). However I am only getting the value of the first cell in the column and it stops looping through. I have created a comment for a reference.
Could someone please help me?
Please ignore:
It looks like your post is mostly code; please add some more details.
It looks like your post is mostly code; please add some more details.
It looks like your post is mostly code; please add some more details.
function myFunction(e) {
var sheet = SpreadsheetApp.openById("1naSWINA8_uxeLUsj0lFntqILyDj2nirb56uvkBel79Y").getSheetByName("CRM Feedback");
var ss = SpreadsheetApp.getActive().getSheetByName("Form Responses 1");
var data = sheet.getRange(4, 1, ss.getLastRow(), ss.getLastColumn()).getValues();
var manager_email = "XXXXX";
for( var i = 0; i< data.length;i++ ) {
var timestamp = data[i][0];
var requesterEmail = data[i][1];
var starRating = data[i][2];
var requestCatergory = data[i][3];
var description = data[i][4];
var label = data[i][5];
var ticketId = data[i][6];
var comment = data[i][7];
var status = data[i][8];
var priority = data[i][9];
var office = data[i][10];
//I am trying to log all the values in column 11
var check = data[i][11];
Logger.log(check)
var checkTimestamp = data[i][0]
if(check == false){
continue;
} else {
var subject = "CT IT feedback - ";
var body = "<body>";
body += "<br><b>Requester email:</b> " + requesterEmail
body += "<br><b>Star Rating:</b> " + starRating
body += "<br><b>Request Category</b> " + requestCatergory
body += "<br><b>Description:</b> " + description
body += "<br><b>label: </b> " + label
body += "<br><b>Ticket ID: </b>" + ticketId
body += "<br><b>Comment: </b>" + comment
body += "<br><b>status: </b>" + status
body += "<br><b>priority:</b> " + priority
body += "<br><b>office: </b>" + office
body += "</body>";
MailApp.sendEmail(manager_email, subject, body, {htmlBody:body})
var sent_string = "sent";
ss.getRange(i + 1, 12).setValue(sent_string)
if (sent_string){
return
}
}
}
}
You want to loop through all data rows and send emails for each row where the status is not set to "sent" yet
You want to set the status of a row to "sent" after sending an email
The problem is that
you have a return statement which makes you exit the for loop and stop iterating
You seem not to change the status for the right sheet and the right row
I suggest you to modify your code as following:
function myFunction(e) {
var sheet = SpreadsheetApp.openById("1naSWINA8_uxeLUsj0lFntqILyDj2nirb56uvkBel79Y").getSheetByName("CRM Feedback");
var ss = SpreadsheetApp.getActive().getSheetByName("Form Responses 1");
var data = sheet.getRange(4, 1, ss.getLastRow(), ss.getLastColumn()).getValues();
var manager_email = "XXX";
for( var i = 0; i< data.length;i++ ) {
var timestamp = data[i][0];
var requesterEmail = data[i][1];
var starRating = data[i][2];
var requestCatergory = data[i][3];
var description = data[i][4];
var label = data[i][5];
var ticketId = data[i][6];
var comment = data[i][7];
var status = data[i][8];
var priority = data[i][9];
var office = data[i][10];
//I am trying to log all the values in column 11
var check = data[i][11];
Logger.log(check)
var checkTimestamp = data[i][0]
if(check != "sent"){
var subject = "CT IT feedback - ";
var body = "<body>";
body += "<br><b>Requester email:</b> " + requesterEmail
body += "<br><b>Star Rating:</b> " + starRating
body += "<br><b>Request Category</b> " + requestCatergory
body += "<br><b>Description:</b> " + description
body += "<br><b>label: </b> " + label
body += "<br><b>Ticket ID: </b>" + ticketId
body += "<br><b>Comment: </b>" + comment
body += "<br><b>status: </b>" + status
body += "<br><b>priority:</b> " + priority
body += "<br><b>office: </b>" + office
body += "</body>";
MailApp.sendEmail(manager_email, subject, body, {htmlBody:body})
var sent_string = "sent";
//are you sure you want to set the stutus in ss and not in sheet to 'sent'?
//Keep in mind that you start with row 4
sheet.getRange(i +4, 12).setValue(sent_string)
}
}
}
The script just works as I want, I didn't develop it, I forgot the author's site, sorry if I don´t mention he/she.
The big problem is that I´m unable or I can't figure out how can I send an email with the PDF created through the script, I don't want to sent it in Zip format and if you release, the PDF file name´s change every time you use the spreadsheet, here I leave the code:
function spreadsheetToPDF(){
var key = '1hBbCnmca_wx4wbQx93Vf4d9cfUwGbFSP9hKgv9Qu7Vk'; //docid
var index = 0; //sheet gid / number
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ActiveSheet = ss.getSheetByName('Sheet 1');
var timestamp = Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd'-'HHmm");
var plainonum = ActiveSheet.getRange("C5").getValue(); //order number
var supp_name = ActiveSheet.getRange("C12").getValue(); //supplier
var onum = ('0000' + plainonum ).slice(-4); //sets leading zeros to order number
var description = ActiveSheet.getRange("C18").getValue(); //description
var email = ActiveSheet.getRange("D1").getValue(); //email
var name = 'Order-' + onum +'-' + supp_name + '-' + description + '-' + timestamp + '.pdf'; //makes pdf filename
SpreadsheetApp.flush(); //ensures everything on spreadsheet is "done"
//make the pdf from the sheet
var theurl = 'https://docs.google.com/spreadsheets/d/'
+ key
+ '/export?exportFormat=pdf&format=pdf'
+ '¬es=false'
+ '&size=letter'
+ '&portrait=true'
+ '&fitw=true' // fit to width, false for actual size
+ '&sheetnames=false&printtitle=false&pagenumbers=false'
+ '&gridlines=false'
+ '&fzr=false' // do not repeat frozen rows on each page
+ '&gid='
+ index; //the sheet's Id
var token = ScriptApp.getOAuthToken();
var docurl = UrlFetchApp.fetch(theurl, { headers: { 'Authorization': 'Bearer ' + token } });
var pdf = docurl.getBlob().setName(name).getAs('application/pdf');
//save the file to folder on Drive
var fid = '0B6iePPHdQRoxQVB3eERrb1c3MUE';
var folder = DriveApp.getFolderById(fid);
folder.createFile(pdf);
var pfd = DriveApp.getFileById(pdf.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:name,content:pfd, mimeType:'application/pdf'};
// Here I need to send the email
// GmailApp.sendEmail(email, "The subject", "The body content") // AND The PDF File witch I can´t attach
//Show a Popup with a message that a file was created inside a folder
SpreadsheetApp.getUi().alert('New document created in' + ' ' + folder);
}
After getting the file from drive using the DriveApp.getFolderById(id), you may then send it as an attachment using MailApp.sendEmail(recipient, subject, body, options).
Here's the sample code that you can try:
// Send an email with two attachments: a file from Google Drive (as a PDF) and an HTML file.
var file = DriveApp.getFileById('1234567890abcdefghijklmnopqrstuvwxyz');
var blob = Utilities.newBlob('Insert any HTML content here', 'text/html', 'my_document.html');
MailApp.sendEmail('mike#example.com', 'Attachment example', 'Two files are attached.', {
name: 'Automatic Emailer Script',
attachments: [file.getAs(MimeType.PDF), blob]
});
Solution given in this SO post might also help.
As I suspected, I was emailing only the name of the file but without the content, so I made a little variation to the var under the folder creation:
var archivo = docurl.getBlob().getAs('application/pdf').getBytes();
// Create a PDF from the active sheet, save it under a specific directory and send the PDF by mail
function spreadsheetToPDF(){
var key = 'abcdefghijk1234567890'; //docid (actual spreadsheet)
var index = 0; //sheet gid / number
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ActiveSheet = ss.getSheetByName('Hoja 1');
var timestamp = Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd'-'HHmm");
var plainonum = ActiveSheet.getRange("C5").getValue(); //order number
var supp_name = ActiveSheet.getRange("C12").getValue(); //supplier
var onum = ('0000' + plainonum ).slice(-4); //sets leading zeros to order number
var description = ActiveSheet.getRange("C18").getValue(); //description
var correo = ActiveSheet.getRange("D1").getValue(); //correo electrónico
var name = 'Order-' + onum +'-' + supp_name + '-' + description + '-' + timestamp + '.pdf'; //makes pdf filename
SpreadsheetApp.flush(); //ensures everything on spreadsheet is "done"
//make the pdf from the sheet
var theurl = 'https://docs.google.com/spreadsheets/d/'
+ key
+ '/export?exportFormat=pdf&format=pdf'
+ '&size=A4'
+ '&portrait=true'
+ '&fitw=true' // fit to width, false for actual size
+ '&sheetnames=false&printtitle=false&pagenumbers=false'
+ '&gridlines=false'
+ '&fzr=false' // do not repeat frozen rows on each page
+ '&gid='
+ index; //the sheet's Id
var token = ScriptApp.getOAuthToken();
var docurl = UrlFetchApp.fetch(theurl, { headers: { 'Authorization': 'Bearer ' + token } });
var pdf = docurl.getBlob().setName(name).getAs('application/pdf');
//save the file to folder on Drive
var fid = 'abcdefghij1234567890';
var folder = DriveApp.getFolderById(fid);
folder.createFile(pdf);
//get the file, name and content to send it by email
var archivo = docurl.getBlob().getAs('application/pdf').getBytes();
var attach = {fileName:name,content:archivo, mimeType:'application/pdf'};
// Send email with the PDF attached
GmailApp.sendEmail(correo, "The subject", "The body content", {attachments:[attach]});
//Show a Popup with a message that a file was created inside a folder
SpreadsheetApp.getUi().alert('Nuevo Documento creado en el folder' + ' ' + folder);
}
I got a simple JavaScript based blog . First have a look at the below codes and I will ask my question.
Index.html have the following codes in its body
<script language="javascript" type="text/javascript" src="blog/config.js"> </script>
<script language="javascript" type="text/javascript" src="blog/single.js"> </script>
<script language="javascript" type="text/javascript" src="blog/posts.js"> </script>
config.js has
//This is the configuration file of the blog system.
//change these variables to suit your style and needs
var head = "h2"; //the heading style, ex. h1, h2, ect. use "h2" rather than "<h2>"
var text = "text"; //the text style, from your style sheet, it's in a <div> tag
var divider = "<hr>"; //the division between posts
var newer = "newer"; //the class for the link to the next newest page
var older = "older"; //the class for the link to the next oldest page
var pageclass = "page"; //the class for the text that displays the page number
var dateclass = "date"; //the class for the date
var pagesize = 4; //the number of posts on each page
var navclass = nav; //the configuration for the navigation`
posts.js
var posts = 1; //add 1 to this after adding a post. should be equal to the id of the newest post.
initblog(posts);
var id = 1; //make sure that this number is one greater than the one below it
var date = "mm/dd/yyyy"; //The date of the post
var heading = "Post 1"; //The title
var entry = ""; //reset the string
//don't worry about formatting and stuff like that, the system takes care of it all for us.
//VV your entry VV
entry += "<p>Wow, this post is on another page, If you have this many real posts, congratulations!</p>";
//^^ The most important part ^^
add_entry(id,date,heading,entry); //adds the entry to the blog
single.js
var maxpost;
function initblog(posts){
maxpost = posts;
var address = window.location.search;
if (address.substring(0, 1) == '?') {
page = address.substring(1);
} else{
window.location = "post.html?" + posts;
}
page = parseInt(page);
if (page > maxpost){
page = maxpost;
}
if (page < 1){
page = 1;
}
}
function add_entry(id,date,heading,entry) {
for (i=page;i>page - 1;i--){
if (id == i){
var entrytext = "";
entrytext += "<div class=" + text + ">";
entrytext += "<" + head + ">";
entrytext += "<a name=" + id + "></a>";
entrytext += "<span class='date'>[" + date + "]</span> ";
entrytext += heading;
entrytext += "</" + head + ">";
entrytext += entry;
entrytext += "</div>" + divider;
document.write(entrytext);
}
}
}
function pages(){
entrytext = ""
entrytext += "<table class=\"nav\"><tr>";
entrytext += "<td width=25% class = " + newer + "> ";
if (page < maxpost){
entrytext += "<A HREF=javascript:prev()>Newer Posts </A>";
}
entrytext += "</td><td width=50% class = " + pageclass + "><br><A HREF=javascript:newest()> Back to Index</A></td>";
entrytext += "<td width=25% class = " + older + "> ";
if (page-1 > 0){
entrytext += "<A HREF=javascript:next()>Older Posts</A>";
}
entrytext += "</td></table>";
entrytext += "";
document.write(entrytext);
}
function next(){
page = page - 1;
if (page < 1) {
page = page + 1;
}
window.location = "post.html?" + page;
}
function prev(){
page = page + 1;
if (page > maxpost) {
page = maxpost;
}
window.location = "post.html?" + page;
}
function newest(){
window.location = "index.html?" + maxpost;
}
Well , this is the whole blog script . I ain't added styles and you may see the comments on each lines for simplicity.
This blog doesn't have options to add title and meta description , keyword etc. Due to the style of applying it can do nothing outside the body tag.
1 . How to add an option to take/load titles?
2 . How to add the feature to load meta tag?
Don't tell me to edit and add titles on the template (index.HTML) , because that make no sense
As you see the heading block is for the title of the blog. All you need is just making it more visible.
var entrytext = "";
entrytext += "<div class=" + text + ">";
entrytext += "<h1>" + heading + "</h1>";
entrytext += "<" + head + ">";
entrytext += "<a name=" + id + "></a>";
entrytext += "<span class='date'>[" + date + "]</span> ";
entrytext += "</" + head + ">";
entrytext += entry;
entrytext += "</div>" + divider;
document.write(entrytext);
document.title = heading;
This will solve your problem about titles.
Regarding to meta tags, usually (actually by standard) meta tags are written betweeen <head> tags in HTML. To make it SEO compilant you need add them into these tags. More detailed: http://www.w3schools.com/tags/tag_meta.asp
But, if this code is generated on client-side. There is no meaning to generate it, because search engine will not parse on-fly generated meta tags. Because it's executed on browser.
I am trying to rebuild an old application without the loss of data. The current data has all been stored in xml files that i am trying to read using Javascript.
This is the Javascript (i'm new to this, feedback is appreciated):
// Create a connection to the file.
var Connect = new XMLHttpRequest();
// Define which file to open and
// send the request.
Connect.open("GET", "writers.xml", false);
Connect.setRequestHeader("Content-Type", "text/xml");
Connect.send(null);
// Place the response in an XML document.
var TheDocument = Connect.responseXML;
// Place the root node in an element.
var Customers = TheDocument.childNodes[0];
// Retrieve each customer in turn.
for (var i = 0; i < Customers.children.length; i++){
var Customer = Customers.children[i];
//Create div's for data
document.getElementById("body").innerHTML += "<div id='who" + i + "'></div>"
document.getElementById("body").innerHTML += "<div id='age" + i + "'></div>"
document.getElementById("body").innerHTML += "<div id='hobby" + i + "'></div>"
document.getElementById("body").innerHTML += "<div id='image" + i + "'></div>"
document.getElementById("body").innerHTML += "<div id='something" + i + "'></div>"
//Assign data to correct divs
var who = Customer.getElementsByTagName("name");
var who2 = who[0].textContent.toString();
document.getElementById("who"+i).innerHTML += who2;
var age = Customer.getElementsByTagName("age");
var age2 = age[0].textContent.toString();
document.getElementById("age"+i).innerHTML += age2;
var hobby = Customer.getElementsByTagName("hobby");
var hobby2 = hobby[0].textContent.toString();
document.getElementById("hobby"+i).innerHTML += hobby2;
var image = Customer.getElementsByTagName("image");
var image2 = image[0].textContent.toString();
document.getElementById("image"+i).innerHTML += image2;
var something = Customer.getElementsByTagName("something");
var something2 = something[0].textContent.toString();
document.getElementById("something"+i).innerHTML += something2;
}
This is an example of my xml file:
<doc>
<person>
<name>Paul</name>
<age>21</age>
<hobby>blabla</hobby>
<image>thisisanimage.jpg</image>
<something>Random string</something>
</person>
<person>
<name>Peter</name>
<age></age>
<hobby>blabla</hobby>
<image>thisisanimage.jpg</image>
<something>Random string</something>
</person>
</doc>
Now i am trying to filter Peter out, because the age field is empty. Anyone got an idea?
The easiest way is to add a condition in the loop, to test if the age is blank. If the age value is blank then the if block will not be entered, and the next iteration of the loop will start.
for (var i = 0; i < Customers.children.length; i++) {
var Customer = Customers.children[i];
var age = Customer.getElementsByTagName("age");
var age2 = age[0].textContent.toString();
if (age2 != '') { // only do the below code if age2 is not blank
//Create div's for data
document.getElementById("body").innerHTML += "<div id='who" + i + "'></div>"
document.getElementById("body").innerHTML += "<div id='age" + i + "'></div>"
document.getElementById("body").innerHTML += "<div id='hobby" + i + "'></div>"
document.getElementById("body").innerHTML += "<div id='image" + i + "'></div>"
document.getElementById("body").innerHTML += "<div id='something" + i + "'></div>"
document.getElementById("age" + i).innerHTML += age2;
//Assign data to correct divs
var who = Customer.getElementsByTagName("name");
var who2 = who[0].textContent.toString();
document.getElementById("who" + i).innerHTML += who2;
var hobby = Customer.getElementsByTagName("hobby");
var hobby2 = hobby[0].textContent.toString();
document.getElementById("hobby" + i).innerHTML += hobby2;
var image = Customer.getElementsByTagName("image");
var image2 = image[0].textContent.toString();
document.getElementById("image" + i).innerHTML += image2;
var something = Customer.getElementsByTagName("something");
var something2 = something[0].textContent.toString();
document.getElementById("something" + i).innerHTML += something2;
}
}
I have this little problem.
I have this javascript in my html page:
function myfunction(form)
{
var name = document.details.txtName.value + "\n";
var street = document.details.txtStreet.value + "\n";
var city = document.details.txtCity.value + "\n";
var stateProvince = document.details.txtStateProvince.value + "\n";
var postalCode = document.details.txtPostalCode.value + "\n";
var country = document.details.txtCountry.value + "\n";
var homeTel = document.details.txtHomeTel.value + "\n";
var workTel = document.details.txtWorkTel.value + "\n";
var fax = document.details.txtFax.value + "\n";
var mobile = document.details.txtMobile.value + "\n";
var email = document.details.txtEmail.value + "\n";
var enquiry = document.details.txtEnquiry.value + "\n";
var message = (name +
street +
city +
stateProvince +
postalCode +
country +
homeTel +
workTel +
fax +
mobile +
email +
enquiry);
alert(message);
location='mailto:somecrazyassemail#gmail.com?subject=Message From Redec Website&body=' + message;
return false; //So that the page can stay at its current location.
In the messagebox that pops up, it displays the strings underneath each other, which I want.
but when this opens outlook it is all in one long string. how can I fix this?
}
The mailto is particular attribute. You have to encode the string using escape function.
But for the new lines, you can use %0D%0A.
See this site for more informations.
You're inserting the text as HTML, so new line characters '\n' are simply parsed as 'n'. To insert a line break, using the corresponding HTML element <br>.
For example:
var name = document.details.txtName.value + "<br>";
// ^^^^