AppScript批量附加Drive多PDF到Gmail 移动端附件显示重复问题
问题现象
- 使用Google Sheets搭配AppScript实现从Google Drive导出发票并向客户发送邮件的功能,支持单封邮件附加多份发票
- 异常表现:已发送邮件内附件预览正常,收件人在电脑端下载、打开所有附件均显示正确,但移动端打开邮件时所有PDF附件内容完全相同
- 复现规律:该问题与移动端操作系统、邮件类App无关,所有客户收件时均会触发;如果从已发送邮件文件夹将原邮件转发给同一位客户,移动端即可正常显示所有不同的PDF附件
故障根因
核心原因是批量添加附件时生成的PDF Blob对象缺少唯一标识,触发了移动端邮件客户端的MIME解析缓存bug:
- 调用
file.getAs(MimeType.PDF)获取的Blob对象默认没有设置独立的Content-ID头,也没有显式绑定原文件名的强关联标识 - 桌面端邮件客户端按附件在邮件多部分结构中的索引顺序读取文件内容,因此不会出错;移动端邮件客户端会优先按
Content-ID缓存附件资源,当多个附件ID缺失或重复时,会直接复用第一个匹配缓存的附件内容,导致所有PDF显示为同一个文件 - 转发邮件时,Gmail服务端会重新构建整封邮件的MIME结构,自动为所有附件生成唯一的
Content-ID并修正多部分边界参数,因此转发后的邮件在移动端可以正常解析。
额外代码隐患:当前代码中检查日期文件夹是否存在的逻辑,写在了读取dateFolderName变量的逻辑之前,运行时会直接触发变量未定义的报错。
修复方案
调整代码逻辑顺序,同时为每个附件Blob显式设置唯一文件名和Content-ID,修复后的完整代码如下:
function createDraft() { var ss = SpreadsheetApp.getActiveSpreadsheet(); // 获取客户列表 var clientSheet = ss.getSheetByName("Clients"); var rangeData = clientSheet.getDataRange(); var lastRow = rangeData.getLastRow() - 1; var clientNameValues = clientSheet.getRange(2, 1, lastRow, 5).getValues(); // 获取发票根目录 var invoiceFolderId = [FOLDER_ID]; var invoiceFolder=DriveApp.getFolderById(invoiceFolderId); // 提前读取发票配置参数,修复变量顺序问题 var invoiceSheet = ss.getSheetByName("Invoice"); var dateFolderName = invoiceSheet.getRange(9, 6).getValue() var monthOutput = invoiceSheet.getRange(10, 6).getValue() var yearOutput = invoiceSheet.getRange(11, 6).getValue() var payDate = invoiceSheet.getRange(12, 6).getValue() // 检查日期文件夹是否存在 if (folderExists(dateFolderName, invoiceFolderId) === false) { throw new Error("对应日期的发票文件夹不存在,请检查配置"); } // 获取日期文件夹ID var dateFolderId = invoiceFolder.getFoldersByName(dateFolderName).next().getId(); var clientFolders=DriveApp.getFolderById(dateFolderId).getFolders(); var fileArray = [] // 遍历客户文件夹 while(clientFolders.hasNext()) { var clientEmail = '' var dir = clientFolders.next(); var clientFolderName = dir.getName() for(nn=0;nn<lastRow;++nn){ if (clientNameValues[nn][0]==clientFolderName){ clientEmail = clientNameValues[nn][4] }; } var files = dir.getFiles(); var j = 0; // 遍历文件夹内的发票文件 while(files.hasNext()) { var file = files.next(); var pdfBlob = file.getAs(MimeType.PDF); // 显式设置附件文件名 pdfBlob.setName(file.getName()); // 生成唯一Content-ID,避免移动端缓存串内容 pdfBlob.setContentId(`invoice_${clientFolderName.replace(/\s/g,'')}_${j}_${Date.now()}`); fileArray[j] = pdfBlob; j++; } GmailApp.createDraft(clientEmail, 'Customer Statement - ' + clientFolderName , 'Your customer statement(s) for ' + monthOutput + ' ' + yearOutput + ' is attached. \n' + 'Payment will be deposited into your account on ' + monthOutput + ' ' + payDate + ', ' + yearOutput + '.', { attachments: fileArray, name: '[ALIAS_NAME]', from: '[ALIAS_EMAIL]' }); // 重置附件数组 fileArray = [] } }
修复后发送的邮件会自带每个附件的唯一标识,移动端解析时不会出现缓存复用错误,无需转发即可正常查看所有不同的PDF附件。
内容的提问来源于stack exchange,提问作者greenerr
相关产品推荐
相关产品推荐

