Microsoft Graph邮件发送后滞留草稿问题求助(附PHP代码)
问题:Microsoft Graph API发送邮件后草稿滞留未移至已发送文件夹
我们使用Microsoft Graph API(版本1.110.0)连接客户的Office365账户,每日发送超10万封邮件,这是一款基于Office365的专业物业管理CRM系统,后端部署在AWS EC2上。
我们的邮件发送流程如下:
- 创建邮件草稿
-(可选)为邮件添加附件 - 获取邮件以存储原始EML文件
- 发送邮件
所有接口调用均返回HTTP 2xx状态码,无异常抛出。99.8%的邮件发送流程正常:邮件先存入草稿箱,发送后自动移至已发送文件夹。但在0.2%的案例中(尤其当同一客户同时发送多封带附件的邮件时),邮件已成功送达收件人,但草稿未从草稿箱移至已发送文件夹,仍滞留原地。
我们发现已有其他用户报告过此问题,现寻求可行的解决方案。由于直接发送接口无法获取邮件EML文件(需通过messageId执行GET操作才能获取),因此我们无法重构代码采用该方式发送邮件。
以下是相关业务代码(复制可能存在小问题,但无语法错误):
$message = array( "subject" => "Test", "body" => array( "contentType" => "html", "content" => "<strong>message</strong>" ), "from" => array( "emailAddress" => array("name" => "sender", "address" => "mail@mail.de") ), "toRecipients" => array( "emailAddress" => array("name" => "receiver", "address" => "mail@mail.de") ), "replyTo" => [...], // 可选 "bccRecipients" => [...], // 可选 "ccRecipients" => [...] // 可选 ); $saveResult = $microsoftGraph->saveMail($message); $messageID = $saveResult->getId(); foreach($attachments as $attachment) { if($attachment["fileSize"] / 1000 <= 3000) { $attachmentRequest = array( "@odata.type" => "#microsoft.graph.fileAttachment", "name" => "file.pdf", "contentBytes" => base64_encode("raw") ); $microsoftGraph->addMailAttachment($messageID, $attachmentRequest); } else { $attachmentRequest = array( "AttachmentItem" => array( "attachmentType" => "file", "isInline" => false, "name" => "file.pdf", "size" => 1233 ) ); $uploadResult = $microsoftGraph->addMailAttachmentUploadSession($messageID, $attachmentRequest); $microsoftGraph->uploadFile($uploadResult->getUploadUrl(), "/path/to/file", 1233); } } $messageEML = $microsoftGraph->getMailFile($messageID); $this->saveMail((string)$messageEML->getRawBody()); $sendResult = $microsoftGraph->sendMail($messageID);
microsoftGraph类实现代码:
use Microsoft\Graph\Graph; use Microsoft\Graph\Model; class microsoftGraph { public function setTokens($accessToken, $accessTokenExpire, $refreshToken) { $this->accessToken = $accessToken; $this->accessTokenExpire = $accessTokenExpire; $this->refreshToken = $refreshToken; $this->setAccessToken(); } private function setAccessToken() { $this->graph = new Graph(); $this->graph->setAccessToken($this->accessToken); } public function saveMail($mailBody) { return $this->graph->createRequest("POST", "/me/messages") ->attachBody($mailBody) ->setReturnType(Model\Message::class) ->execute(); } public function addMailAttachment($itemID, $attachmentBody) { return $this->graph->createRequest("POST", "/me/messages/" . $itemID . "/attachments") ->attachBody($attachmentBody) ->execute(); } public function addMailAttachmentUploadSession($itemID, $attachmentBody) { return $this->graph->createRequest("POST", "/me/messages/" . $itemID . "/attachments/createUploadSession") ->attachBody($attachmentBody) ->setReturnType(Model\UploadSession::class) ->execute(); } public function uploadFile($uploadUrl, $file, $fileSize) { $maxPerUpload = 1000 * 3000; $splitCount = ceil($fileSize / $maxPerUpload); $start = 0; for($i = 0; $i < $splitCount; $i++) { $start = $i * $maxPerUpload; $size = ((($fileSize - $start) > $maxPerUpload) ? $maxPerUpload : ($fileSize - $start)); $end = $start + $size - 1; $headers = [ 'Content-Length' => $size, 'Content-Range' => 'bytes ' . $start . '-' . $end . '/' . $fileSize, 'Content-Type' => "application/octet-stream" ]; $guzzle = new \GuzzleHttp\Client(); $guzzle->put( $uploadUrl, [ 'headers' => $headers, 'body' => file_get_contents($file, false, null, $start, $size) ] ); } } public function getMailFile($itemID) { return $this->graph->createRequest("GET", "/me/messages/" . $itemID . "/\$value") ->execute(); } public function sendMail($itemID) { return $this->graph->createRequest("POST", "/me/messages/" . $itemID . "/send") ->execute(); } }
恳请各位提供解决方案,非常感谢!
内容的提问来源于stack exchange,提问作者Tobias Bambullis
相关产品推荐
相关产品推荐

