I am trying to read Gmail attachments and push it to Google Drive. It works great except for one minor issue/behavior.
Whenever I call the getAttachments() method, it includes the inline signature image which is irrelevant in the drive folder. Is there any way to exclude the signature image (or inline images altogether) so that I will be able to push only the attached files?
Below is my code if you want to review.
var threads = myLabel.getThreads(0,500);
for (var threadIdx=0; threadIdx<threads.length; threadIdx++) {
var thread = threads[threadIdx];
var messages = thread.getMessages();
for (var msgIdx=0; msgIdx<messages.length; msgIdx++) {
var message = messages[msgIdx];
var attachments = message.getAttachments();
Logger.log(attachments.length);
}
}
So I always get the attachments.length to be one more than the actual number of attachments, when there is a signature image.
Can someone help?
Sorry for late reply but I was facing the same issue and found a workaround,
Your message.getBody() method will contain whole message body. This will also contain signature image name. So what we can do we can check signature name from attachment and if my body text contains this signature name then I should emit that attachment. Here's the code snippet,
var textMessage = message.getBody();
if (attachments.length > 0) {
for (var z=0; z<attachments.length; z++) {
var attachment = attachments[z];
if(textMessage.indexOf(attachment.getName()) === -1)
{
folder.createFile(attachment);
}
}
}
I've checked for Inline attachments as well, this code considers those as an attachment only.
Use
var attachments = message.getAttachments({
includeInlineImages : false
});
instead of
var attachments = message.getAttachments();
It will exclude inline images. Signature in the email message is also an inline image which is being extracted as attachment in your case.
Related
I am trying to extract all the images store in Inline body of email, store it in drive folder.
I am tryin to use this code
function GETGMEmails(){
var label = GmailApp.getUserLabelByName ('WHOLESALE REP');
var threads = label.getThreads();
for(var i = threads.length - 1; i >= 0; i--){
var messages = threads[i].getMessages();
for (var j = 0; j < messages.length; j++){
var message = messages[j];
// extractDetails(message,folder)
fetchInlineImage(message)
}
}
}
function fetchInlineImage(message) {
var msg = message;
console.log(message)
var pattern = /<img.*src="([^"]*)"[^>]*>/;
var matches = pattern.exec(msg.getBody());
console.log(matches.length)
if(matches) {
var url = matches[1];
var urlPattern = /^https*\:\/\/.*$/;
// If this matches, that means this was copied and pasted from a browser and it's a
// standard URL that we can urlFetch
if(urlPattern.exec(url)) {
// NO OP!
} else {
// Else this means the user copied and pasted from an OS clipboard and the image
// exists on Google's servers. The image can only be retrieved when logged in. Fortunately,
// if we use URLFetchApp, this will act as a logged in user and be able to URLFetch the image.
// We'll need to prepend a Gmail URL (subject to change)
url = "https://mail.google.com/mail/u/0/" + url;
}
// TODO - there is one more case that we're not covering - embedded images that newsletters use
Logger.log("Fetching image from URL: " + url);
var response = UrlFetchApp.fetch(url);
Logger.log("Response status: " + Utilities.jsonStringify(response.getHeaders()));
var blob = response.getBlob();
Logger.log("Response blob: " + blob.getBytes().length);
Drivefolder.createFile(blob).setName('ss.jpeg')
}
};
Email look like this, with lot of images here and there, and I want to extract each one of them:-
enter image description here
You are trying to access inline images from a GMail message.
When GMail was first introduced there was no ability to access inline images.
In 2012 an Issue:Access to inline images was raised and the script shown in the question was proposed as a workaround. A question was also asked on StackOverflow Parsing inlineImages from Gmail raw content.
These (and some variants) worked for a few years until 2014 when a second Issue:GmailApp.getAttachments Issue was raised.
Workarounds were patchy until 2017 when it was announced that the Issue had been resolved.
In 2018, a new answer was added to the StackOverFlow question. and in 2022 a new StackOverflow question How can I extract inline images from a Gmail email? (all available workarounds do not work anymore) was asked and answered.
In short, the script that you are using is redundant. However, the process to access inline images is simple and straightforward. The key is to examine the body by Regex.
The following script provides a basis for you to identify and log inline images.
Put headers in row 1 of sheet="Images".
A1="ID", B1="Subject", C1="Image"
function so75327302() {
var label = GmailApp.getUserLabelByName ('WHOLESALE REP');
var threads = label.getThreads();
for (var i=0;i<threads.length;i++){
var messages = threads[i].getMessages()
for (m=0;m<messages.length;m++){
// Logger.log("DEBUG: i:"+i+",m:"+m+", subject:"+messages[m].getSubject()+", message ID:"+messages[m].getId())
var body = messages[m].getBody()
var regex1 = RegExp('<img src="([^"]*)"[^>]*>', 'g')
var array1 = new Array
var images = new Array
while ((array1 = regex1.exec(body)) !== null) {
Logger.log("message ID:"+messages[m].getId()+", Subject: "+messages[m].getSubject()+" contains inline images."+ `Found ${array1[0]}`);
images.push([array1[0]])
}
if (images.length > 0){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheetName = "Images"
var sheet = ss.getSheetByName(sheetName)
var imageLR = sheet.getLastRow()
sheet.getRange(imageLR+1,1).setValue(messages[m].getId())
sheet.getRange(imageLR+1,2).setValue(messages[m].getSubject())
sheet.getRange(imageLR+1,3,images.length).setValues(images)
}
}
}
}
I am trying to create a Google Form linked to a Google Sheet utilizing some Google App script that will take some answers from a survey, attach an uploaded file, and send an email to a specific person. I have been able to figure out the part where I collect the data in a Google Sheet and send an email, but the part where I take the uploaded file and have it as an attachment in the email is stumping me.
Currently, my code to send the email looks like this:
GmailApp.sendEmail(Recipient,subject,'',{htmlBody: htmlText},);
But looking at the documentation on sendEmail, it looks like I want to add more to that Options part, right? The so if I am defining a variable for this, I need to use getFileById, but the file ID will be different with each upload. Furthermore, I might need to attach multiple files.
I have created a test Google Form here and I have attached it to a Google Sheet here. You can see the Google App Script here. You can check the email being sent/received successfully by looking at formtesting4#mailinator.com as specified in the code.
Is that possible with what I am trying to do?
You can refer to this sample script:
function emailMe() {
const ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const info = ss.getDataRange().getValues();
info.forEach((entry,a) => {
// Identify whether notification has been sent
if (entry[4] === '') {
// Collect entries
var Recipient = "your#email.com"
var subject = 'Roster Scheduler Update';
Timestamp = entry[0];
Name = entry[1];
Roster = entry[2];
attachment = "TEST";
var attachmentBlobs = [];
//Get the blob of all attachments available
if(entry[3]){
var attachments = entry[3].split(', ');
attachments.forEach(url => {
var fileId = url.replace('https://drive.google.com/open?id=','');
Logger.log(fileId);
var file = DriveApp.getFileById(fileId);
attachmentBlobs.push(file.getBlob());
});
}
let body = '';
// Generate email
var html = HtmlService.createTemplateFromFile("email.html");
var htmlText = html.evaluate().getContent();
// Send email
GmailApp.sendEmail(Recipient, subject, body, {htmlBody: htmlText, attachments: attachmentBlobs});
// Email confidence
const check = 'Sent';
ss.getRange(a + 1,5).setValue(check);
}
});
}
Changes done:
Get the blob file of all the uploaded attachments using File.getBlob(). You can get the file id from the attachment's url link and use DriveApp.getFileById(id)
Include body in the GmailApp.sendEmail() to fix email content issue
Include attachments as an option in the GmailApp.sendEmail(recipient, subject, body, options)
Output:
Sample1: 3 attachments
Sample2: 1 attachment
I am trying to write a small Google Script to extract the details of my emails especially the attachments. In this example I am trying to get the 'user' and 'attachment' details in the Log window.
After running the code, I can see the 'attachment details' as :-
1) GmailAttachment - wherever attachment is present
2) Undefined - wherever attachment isn't present
I would like to check that how can I get more details of Attachment like Name of Attachment, Url of Attachment, type etc. is that possible through Google Scripting?
function testing1() {
Logger.log(Session.getActiveUser().getEmail());
var mail1 = GmailApp.getInboxThreads();
for(var x=0;x<mail1.length;x++){
var msg = mail1[x].getMessages();
for(var i=0;i<msg.length;i++){
var mesg = msg[i].getBody();
var att = msg[i].getAttachments()[0];
Logger.log(att);
}
}
}
Thanks in advance for your guidance.
Regards,
Alok
You can loop through attachments (if available) and get the file name and size from the GmailAttachment class.
for(var i=0;i<msg.length;i++){
var mesg = msg[i].getBody();
var att = msg[i].getAttachments();
for (var a=0; a<att.length; a++) {
Logger.log(att[1].getName());
Logger.log(att[1].getSize());
}
}
I receive an email with a hyperlink that when clicked starts a download of a csv file to my Gmail account. It's not an actual attachment. When I receive this email (which has a unique subject line), I need a way to automatically add the contents of the downloaded .csv
Trigger:
An email with a specific subject line is received to my gmail account
Action 1:
Download a .csv file from a hyperlink within the body of the email
Action 2:
Add the contents of the .csv file to a Google Sheet file
I need an already built service that does this or suggestions on how to approach it.
If I can get this Google script to run, I should be able to find a working solution. The problem is the script keeps giving me errors.
function downloadFile(fileURL,folder) {
var fileName = "";
var fileSize = 0;
var response = UrlFetchApp.fetch(fileURL, {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob()
var folder = DocsList.getFolder(folder);
if (folder != null) {
var file = folder.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
}
var fileInfo = { "rc":rc, "fileName":fileName, "fileSize":fileSize };
return fileInfo;
}
This is something I recently tackled at work, fully automating data pulls from my emails to a database. I am not going to write a solution for you, but I will provide you with the information and links you need to do it yourself.
Note: Your question is very broad, and covers a large range of different problems, each of which should be tackled one at a time with their own question (Many of which already have multiple answers on StackOverflow). This is a process to follow with linked documentation, and a couple code snippets so you can do it yourself and tackle each problem along the way.
The Proposed Process:
Open the email with the GmailApp Service
Extract the link via the script below
Get the CSV from the link via the code linked below. This utilizes UrlFetchAp, the Blob datatype, and the parseCsv utility (which you have to escape commas first, because it's buggy)
Modify the contents of the resulting array to your liking
Use the SpreadsheetApp Service to open a spreadsheet and get a range
Set the values of that range to your array of data.
Extract href link from email (assumes only 1 link):
//Retrieves a URL from a HTML string from an href. Only applicable if there is only one link in the string
function GetHrefURLsFromString(string){
var href = string.match(/href="([^"]*)/)[1];
if(href){
return href;
} else {
throw "No URL Found"
}
}
Extract CSV from link:
//Gets a CSV from a provided link, and parses it.
function GetCSVFromLink(link){
var urlData = UrlFetchApp.fetch(link);
if(urlData.getBlob().getContentType() == 'csv'){
var stringData = urlData.getContentText();
var escapedStringData = stringData.replace(/(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]\r\n(?:\\[\s\S][^'\\]\r\n)*')/g, '\r\n');
var CSV = Utilities.parseCsv(escapedStringData);
return CSV;
}
Logger.log('DataType Not CSV')
return null;
}
I am currently using the following to send an email to a distribution list containing the headers/questions and corresponding answers when a Google Form is submitted:
function sendFormByEmail(e) {
// Subject field of email
var emailSubject = "New Student Case Filed";
// Comma-separated list of email addresses for distribution.
var yourEmail = "my email address";
// Spreadsheet key, found in the URL when viewing your spreadsheet.
var docKey = "my spreadsheet key";
// If you want the script to auto send to all of the spreadsheet's editors, set this value as 1.
// Otherwise set to 0 and it will send to the yourEmail values.
var useEditors = 0;
// Have you added columns that are not being used in your form? If so, set this value to
// the NUMBER of the last column that is used in your form.
// for example, Column C is the number 3
var extraColumns = 40;
if (useEditors) {
var editors = DocsList.getFileById(docKey).getEditors();
if (editors) {
var notify = editors.join(',');
} else var notify = yourEmail;
} else {
var notify = yourEmail;
}
// The variable e holds all the submission values in an array.
// Loop through the array and append values to the body.
// Need to omit headers with no response*
var s = SpreadsheetApp.getActive().getSheetByName("StudentCases");
if (extraColumns){
var headers = s.getRange(1,1,1,extraColumns).getValues()[0];
} else var headers = s.getRange(1,1,1,40).getValues()[0];
var message = "";
for(var i in headers) {
message += headers[i] + ' : '+ e.values[i].toString() + '\n\n';
}
Now I also want a Google Doc created containing the headers and responses. So far, I've been able to create the Doc, add the title, and add a paragraph, but now I need to replicate the array of headers/responses in the Google Doc as well.
// Create a new Google Doc named 'Case File' * need to figure out how to pull last name response from form.
var doc = DocumentApp.create('Case File: Last Name*');
// Access the body of the Doc, add a paragraph, *need to append array of headers/answers
var body = doc.getBody().body.appendParagraph();
// Get the URL of the Google Doc to include in Email
var url = doc.getUrl();
// Get ID of Doc to attach to email
var id = doc.getId()
One other issue I'd like to solve; I only need the headers/questions that contain a response, as many of them will not necessarily warrant an answer. So in other words, IF there is no answer, THEN do not append to email.
It seems you provided a list of general requirements without much in the way of what you tried with the results you got. StackOverflow will be helpful to you if you provide more pointed questions about what exactly you have tried..
Can you share the exact code you have tried please? What were your results?
From a high level, I would proceed with this general workflow.
Draft a gDoc template using placeholders in a variables nomenclature of your choice ~FName ~LName etc..
Use an onFormSubmit trigger to make a copy of the gDoc template when a new form is submitted.
Replace the ~FName ~LName placeholders in the copied gDoc with content captured in the form
Save the copied gDoc as a PDF
email the PDF to the email address provided in the form submission