Permissions Error: Unable to Send Email with PDF attachment via Google Apps Script Trigger on Form Submission

40 Views Asked by At

I am trying to write a script which is attached to a Google Form. The form collects the user's name and email, then puts their name on a certificate on a Google Slide, and saves it as a PDF in a Google Drive. I want the program to send an email with the PDF or a link to the PDF.

I am running into a permissions error though. I can get it to do everything except send the email. This form is going to be housed on a Google site.

function onFormSubmit(e) {
// 1. Get form responses
    var formResponse = e.response;
    var itemResponses = formResponse.getItemResponses();

// First item is the user's name and the second item is the user's email
    var userName = itemResponses[0].getResponse();
    var userEmail = itemResponses[1].getResponse();
// 2. Open the Google Slides presentation. Presentation is shared to anyone with the link.
    var presentationUrl = MY SHARED URL GOES HERE;
    var presentationId = presentationUrl.match(/\/presentation\/d\/([a-zA-Z0-9-_]+)/)[1];
    var presentation = SlidesApp.openById(presentationId);
// 3. Replace placeholder text with user's name
    var slides = presentation.getSlides();
    var shapeIndex = 3; // Index of the shape containing the placeholder text
    var slide = slides[0];
    var shape = slide.getShapes()[shapeIndex];
    if (shape) {
    shape.getText().setText(userName);

// Save changes made to the presentation
    presentation.saveAndClose();

// Wait for changes to be applied
    Utilities.sleep(5000); // 5 seconds delay

// 4. Export presentation as PDF. This is where I keep getting the error message.
    var pdf = DriveApp.getFileById(presentationId).getAs('application/pdf');

// Extracting folder ID from the provided folder URL. The folder is shared to anyone with the link.
    var folderUrl = URL TO FOLDER GOES HERE.;
    var folderId = folderUrl.match(/[-\w]{25,}/);
    if (folderId) {
    folderId = folderId[0];
    } else {
    throw new Error("Folder ID not found in the URL.");
    }

// Accessing the folder and saving the PDF file.
    var folder = DriveApp.getFolderById(folderId);

//THIS IS WHERE I KEEP GETTING THE ERROR MESSAGE
    var pdfFile = folder.createFile(pdf);
    var pdfFileName = userName + "_Certificate.pdf";
    pdfFile.setName(pdfFileName);

// Generating the URL for the file in the user's local Google Drive
    var fileUrl = FILE URL GOES HERE;

// 5. Send email to the user with the download link
    var subject = "Your Certificate";
    var body = "Dear " + userName + ",\n\nPlease find your certificate attached or download it from the following link:\n" + fileUrl;
    MailApp.sendEmail(userEmail, subject, body, { attachments: [pdfFile] });
      } else {
    Logger.log("Shape not found.");
      }
}

Thoughts?

  1. The program has a trigger upon the submission of the form. I have tried running the program directly and allowing all relevant permissions.
  2. I have also gotten the program to successfully run by replacing the first variables with strings. Meaning: var userName = 'Name'; var userEmail = 'Email';
  3. I have also had ChatGPT try to debug the code, but it isn't really understanding the nature of my problem.
  4. I have also explored having it allow users to download the certificate locally, but I am having the same problem.
  5. I have added the Google Drive API, the Gmail API, and the Slides API. Edit: I realized that I did not include the error code- You do not have permission to call DriveApp.Folder.createFile. Required permissions: googleapis.com/auth/drive at onFormSubmit(onFormSubmit:44:26)
1

There are 1 best solutions below

0
DJP On

I'd suggest double checking your permissions:

  • who is the owner of the form?
  • Is the script bound to the form?
  • If not, who is the owner of the script?
  • Does the owner of the form (or script if it's not bound) have editor permissions on the folder where you want to create the file?

Re the last point, you say "the folder is shared to anyone with the link" - but do they have editor permissions? YOu probably don't want that anyway as that's giving the world full access, but so long as the owner of the form (or script if it's not bound) has editor access, it should work.

I replicated your script (with a few tweaks for personal preference about the flow), and it worked fine in my Google workspace. I've copied the slightly edited script below in case it's useful - I doubt the very minor changes I made were the issue for you.

function onFormSubmit(e) {
// 1. Get form responses
  var formResponse = e.response;
  var itemResponses = formResponse.getItemResponses();

// First item is the user's name and the second item is the user's email
  var userName = itemResponses[0].getResponse();
  var userEmail = itemResponses[1].getResponse();
  Logger.log(userName + ", " + userEmail);

// 2. Open the Google Slides presentation. Presentation is shared to anyone with the link.
  var presentationUrl = "https://docs.google.com/presentation/d/1B-A0x2OtQmlYAe1Yh9YvBh90foZSs9JMKHfrii2XXPc/edit#slide=id.p";
  var presentationId = presentationUrl.match(/[-\w]{25,}/);
  Logger.log(presentationId);
  var presentation = SlidesApp.openById(presentationId);

// 3. Replace placeholder text with user's name
  var slides = presentation.getSlides();
  var shapeIndex = 3; // Index of the shape containing the placeholder text
  var slide = slides[0];
  var shape = slide.getShapes()[shapeIndex];
  if (shape) {
    shape.getText().setText(userName);

// Save changes made to the presentation
    presentation.saveAndClose();

//4a. Get the folder where you want to save the PDF first
// Extracting folder ID from the provided folder URL. The folder is shared to anyone with the link.
    var folderUrl = "https://drive.google.com/drive/folders/1Pg6QJZX9WACTCwh0uY6nFRymNg695B1K";
    var folderId = folderUrl.match(/[-\w]{25,}/);
    if (folderId) {
      folderId = folderId[0];
    } else {
      throw new Error("Folder ID not found in the URL.");
    }
    var folder = DriveApp.getFolderById(folderId);

// 4b. THEN Export presentation as PDF to the folder.
    var pdf = DriveApp.getFileById(presentationId).getAs('application/pdf');
    pdf.setName(userName + "_Certificate.pdf");
    var pdfFile = folder.createFile(pdf);
    var fileUrl = pdfFile.getUrl();

  // 5. Send email to the user with the download link
    var subject = "Your Certificate";
    var body = "Dear " + userName + ",\n\nPlease find your certificate attached or download it from the following link:\n" + fileUrl;
    MailApp.sendEmail(userEmail, subject, body, { attachments: [pdfFile] });
  } else {
    Logger.log("Shape not found.");
  }
}