The Problem: You're on set, and a last-minute change comes through. Do you have the latest call sheet? Are you frantically searching through your emails for the most recent unit list or movement order?
The Solution: This guide will help you set up a free, "set it and forget it" system that automatically saves the latest versions of key production documents to a dedicated folder in your Google Drive. Using an iOS Shortcut, you can then access the latest file with a single tap, confident you're always looking at the most current version.
Before you begin, make sure you have the following:
- A Google Account (which includes Gmail and Google Drive).
- An iPhone or iPad.
- The official Google Drive app installed on your iOS device from the App Store.
This system has three parts:
- Google Drive: A central folder acts as the home for your most current documents.
- Google Apps Script: A smart "robot" that lives in your Google account. It constantly watches your new emails for specific attachments.
- iOS Shortcut: A button on your iPhone home screen that instantly opens the latest file.
Think of the script you're about to install as a highly organized digital assistant working for you 24/7. It doesn't read the content of your emails; it only looks at the filenames of incoming attachments. Here’s its step-by-step process:
- Wakes Up on a Schedule: Every 15 minutes, the script wakes up and gets to work.
- Scans for New Mail: It asks Gmail, "Are there any new, unread emails that have a PDF attachment?"
- Inspects Attachments: If it finds any, it looks at the name of each PDF file.
- Looks for Keywords: It checks the filename against its list of keywords (like "callsheet", "CS", "unit list", etc.). Its search is smart, so it knows to match "CS" as a whole word, not as part of "specs".
- Files It Away: If it finds a match, it saves a copy of that PDF to the correct folder in your Google Drive—for example, a file with "callsheet" in the name goes into the "Call Sheets" folder.
- Keeps Things Tidy: If a file named
callsheet.pdfalready exists, the script cleverly moves the old version into a subfolder named "old" (stamping it with the date and time) before saving the new one. This ensures the main file in the folder is always the absolute latest version. - Finds the Newest: If you receive multiple unread emails with call sheets at once, the script is smart enough to identify which email is the most recent and will only save that one, ignoring the older ones.
- Marks as Done: Once it has saved an attachment from an email, it marks that email as "read". This is its signal that the work is done, so it doesn't accidentally process the same email again on its next run.
This entire process happens automatically in the background, ensuring your production folders are always effortlessly up to date.
Follow these steps to build your automated system.
This is where your up-to-date documents will live.
-
Go to Google Drive.
-
Create a new folder. Let's call it
Film Productionor something similar. -
Open that new folder. Look at the URL in your browser's address bar. You need to copy the Folder ID, which is the long string of letters and numbers at the end of the URL.
*Example:
https://drive.google.com/drive/folders/1a2b3c4d5e6f7g8h9i0j<- Copy this part.
- Go to script.google.com.
- Click New project in the top-left.
- Delete the sample
function myFunction() { ... }code in the editor window.
- Copy the entire code block below and paste it into the empty script editor.
- Find the line that says
const ROOT_FOLDER_ID = 'YOUR_FOLDER_ID_HERE';. - Replace
YOUR_FOLDER_ID_HEREwith the actual Folder ID you copied in Step 1. Make sure to keep the single quotes around it.
/**
* A production-grade script to automatically find and save specific email attachments.
* This script is designed to be robust, preventing common issues and handling errors gracefully.
*
* v5: Implements LockService, try/catch error handling, and folder caching.
*
* @OnlyCurrentDoc
*/
// --- CONFIGURATION: PASTE YOUR FOLDER ID BELOW ---
// Find this by opening your target Google Drive folder and copying the last part of the URL.
const ROOT_FOLDER_ID = 'YOUR_FOLDER_ID_HERE';
// This section defines which documents to look for. You can customize this.
const FILE_RULES = {
'callsheet.pdf': { keywords: ['call sheet', 'callsheet', 'CS'], folderName: 'Call Sheets' },
'prepdiary.pdf': { keywords: ['prep diary', 'prepdiary'], folderName: 'Prep Diaries' },
'unitlist.pdf': { keywords: ['unit list', 'unitlist'], folderName: 'Unit Lists' },
'movementorder.pdf': { keywords: ['Movement Order', 'MO'], folderName: 'Movement Orders' }
};
// --- SCRIPT LOGIC (No need to edit below this line) ---
function saveMostRecentAttachments() {
// Use a lock to prevent simultaneous runs. Wait up to 30 seconds.
const lock = LockService.getScriptLock();
if (!lock.tryLock(30000)) {
console.warn("Could not obtain lock. Another instance of the script is likely running. Skipping this run.");
return;
}
console.log("Script run started at: " + new Date().toLocaleTimeString());
// Wrap all logic in a try...catch...finally block for resilience.
try {
// Cache for Drive folder objects to reduce API calls.
const folderCache = {};
const rootFolder = DriveApp.getFolderById(ROOT_FOLDER_ID);
folderCache[ROOT_FOLDER_ID] = rootFolder;
const processedTypes = new Set();
const searchQuery = 'is:unread has:attachment filename:pdf';
const threads = GmailApp.search(searchQuery);
console.log(`Found ${threads.length} unread email thread(s) with PDF attachments to process.`);
if (threads.length === 0) {
console.log("No new emails to process. Ending script run.");
return;
}
threads.forEach(thread => {
const messages = thread.getMessages();
let threadMarkedAsRead = false;
messages.reverse().forEach(message => {
if (!message.isUnread()) return;
const attachments = message.getAttachments();
attachments.forEach(attachment => {
if (attachment.getContentType() !== 'application/pdf') return;
const attachmentName = attachment.getName();
console.log(`-- Checking attachment: '${attachmentName}'`);
for (const targetFilename in FILE_RULES) {
if (processedTypes.has(targetFilename)) continue;
const rule = FILE_RULES[targetFilename];
const foundKeyword = rule.keywords.find(keyword => {
const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(`(^|[^A-Za-z0-9])${escapedKeyword}([^A-Za-z0-9]|$)`, 'i');
return regex.test(attachmentName);
});
if (foundKeyword) {
console.log(` └─> Match found on keyword '${foundKeyword}'. Processing now.`);
const typeFolder = getOrCreateSubfolder(rootFolder, rule.folderName, folderCache);
const oldFolder = getOrCreateSubfolder(typeFolder, 'old', folderCache);
processFile(typeFolder, oldFolder, targetFilename, attachment);
processedTypes.add(targetFilename);
if (!threadMarkedAsRead) {
thread.markRead();
threadMarkedAsRead = true;
}
}
}
});
});
});
console.log("Script run finished successfully. Processed types: ", Array.from(processedTypes));
} catch (e) {
console.error("An error occurred during script execution: " + e.toString());
console.error("Stack Trace: " + e.stack);
} finally {
// ALWAYS release the lock at the end.
lock.releaseLock();
console.log("Script lock released. Execution complete.");
}
}
function getOrCreateSubfolder(parentFolder, folderName, cache) {
const cacheKey = parentFolder.getId() + '_' + folderName;
if (cache[cacheKey]) { return cache[cacheKey]; }
const folders = parentFolder.getFoldersByName(folderName);
if (folders.hasNext()) {
const folder = folders.next();
cache[cacheKey] = folder;
return folder;
}
console.log(` └─> Creating subfolder: '${folderName}' inside '${parentFolder.getName()}'`);
const newFolder = parentFolder.createFolder(folderName);
cache[cacheKey] = newFolder;
return newFolder;
}
function processFile(typeFolder, oldFolder, targetFilename, attachment) {
const existingFiles = typeFolder.getFilesByName(targetFilename);
if (existingFiles.hasNext()) {
const oldFile = existingFiles.next();
const timestamp = new Date().toISOString().replace(/:/g, '-').slice(0, 19);
const oldFilename = `${targetFilename.replace('.pdf', '')}_${timestamp}.pdf`;
console.log(` └─> Moving existing file to 'old' folder.`);
oldFile.moveTo(oldFolder).setName(oldFilename);
}
const blob = attachment.copyBlob();
const newFile = typeFolder.createFile(blob).setName(targetFilename);
console.log(` └─> Saved new file to '${typeFolder.getName()}' folder.`);
}This makes the script run automatically for you.
- In the script editor, click the Triggers icon (looks like a clock) on the left-hand menu.
- Click the + Add Trigger button in the bottom-right.
- Set up the trigger with these exact options:
- Choose which function to run:
saveMostRecentAttachments - Choose which deployment should run:
Head - Select event source:
Time-driven - Select type of time-based trigger:
Minutes timer - Select minute interval:
Every 15 minutes
- Choose which function to run:
- Click Save.
The first time you save the trigger, Google will ask for permission.
- Choose your Google account.
- You will see a "Google hasn't verified this app" warning. This is normal and expected because you are the developer.
- Click Advanced, then click Go to [Your Project Name] (unsafe).
- Review the permissions and click Allow.
Your automation is now live!
Follow this reliable method to create shortcuts to your files.
- Important First Step: Wait for your script to save at least one file (e.g.,
callsheet.pdf). Open the Google Drive app on your iPhone and manually open that file once. This "primes" the app and lets it know the file is important to you. - In the Google Drive app, tap the menu icon (☰) in the top-left corner.
- Go to Settings.
- Tap on Siri Shortcuts.
- Under the "Suggested" section, you should see an option like "Open callsheet.pdf".
- Tap the
+icon next to that suggestion. - On the next screen, you can record a voice phrase like "Latest Call Sheet" if you use Siri, but you don't have to. Just tap "Add to Siri".
The shortcut is now created and saved in Apple's Shortcuts app. Repeat these steps for your other documents (Unit List, etc.) after you've opened them once in the Drive app.
For true one-tap access, let's put that new shortcut in a widget.
- Go to your iPhone's Home Screen.
- Long-press on an empty area until your apps start to jiggle.
- Tap the
+icon in the top-left corner. - Search for or scroll down to find the Shortcuts widget.
- Choose a size (the single or four-shortcut size is best) and tap "Add Widget".
- The widget will appear on your screen. Tap it while in jiggle mode.
- You can now choose which shortcut (or folder of shortcuts) you want it to display. Select the "Open callsheet.pdf" shortcut you just made.
That's it! You now have a button on your Home Screen that will always open the latest version of your document.