You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 06:22:04