Google脚本超时且重复下载附件问题求助及优化建议
Google脚本优化:解决超时、重复下载问题并支持共享驱动器
问题分析
原脚本存在以下核心问题:
- 执行超时:一次性处理所有匹配线程,线程数量大时易触发Google Apps Script 6分钟执行上限
- 重复下载:仅给线程添加标签,脚本中断后会重复处理;未校验Drive中已存在的附件,导致重复占用空间
- 无共享驱动器支持:仅默认使用"我的驱动器",未满足优先使用Workspace共享驱动器的需求
修改后的完整代码
// 配置项 var fileTypesToExtract = ['csv', 'xlsm', 'xlsx', 'xls', 'pdf']; var folderName = 'Audit Grab to Sort'; var labelName = '@indrive'; var sharedDriveId = ''; // 替换为你的共享驱动器ID,留空则使用"我的驱动器" var batchSize = 50; // 每次处理的线程数量,避免超时 function GmailToDrive() { // 构建搜索查询 var queryParts = fileTypesToExtract.map(type => `filename:${type}`); var query = `in:inbox has:nouserlabels (${queryParts.join(' OR ')})`; var label = getGmailLabel_(labelName); var parentFolder = getFolder_(folderName); if (!parentFolder) return; var start = 0; var threads; do { // 分批获取线程,避免一次性处理过多导致超时 threads = GmailApp.search(query, start, batchSize); if (threads.length === 0) break; for (var i = 0; i < threads.length; i++) { var thread = threads[i]; var messages = thread.getMessages(); try { for (var j = 0; j < messages.length; j++) { var message = messages[j]; // 跳过已处理的邮件 if (message.hasLabel(label)) continue; var attachments = message.getAttachments(); for (var k = 0; k < attachments.length; k++) { var attachment = attachments[k]; // 过滤非目标类型的附件 if (!checkIfDefinedType_(attachment)) continue; var fileName = attachment.getName(); var fileSize = attachment.getSize(); var existingFile = findExistingFile_(parentFolder, fileName, fileSize); // 仅当Drive中不存在相同文件时创建 if (!existingFile) { parentFolder.createFile(attachment.copyBlob()); console.log(`已创建文件: ${fileName}`); } else { console.log(`文件已存在,跳过: ${fileName}`); } } // 处理完单封邮件后添加标签,精准标记已处理状态 message.addLabel(label); } // 给线程添加标签(可选,便于可视化筛选) thread.addLabel(label); } catch (e) { console.error(`处理线程失败: ${e.message},线程ID: ${thread.getId()}`); } } start += batchSize; } while (threads.length === batchSize); } function getFolder_(folderName) { try { // 优先使用共享驱动器 if (sharedDriveId) { var sharedDrive = DriveApp.getFolderById(sharedDriveId); var folders = sharedDrive.getFoldersByName(folderName); return folders.hasNext() ? folders.next() : sharedDrive.createFolder(folderName); } // 共享驱动器不可用时,回退到"我的驱动器" var folders = DriveApp.getFoldersByName(folderName); return folders.hasNext() ? folders.next() : DriveApp.createFolder(folderName); } catch (e) { console.error(`获取/创建文件夹失败: ${e.message}`); return null; } } function findExistingFile_(folder, fileName, fileSize) { // 查找同名且大小一致的文件,避免重复创建 var files = folder.getFilesByName(fileName); while (files.hasNext()) { var file = files.next(); if (file.getSize() === fileSize) { return file; } } return null; } function getGmailLabel_(name) { var label = GmailApp.getUserLabelByName(name); return label ? label : GmailApp.createLabel(name); } function checkIfDefinedType_(attachment) { var fileName = attachment.getName(); var extParts = fileName.split('.'); if (extParts.length < 2) return false; var fileExtension = extParts[extParts.length - 1].toLowerCase(); return fileTypesToExtract.indexOf(fileExtension) !== -1; }
关键优化点
- 分批处理线程:通过
GmailApp.search(query, start, batchSize)分页获取线程,每次处理50条,避免触发超时限制 - 精准标记已处理:给单封邮件添加标签而非线程,即使脚本中断,已处理的邮件也不会被重复扫描
- 附件重复校验:新增
findExistingFile_函数,检查目标文件夹中是否存在同名且大小一致的附件,存在则跳过创建 - 共享驱动器支持:新增
sharedDriveId配置项,优先从共享驱动器获取/创建文件夹,失败则回退到"我的驱动器" - 错误容错:添加try-catch块,单个线程处理失败不会导致整个脚本终止,同时输出错误日志便于排查
- 优化查询构建:使用数组map和join简化查询字符串拼接,更易维护
内容的提问来源于stack exchange,提问作者Michael Williams
相关产品推荐
相关产品推荐

