使用Gmail API发送超5MB大附件遇“Entity too large”错误求解决
Fixing "Entity too large" Error When Sending Large Attachments (>5MB) via Gmail API with PHP Client Library
我之前在项目里也踩过一模一样的坑——照着官方文档和第三方教程操作,结果反复收到"Entity too large"错误,折腾了好一阵子才摸透问题的核心。下面是我亲测有效的解决方案,一步步帮你搞定:
核心前提:必须用可恢复上传(Resumable Upload)
Gmail API对超过5MB的附件强制要求使用可恢复上传模式,直接调用普通的messages.send接口传完整邮件内容肯定会触发报错。你需要先创建上传会话,分块上传附件,最后完成邮件发送流程。
PHP客户端库的正确代码流程
给你一份完整的可运行代码示例,我会拆解里面的关键细节:
<?php require __DIR__ . '/vendor/autoload.php'; // 初始化已完成OAuth2认证的Gmail客户端(这里假设你已经搞定了授权流程) $client = getYourAuthenticatedGmailClient(); // 替换成你的认证逻辑 $gmail = new Google\Service\Gmail($client); // 1. 构建邮件基础MIME结构(先预留附件位置) $boundary = uniqid('boundary_'); $rawMessage = <<<EOT To: recipient@example.com Subject: Test Large Attachment MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="$boundary" --$boundary Content-Type: text/plain; charset="UTF-8" This is a test email with a large attachment. --$boundary Content-Type: application/pdf; name="large_file.pdf" Content-Disposition: attachment; filename="large_file.pdf" Content-Transfer-Encoding: base64 EOT; // 2. 初始化可恢复上传会话 $message = new Google\Service\Gmail\Message(); $upload = new Google\Http\MediaFileUpload( $client, $gmail->users_messages->send('me', $message), 'message/rfc822', null, true, // 关键:启用可恢复上传 10485760 // 分块大小建议设为10MB,不要超过32MB的上限 ); // 计算完整邮件的总大小(基础MIME + 附件base64编码后的大小) $filePath = '/path/to/your/large_file.pdf'; $fileSize = filesize($filePath); $base64Size = ceil($fileSize * 4 / 3); // base64会增加约33%的体积 $totalSize = strlen($rawMessage) + $base64Size + strlen("\r\n--$boundary--"); $upload->setFileSize($totalSize); // 3. 分块上传完整邮件内容 $fileHandle = fopen($filePath, 'rb'); // 先上传基础MIME部分 $status = $upload->nextChunk($rawMessage); // 再分块上传附件的base64内容 while (!$status && !feof($fileHandle)) { $chunk = fread($fileHandle, 7864320); // 对应10MB原始文件的base64块(10MB*3/4=7.5MB) $status = $upload->nextChunk(base64_encode($chunk)); } // 上传结尾的边界标记 $status = $upload->nextChunk("\r\n--$boundary--"); fclose($fileHandle); // 4. 验证发送结果 if ($status) { echo "邮件发送成功!消息ID:" . $status->getId(); } else { echo "上传失败,请检查文件权限或网络连接"; } ?>
关键注意事项
- 分块大小匹配:原始文件分块设为10MB时,base64编码后的块要对应约7.5MB(因为base64是3字节转4字节),避免单次上传的块超过API限制。
- MIME结构严谨:边界标记必须前后一致,附件的Content-Type要和文件类型匹配,否则API会解析失败,误判为内容过大。
- 权限检查:确保你的OAuth2令牌拥有
https://www.googleapis.com/auth/gmail.send权限,且没有过期。 - 文件权限:确认PHP进程能读取目标大文件,避免因文件读取失败导致上传中断。
排查"Entity too large"的常见坑
- 你之前可能直接把包含大附件的完整raw字符串传给
messages.send,这种方式只支持5MB以内的内容; - 初始化
MediaFileUpload时没把resumable参数设为true,导致还是用了普通上传模式; - 邮件MIME结构错误(比如边界不闭合、附件编码错误),导致API解析时把损坏的内容判定为"过大"。
内容的提问来源于stack exchange,提问作者Yehuda
相关产品推荐
相关产品推荐

