Reputation: 109
I’m trying to attach a file to an email I send in Google Apps Script with MailApp.sendEmail(). In the browser JavaScript I read in the file manually with this code because I’ve already processed the equivalent of the submit button in my HTML form, and it works:
var file = document.getElementById('myfile');
var fileInfo = [];
if(file.files.length) // if there is at least 1 file
{
if (file.files[0].size < maxEmailAttachmentSize) // and its size is < 25M
{
var reader = new FileReader();
reader.onload = function(e)
{
fileInfo[0] = e.target.result;
};
reader.readAsBinaryString(file.files[0]);
fileInfo[1] = file.files[0].name;
fileInfo[2] = file.files[0].type;
fileInfo[3] = file.files[0].size;
}
console.log(fileInfo); // here I see the full file and info. All looks correct.
}
Then I send it up to the server.
google.script.run.withSuccessHandler(emailSent).sendAnEmail(fileInfo);
On the server I pull out the fields and send the email like so:
var fname = fileInfo[1];
var mimeType = fileInfo[2];
var fblob = Utilities.newBlob(fileInfo[0], mimeType, fname);
// all looks right in the Logger at this point
try {
GmailApp.sendEmail(emaiRecipient, emailSubject, emailBody,
{
name: 'Email Sender', // email sender
attachments: [fblob]
}
);
catch …
This works fine when the file is a text file or HTML file but doesn’t when the file is anything else. The file is sent but it's empty and apparently corrupt. Can anyone see what’s wrong with this code? (It doesn’t work with MailApp.sendEmail() either.) I did see in another stackoverflow post that the document has to be saved once, but that is something I definitely don’t want to do. Isn’t there any other way? What am I missing?
Upvotes: 1
Views: 336
Reputation: 201613
readAsArrayBuffer
instead of readAsBinaryString
.When above points are reflected to your script, it becomes as follows.
// Added
function getFile(file) {
return new Promise((resolve, reject) => {
var reader = new FileReader();
reader.onload = (e) => resolve([...new Int8Array(e.target.result)]);
reader.onerror = (err) => reject(err);
reader.readAsArrayBuffer(file);
});
}
async function main() { // <--- Modified
var file = document.getElementById('myfile');
var fileInfo = [];
if(file.files.length) {
if (file.files[0].size < maxEmailAttachmentSize) {
fileInfo[0] = await getFile(file.files[0]); // <--- Modified
fileInfo[1] = file.files[0].name;
fileInfo[2] = file.files[0].type;
fileInfo[3] = file.files[0].size;
}
console.log(fileInfo); // here I see the full file and info. All looks correct.
google.script.run.withSuccessHandler(emailSent).sendAnEmail(fileInfo);
}
}
main()
is run. When main()
is run, the file is converted to the byte array and put it to fileInfo[0]
.fileInfo
, var fblob = Utilities.newBlob(fileInfo[0], mimeType, fname);
has the correct blob for Google Apps Script.In this modification, your Google Apps Script is not modified.
This code looks good but we can't use it because we are running on the Rhino JavaScript engine, not V8. We don't have support for newer JavaScript syntax. Could you give us an example of how it's done with older syntax? Ref
From your above comment, I modified as follows.
function main() {
var file = document.getElementById('myfile');
var fileInfo = [];
if(file.files.length) {
if (file.files[0].size < maxEmailAttachmentSize) {
var reader = new FileReader();
reader.onload = function(e) {
var bytes = new Int8Array(e.target.result);
var ar = [];
for (var i = 0; i < bytes.length; i++) {
ar.push(bytes[i]);
}
fileInfo[0] = ar;
fileInfo[1] = file.files[0].name;
fileInfo[2] = file.files[0].type;
fileInfo[3] = file.files[0].size;
console.log(fileInfo); // here I see the full file and info. All looks correct.
google.script.run.withSuccessHandler(emailSent).sendAnEmail(fileInfo);
}
reader.onerror = function(err) {
reject(err);
}
reader.readAsArrayBuffer(file.files[0]);
}
}
}
In this modification, your Google Apps Script is not modified.
Upvotes: 3