0
votes

I've been consuming StackOverflow info for years now and have never posted, but I've finally found something that stumps me, and doesn't seem to have a direct response anywhere. I work in Google Apps Script, and have successfully integrated scripts with the SendGrid V3 Web API to send emails, including emails with attachments. But for some reason I can't get it to work with a PDF pulled from Google Drive. Here is how I'm creating the attachment:

var filePath = "https://drive.google.com/file/d/19rzCtnOMWw0ZZM4FViMWVZWkRRnsWx3L/view?usp=sharing";
var response = UrlFetchApp.fetch(filePath);
var attachment = Utilities.base64Encode(response.getContent());

... and here is the object I'm passing to the v3/mail/send endpoint:

"attachments": [{"content": attachment, "type": "application/pdf", "filename": "testPDF.pdf"}]

When I do this, I receive an email with a PDF attachment, and the attachment is the same size as the PDF file in Google Drive. But when I try to open it, I get an error telling me I can't preview the file, and telling me to try downloading it instead. When I download and open, I get an "Error: Failed to load PDF document" message. Clearly I'm somehow creating an attachment that is not a proper PDF document. Is there anything in the above that someone can spot that I'm doing wrong?

I'm self-taught and a bit of a hack, so I apologize in advance if I'm missing something obvious, or if I've excluded critical information.

2

2 Answers

0
votes
  • Use getBlob() instead of base64Encode(response.getContent())
  • Use getAs(contentType)
  • Pass a variable of requested type instead of an object as an attachment.

Working sample:

function myFunction() {
  var filePath = "https://drive.google.com/file/d/19rzCtnOMWw0ZZM4FViMWVZWkRRnsWx3L/view?usp=sharing";
  var response = UrlFetchApp.fetch(filePath);
  var attachment = response.getBlob().getAs(MimeType.PDF);
  attachment.setName("testPDF.pdf");
  GmailApp.sendEmail("recipient", "subject", "body", {"attachments": [attachment]})
}

Sidenote:

If the file is located on your Drive, you can make your request much easier, without UrlfetchApp:

function myFunction2() {
  GmailApp.sendEmail("recipient", "subject", "body", {
    "attachments": [ DriveApp.getFileById("19rzCtnOMWw0ZZM4FViMWVZWkRRnsWx3L").getAs(MimeType.PDF)]}
  )
}
0
votes

Well, after much more digging, I found the answer I was looking for. What was initially so confusing to me was that I had successfully retrieved PDFs on the web and attached them to SendGrid messages using the same UrlFetchApp and base64encode pattern posted in my question. But through some other threads, I found out that UrlFetchApp doesn't work the same way with Google Drive files. After experimenting with the Drive API, I decided to look more closely at WHY the UrlFetchApp pattern was successful with "normal" URLs, and came to the conclusion that it was because the UrlFetchApp response has a method called "getContent()" that returns binary data. So I went back and looked at how to get binary data from a PDF stored on Google Drive, and came up with the below pattern:

  var docBytes = DriveApp.getFileById("19rzCtnOMWw0ZZM4FViMWVZWkRRnsWx3L").getBlob().getBytes();
  var doc = Utilities.base64Encode(docBytes);
  var attachments = [{"content": doc, "type": "application/pdf", "filename": docTitle}];  

I kept the call to the SendGrid endpoint v3/mail/send endpoint the same as before:

"attachments": [{"content": attachment, "type": "application/pdf", "filename": "testPDF.pdf"}]

... and now it works! Thank you again to ziganotschka for looking at this and giving me some clues to get me on the right track.