Build an external file-request intake system
Collect uploads from outside people into a Northwind intake folder via a web app.
Publié le 17 août 2025
Northwind regularly needs files from people who do not have a Google account — a freelance photographer’s raw exports, a client’s brand assets, a contractor’s invoice. The usual options are all awkward: email attachments get lost, “share this folder with me” needs an account, and third-party transfer tools are one more login to manage.
This script turns Apps Script into a tiny upload endpoint. It deploys as a web
app that accepts a POST request carrying a base64-encoded file, decodes it, and
drops it straight into a single Northwind intake folder. Anyone with the URL can
send a file — no account, no shared permissions — and everything lands in one
place for you to sort.
What you’ll need
- An intake folder in Drive where uploads should land. Keep it separate from client folders so you can review everything before it gets filed properly.
- The folder’s ID — the string in its URL after
/folders/. - A deployed web app. You create the deployment once from the Apps Script editor; the steps are under “Deploy it” below.
- Whoever sends files needs only the deployment URL and a way to make an HTTP
request —
curl, a form, or a script on their side.
The script
// The Drive folder every upload lands in. Review it before filing.
const INTAKE_FOLDER_ID = '1abcIntakeFolderId';
// Default MIME type when the caller does not declare one.
const DEFAULT_MIME = 'application/octet-stream';
// Reject anything larger than this. Apps Script's own limits are
// generous, but a cap stops one huge upload from blocking the folder.
const MAX_BYTES = 25 * 1024 * 1024; // 25 MB
/**
* Web-app entry point. Accepts a JSON POST with a base64-encoded file,
* writes it into the intake folder, and returns the new file's ID.
* Deploy this script as a web app for the endpoint to exist.
*/
function doPost(e) {
// 1. Parse the request body, tolerating a missing or empty payload.
const data = e && e.postData ? JSON.parse(e.postData.contents) : {};
// 2. Reject requests missing the two required fields.
if (!data.name || !data.contents) {
return jsonResponse({ error: 'missing fields: name and contents are required' });
}
// 3. Decode the base64 payload into raw bytes.
const bytes = Utilities.base64Decode(data.contents);
// 4. Enforce the size cap before touching Drive.
if (bytes.length > MAX_BYTES) {
return jsonResponse({ error: 'file too large; limit is ' + MAX_BYTES + ' bytes' });
}
// 5. Wrap the bytes in a blob and write it to the intake folder.
const blob = Utilities.newBlob(bytes, data.mimeType || DEFAULT_MIME, data.name);
const file = DriveApp.getFolderById(INTAKE_FOLDER_ID).createFile(blob);
// 6. Hand the caller the new file's ID so they can confirm receipt.
return jsonResponse({ fileId: file.getId(), name: file.getName() });
}
/**
* Wraps an object as a JSON HTTP response. Keeps every return path
* in doPost consistent.
*/
function jsonResponse(obj) {
return ContentService.createTextOutput(JSON.stringify(obj))
.setMimeType(ContentService.MimeType.JSON);
}
How it works
doPostruns whenever someone sends aPOSTto the deployment URL. It readse.postData.contents— the raw request body — and parses it as JSON, falling back to an empty object if the body is missing.- It checks for the two required fields,
nameandcontents. If either is absent it returns an error object rather than throwing, so the caller gets a readable response instead of a generic 500. - It decodes
contentsfrom base64 into a byte array. - It checks the byte count against
MAX_BYTESbefore writing anything, so an oversized upload is rejected cheaply. - It wraps the bytes in a blob — using the caller’s
mimeTypeorDEFAULT_MIME— and creates the file insideINTAKE_FOLDER_ID. - It returns the new file’s ID and name as JSON, which lets the sender confirm the upload succeeded.
Example run
A photographer sends a PDF with curl:
curl -X POST "$WEBAPP_URL" \
-H 'Content-Type: application/json' \
-d "{\"name\": \"brief.pdf\", \"mimeType\": \"application/pdf\", \"contents\": \"$(base64 brief.pdf)\"}"
The endpoint replies with the stored file’s ID:
{ "fileId": "1AbCdEfGhIjK…", "name": "brief.pdf" }
And brief.pdf now sits in the Northwind intake folder, ready to be reviewed and
filed. A request missing a field comes back just as clearly:
{ "error": "missing fields: name and contents are required" }
Deploy it
The endpoint only exists once the script is deployed as a web app:
- In the Apps Script editor, click Deploy → New deployment.
- Choose type Web app.
- Set Execute as to yourself, so files are created under your Drive.
- Set Who has access to Anyone — external senders have no Google account, so anonymous access is required.
- Click Deploy, approve the authorisation prompt, and copy the web-app URL. That URL is what you hand to anyone who needs to send you a file.
Re-deploy (Manage deployments → Edit) whenever you change the code, or the live endpoint keeps running the old version.
Watch out for
- An Anyone deployment accepts uploads from anyone who learns the URL. Treat the URL as a shared secret, and never run downstream processing on an upload without checking it first — that is what the separate intake folder is for.
- The script trusts the caller’s
name. Someone could send a file named to look like an existing one. Review the intake folder before moving anything into a client folder, and rename on the way. - Base64 inflates a file by roughly a third on the wire, and the whole request
is held in memory. Combined with the script’s quotas, that makes
MAX_BYTESa real ceiling — large media is better handled with a resumable upload to Drive directly. doPostonly fires onPOST. Opening the URL in a browser sends aGETand will show an error; that is expected, not a broken deployment.- There is no virus scanning here. Files an outside party uploads should be reviewed by a person before anyone at Northwind opens them.
À voir aussi
Build a recurring file-delivery system
Drop a fresh report file into a Northwind client folder weekly — they don't even ask.
Mis à jour le 15 déc. 2025
Build a Drive search index in Sheets
Make Northwind's file metadata searchable in a Sheet — like Spotlight for Drive.
Mis à jour le 7 déc. 2025
Build a shared-folder onboarding kit
Auto-grant new Northwind hires the folders they need on day one.
Mis à jour le 29 nov. 2025
Route saved email attachments to project folders
File Gmail attachments into the right Northwind client folder based on subject keywords.
Mis à jour le 25 nov. 2025
Bundle a folder of images into one PDF
Combine Northwind scans into a single deliverable PDF using a generation service.
Mis à jour le 17 nov. 2025