Share File With Email

Sharing from a script is one line, until the job runs twice and the client gets two “shared with you” emails. shareFileWithEmail(fileIdOrFile, email, role, opts) grants Viewer or Editor to one email and skips if that person already has that access or higher (owner, editor, or viewer for a viewer request). Want no notification email? Pass { notify: false } with the Drive advanced service enabled.

When to use

  • Sharing a deliverable when a row flips to Approved
  • Granting a client access to their folder’s report
  • Any re-runnable job that shouldn’t spam people with duplicate share emails

How to use this snippet

/** * Give an email Viewer or Editor access to a Drive file. Idempotent. * * @param {string|GoogleAppsScript.Drive.File} fileIdOrFile * @param {string} email * @param {'viewer'|'editor'} role * @param {{notify?: boolean}=} opts * notify default true. false = no email, which needs the Drive advanced service * (Editor → Services → Drive API). Without it, DriveApp sends Google's * standard "shared with you" email. * @return {{changed: boolean, method: 'none'|'drive-api-quiet'|'driveapp'}} */ function shareFileWithEmail(fileIdOrFile, email, role, opts) { opts = opts || {}; role = String(role || 'viewer').toLowerCase(); if (role !== 'viewer' && role !== 'editor') { throw new Error('shareFileWithEmail: role must be viewer or editor'); } var file = typeof fileIdOrFile === 'string' ? DriveApp.getFileById(fileIdOrFile) : fileIdOrFile; var who = String(email || '').trim().toLowerCase(); if (!who) throw new Error('shareFileWithEmail: email required'); var emails = function (users) { return users.map(function (u) { return String(u.getEmail()).toLowerCase(); }); }; // 1. Who already has access? Owner + editors count as "editor or higher". var owner = file.getOwner(); // null for files in shared drives var editors = emails(file.getEditors()) .concat(owner ? [String(owner.getEmail()).toLowerCase()] : []); var viewers = emails(file.getViewers()); // viewers and commenters // 2. Already enough access? Do nothing (no duplicate emails). if (editors.indexOf(who) !== -1) return { changed: false, method: 'none' }; if (role === 'viewer' && viewers.indexOf(who) !== -1) return { changed: false, method: 'none' }; // 3. Quiet share via the Drive advanced service, if enabled. if (opts.notify === false && typeof Drive !== 'undefined' && Drive.Permissions) { var apiRole = role === 'editor' ? 'writer' : 'reader'; if (Drive.Permissions.create) { // Drive API v3 (the default for newly added advanced services) Drive.Permissions.create( { role: apiRole, type: 'user', emailAddress: who }, file.getId(), { sendNotificationEmail: false, supportsAllDrives: true } ); } else { // Drive API v2 (older projects) Drive.Permissions.insert( { role: apiRole, type: 'user', value: who }, file.getId(), { sendNotificationEmails: false, supportsAllDrives: true } ); } return { changed: true, method: 'drive-api-quiet' }; } // 4. Plain DriveApp: works everywhere, always sends the share email. if (role === 'editor') file.addEditor(who); else file.addViewer(who); return { changed: true, method: 'driveapp' }; }

Example

function shareReportWithClient(row) { var res = shareFileWithEmail(row.ReportFileId, row.ClientEmail, 'viewer'); console.log('%s → %s (%s)', row.ReportFileId, row.ClientEmail, res.changed ? 'shared via ' + res.method : 'already had access'); return res; } // Quiet share (needs Services → Drive API enabled in the editor) shareFileWithEmail(fileId, 'teammate@example.com', 'editor', { notify: false });

Tips:

  • { notify: false } without the Drive advanced service falls back to DriveApp, which sends the email. Check res.method if silence matters.
  • Upgrading a Viewer to Editor works; asking for Viewer when they’re already an Editor is a no-op. This helper never downgrades.
  • Group addresses and domain-wide link sharing aren’t detected as “already has access.” The helper only checks people listed directly on the file.
  • Sharing to non-Google emails can be blocked by Workspace admin policy. Expect a thrown error in that case and log it on the row.
  • Got a URL instead of an id? Run it through extractDriveFileId first.

Tip: NitroGAS Co-Pilot can wire shareFileWithEmail into a status-change job and add a “shared at” stamp so reruns never re-share.

Happy Coding!

NitroGAS Chrome Extension

Want this snippet handy inside the Apps Script editor? NitroGAS gives you free themes and snippets — plus optional Co-Pilot when you want a boost (1-week, 1-month, or yearly passes — no subscription). Happy Coding!

Get the Extension