无法使用 Gmail PHP API 获取电子邮件正文

Posted

技术标签:

【中文标题】无法使用 Gmail PHP API 获取电子邮件正文【英文标题】:Cannot get the body of email with Gmail PHP API 【发布时间】:2015-12-15 19:56:05 【问题描述】:

我在使用 Gmail php API 时遇到问题。

我想检索电子邮件的正文内容,但我只能检索带有附件的电子邮件!我的问题是为什么?

到目前为止,这是我的代码:

// Authentication things above...
$client = getClient();
$gmail = new Google_Service_Gmail($client);    
$list = $gmail->users_messages->listUsersMessages('me', ['maxResults' => 1000]);

while ($list->getMessages() != null)    
    foreach ($list->getMessages() as $mlist)                
        $message_id = $mlist->id;   
        $optParamsGet2['format'] = 'full';
        $single_message = $gmail->users_messages->get('me', $message_id, $optParamsGet2);

        $threadId = $single_message->getThreadId();
        $payload = $single_message->getPayload();
        $headers = $payload->getHeaders();
        $parts = $payload->getParts();
        //print_r($parts); PRINTS SOMETHING ONLY IF I HAVE ATTACHMENTS...
        $body = $parts[0]['body'];
        $rawData = $body->data;
        $sanitizedData = strtr($rawData,'-_', '+/');
        $decodedMessage = base64_decode($sanitizedData); //should display my body content
    

    if ($list->getNextPageToken() != null) 
        $pageToken = $list->getNextPageToken();
        $list = $gmail->users_messages->listUsersMessages('me', ['pageToken' => $pageToken, 'maxResults' => 1000]);
     else 
        break;
    

我知道检索内容的第二个选项是使用位于 Headers 部分中的 sn-p,但它只检索前 50 个左右的字符,这不是很有用。

【问题讨论】:

谁能帮帮我。我使用这个网址 $endpoint = "googleapis.com/gmail/v1/users/me/messages/$id?format=full";但它只在一封电子邮件中获得 194 个字符,而不是完整的电子邮件。我该怎么办? 【参考方案1】:

让我们做一个小实验。我给自己发了两条消息。一个有附件,一个没有。

请求:

GET https://www.googleapis.com/gmail/v1/users/me/messages?maxResults=2

回应:


 "messages": [
  
   "id": "14fe21fd6b3fb46f",
   "threadId": "14fe21fd6b3fb46f"
  ,
  
   "id": "14fe21f9341ed73c",
   "threadId": "14fe21f9341ed73c"
  
 ],
 "nextPageToken": "08943597140129624594",
 "resultSizeEstimate": 3

我只要求有效载荷,因为这是所有相关部分的所在:

fields = payload

GET https://www.googleapis.com/gmail/v1/users/me/messages/14fe21fd6b3fb46f?fields=payload

GET https://www.googleapis.com/gmail/v1/users/me/messages/14fe21f9341ed73c?fields=payload

没有附件的邮件:


 "payload": 
  "parts": [
   
    "partId": "0",
    "mimeType": "text/plain",
    "filename": "",
    "headers": [
     
      "name": "Content-Type",
      "value": "text/plain; charset=UTF-8"
     
    ],
    "body": 
     "size": 22,
     "data": "aGVjaz8gTm8gYXR0YWNobWVudD8NCg=="
    
   ,
   
    "partId": "1",
    "mimeType": "text/html",
    "filename": "",
    "headers": [
     
      "name": "Content-Type",
      "value": "text/html; charset=UTF-8"
     
    ],
    "body": 
     "size": 43,
     "data": "PGRpdiBkaXI9Imx0ciI-aGVjaz8gTm8gYXR0YWNobWVudD88L2Rpdj4NCg=="
    
   
  ]
 

带附件的邮件:


 "payload": 
  "parts": [
   
    "mimeType": "multipart/alternative",
    "filename": "",
    "headers": [
     
      "name": "Content-Type",
      "value": "multipart/alternative; boundary=001a1142e23c551e8e05200b4be0"
     
    ],
    "body": 
     "size": 0
    ,
    "parts": [
     
      "partId": "0.0",
      "mimeType": "text/plain",
      "filename": "",
      "headers": [
       
        "name": "Content-Type",
        "value": "text/plain; charset=UTF-8"
       
      ],
      "body": 
       "size": 9,
       "data": "V293IG1hbg0K"
      
     ,
     
      "partId": "0.1",
      "mimeType": "text/html",
      "filename": "",
      "headers": [
       
        "name": "Content-Type",
        "value": "text/html; charset=UTF-8"
       
      ],
      "body": 
       "size": 30,
       "data": "PGRpdiBkaXI9Imx0ciI-V293IG1hbjwvZGl2Pg0K"
      
     
    ]
   ,
   
    "partId": "1",
    "mimeType": "image/jpeg",
    "filename": "feelthebern.jpg",
    "headers": [
     
      "name": "Content-Type",
      "value": "image/jpeg; name=\"feelthebern.jpg\""
     ,
     
      "name": "Content-Disposition",
      "value": "attachment; filename=\"feelthebern.jpg\""
     ,
     
      "name": "Content-Transfer-Encoding",
      "value": "base64"
     ,
     
      "name": "X-Attachment-Id",
      "value": "f_ieq3ev0i0"
     
    ],
    "body": 
     "attachmentId": "ANGjdJ_2xG3WOiLh6MbUdYy4vo2VhV2kOso5AyuJW3333rbmk8BIE1GJHIOXkNIVGiphP3fGe7iuIl_MGzXBGNGvNslwlz8hOkvJZg2DaasVZsdVFT_5JGvJOLefgaSL4hqKJgtzOZG9K1XSMrRQAtz2V0NX7puPdXDU4gvalSuMRGwBhr_oDSfx2xljHEbGG6I4VLeLZfrzGGKW7BF-GO_FUxzJR8SizRYqIhgZNA6PfRGyOhf1s7bAPNW3M9KqWRgaK07WTOYl7DzW4hpNBPA4jrl7tgsssExHpfviFL7yL52lxsmbsiLe81Z5UoM",
     "size": 100446
    
   
  ]
 

这些响应对应于您代码中的$parts。如您所见,如果幸运的话,$parts[0]['body']->data 会给您想要的,但大多数时候不会。

通常有两种方法可以解决这个问题。你可以实现以下算法(你比我更擅长 PHP,但这是它的大致轮廓):

    遍历payload.parts 并检查它是否包含具有您要查找的主体的parttext/plaintext/html)。如果有,您的搜索就完成了。如果您正在解析像上面这样没有附件的邮件,这就足够了。 再次执行第 1 步,但这次使用您刚刚检查的 parts 中的 parts 递归。你最终会找到你的part。如果您正在解析带有附件的上述邮件,最终会找到您的body

算法可能如下所示(javascript 中的示例):

var response = 
 "payload": 
  "parts": [
   
    "mimeType": "multipart/alternative",
    "filename": "",
    "headers": [
     
      "name": "Content-Type",
      "value": "multipart/alternative; boundary=001a1142e23c551e8e05200b4be0"
     
    ],
    "body": 
     "size": 0
    ,
    "parts": [
     
      "partId": "0.0",
      "mimeType": "text/plain",
      "filename": "",
      "headers": [
       
        "name": "Content-Type",
        "value": "text/plain; charset=UTF-8"
       
      ],
      "body": 
       "size": 9,
       "data": "V293IG1hbg0K"
      
     ,
     
      "partId": "0.1",
      "mimeType": "text/html",
      "filename": "",
      "headers": [
       
        "name": "Content-Type",
        "value": "text/html; charset=UTF-8"
       
      ],
      "body": 
       "size": 30,
       "data": "PGRpdiBkaXI9Imx0ciI-V293IG1hbjwvZGl2Pg0K"
      
     
    ]
   ,
   
    "partId": "1",
    "mimeType": "image/jpeg",
    "filename": "feelthebern.jpg",
    "headers": [
     
      "name": "Content-Type",
      "value": "image/jpeg; name=\"feelthebern.jpg\""
     ,
     
      "name": "Content-Disposition",
      "value": "attachment; filename=\"feelthebern.jpg\""
     ,
     
      "name": "Content-Transfer-Encoding",
      "value": "base64"
     ,
     
      "name": "X-Attachment-Id",
      "value": "f_ieq3ev0i0"
     
    ],
    "body": 
     "attachmentId": "ANGjdJ_2xG3WOiLh6MbUdYy4vo2VhV2kOso5AyuJW3333rbmk8BIE1GJHIOXkNIVGiphP3fGe7iuIl_MGzXBGNGvNslwlz8hOkvJZg2DaasVZsdVFT_5JGvJOLefgaSL4hqKJgtzOZG9K1XSMrRQAtz2V0NX7puPdXDU4gvalSuMRGwBhr_oDSfx2xljHEbGG6I4VLeLZfrzGGKW7BF-GO_FUxzJR8SizRYqIhgZNA6PfRGyOhf1s7bAPNW3M9KqWRgaK07WTOYl7DzW4hpNBPA4jrl7tgsssExHpfviFL7yL52lxsmbsiLe81Z5UoM",
     "size": 100446
    
   
  ]
 
;

// In e.g. a plain text message, the payload is the only part.
var parts = [response.payload];

while (parts.length) 
  var part = parts.shift();
  if (part.parts) 
    parts = parts.concat(part.parts);
  

  if(part.mimeType === 'text/html') 
    var decodedPart = decodeURIComponent(escape(atob(part.body.data.replace(/\-/g, '+').replace(/\_/g, '/'))));
    console.log(decodedPart);
  

更简单的选择是只获取邮件的原始数据,然后让已经编写好的库为您完成工作:

请求:

format = raw
fields = raw

GET https://www.googleapis.com/gmail/v1/users/me/messages/14fe21fd6b3fb46f?format=raw&fields=raw

回应:


 "raw": "TUlNRS1WZXJzaW9uOiAxLjANClJlY2VpdmVkOiBieSAxMC4yOC45OS4xOTYgd2l0aCBIVFRQOyBGcmksIDE4IFNlcCAyMDE1IDEzOjIzOjAxIC0wNzAwIChQRFQpDQpEYXRlOiBGcmksIDE4IFNlcCAyMDE1IDIyOjIzOjAxICswMjAwDQpEZWxpdmVyZWQtVG86IGVtdGhvbGluQGdtYWlsLmNvbQ0KTWVzc2FnZS1JRDogPENBRHNaTFJ5eGk2UGt0MHZnUS1iZHd1N2FNLWNHRmZKcEwrRHYyb3ZKOGp4SGN4VWhfQUBtYWlsLmdtYWlsLmNvbT4NClN1YmplY3Q6IFdoYXQgZGENCkZyb206IEVtaWwgVGhvbGluIDxlbXRob2xpbkBnbWFpbC5jb20-DQpUbzogRW1pbCBUaG9saW4gPGVtdGhvbGluQGdtYWlsLmNvbT4NCkNvbnRlbnQtVHlwZTogbXVsdGlwYXJ0L2FsdGVybmF0aXZlOyBib3VuZGFyeT0wMDFhMTE0NjhmMTY1YzUwNDUwNTIwMGI0YzYxDQoNCi0tMDAxYTExNDY4ZjE2NWM1MDQ1MDUyMDBiNGM2MQ0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PVVURi04DQoNCmhlY2s_IE5vIGF0dGFjaG1lbnQ_DQoNCi0tMDAxYTExNDY4ZjE2NWM1MDQ1MDUyMDBiNGM2MQ0KQ29udGVudC1UeXBlOiB0ZXh0L2h0bWw7IGNoYXJzZXQ9VVRGLTgNCg0KPGRpdiBkaXI9Imx0ciI-aGVjaz8gTm8gYXR0YWNobWVudD88L2Rpdj4NCg0KLS0wMDFhMTE0NjhmMTY1YzUwNDUwNTIwMGI0YzYxLS0="

第二种方法的最大缺点是,如果您获取原始消息,您将立即下载所有附件数据,这对于您的用例来说可能是非常多的数据。

我不擅长 PHP,但如果您想采用第二种解决方案,this 看起来很有希望!祝你好运!

【讨论】:

太棒了!非常感谢创立!我将在下周一使用第一种方法,并为未来的用户粘贴完整的代码。 @F3L1X79 没问题 :) 很高兴我能帮上忙。期待看到代码! 我正在处理这个问题几天.. 你刚刚拯救了我的一天。非常感谢! 仅供参考,检索内容的最终代码写在我自己的答案上(经过测试和批准)。 @Tholle 我明白了,谢谢!没有意识到我必须像我认为的那样将它实际放入一个数组中。现在就像一个魅力。【参考方案2】:

更新:您可能想查看我在此答案下方的第二个答案以获得更完整的代码。

终于,我今天工作了,所以这是寻找尸体的完整代码答案 - 感谢 @Tholle

// Authentication things above
/*
 * Decode the body.
 * @param : encoded body  - or null
 * @return : the body if found, else FALSE;
 */
function decodeBody($body) 
    $rawData = $body;
    $sanitizedData = strtr($rawData,'-_', '+/');
    $decodedMessage = base64_decode($sanitizedData);
    if(!$decodedMessage)
        $decodedMessage = FALSE;
    
    return $decodedMessage;


$client = getClient();
$gmail = new Google_Service_Gmail($client);

$list = $gmail->users_messages->listUsersMessages('me', ['maxResults' => 1000]);

try
    while ($list->getMessages() != null) 

        foreach ($list->getMessages() as $mlist) 

            $message_id = $mlist->id;
            $optParamsGet2['format'] = 'full';
            $single_message = $gmail->users_messages->get('me', $message_id, $optParamsGet2);
            $payload = $single_message->getPayload();

            // With no attachment, the payload might be directly in the body, encoded.
            $body = $payload->getBody();
            $FOUND_BODY = decodeBody($body['data']);

            // If we didn't find a body, let's look for the parts
            if(!$FOUND_BODY) 
                $parts = $payload->getParts();
                foreach ($parts  as $part) 
                    if($part['body']) 
                        $FOUND_BODY = decodeBody($part['body']->data);
                        break;
                    
                    // Last try: if we didn't find the body in the first parts, 
                    // let's loop into the parts of the parts (as @Tholle suggested).
                    if($part['parts'] && !$FOUND_BODY) 
                        foreach ($part['parts'] as $p) 
                            // replace 'text/html' by 'text/plain' if you prefer
                            if($p['mimeType'] === 'text/html' && $p['body']) 
                                $FOUND_BODY = decodeBody($p['body']->data);
                                break;
                            
                        
                    
                    if($FOUND_BODY) 
                        break;
                    
                
            
            // Finally, print the message ID and the body
            print_r($message_id . " : " . $FOUND_BODY);
        

        if ($list->getNextPageToken() != null) 
            $pageToken = $list->getNextPageToken();
            $list = $gmail->users_messages->listUsersMessages('me', ['pageToken' => $pageToken, 'maxResults' => 1000]);
         else 
            break;
        
    
 catch (Exception $e) 
    echo $e->getMessage();

如您所见,我的问题是,有时无法在 payload->parts 中找到 body,而是直接在 payload->body 中找到! (另外我为多个部分添加了循环)。

希望这对其他人有所帮助。

【讨论】:

这很有趣,你知道body在payload->body而不是payload->parts中的条件是什么吗? @guival,不确定,但如果我没记错,这取决于您的邮件是否有附件。好久没用这个脚本了,抱歉。 @F3L1X79 好的,谢谢,到目前为止我发现如果有效载荷mimeTypemultipart/alternative,那么主体将在有效载荷部分中,如果mimeType 是@ 987654327@ 或 text/html 正文将在有效负载正文中。我还没有测试附件,但我会留意它们 谁能帮帮我。我使用这个网址 $endpoint = "googleapis.com/gmail/v1/users/me/messages/$id?format=full";但它只在一封电子邮件中获得 194 个字符,而不是完整的电子邮件。我该怎么办? 代码应该是递归的,请看***.com/a/54139473/439944【参考方案3】:

对于那些感兴趣的人,我大大改进了我的最后一个答案,使其与 text/html 一起使用(必要时回退到 text/plain)并将图像转换为 base64 附件,当打印为完整的 HTML 时将自动加载!

代码一点也不完美,而且太长,无法详细解释,但它对我有用。

随意接受并调整它(如有必要,可能会更正/改进它)。

// Authentication things above
/*
 * Decode the body.
 * @param : encoded body  - or null
 * @return : the body if found, else FALSE;
 */
function decodeBody($body) 
    $rawData = $body;
    $sanitizedData = strtr($rawData,'-_', '+/');
    $decodedMessage = base64_decode($sanitizedData);
    if(!$decodedMessage)
        $decodedMessage = FALSE;
    
    return $decodedMessage;


$client = getClient();
$gmail = new Google_Service_Gmail($client);

$list = $gmail->users_messages->listUsersMessages('me', ['maxResults' => 1000]);

try
    while ($list->getMessages() != null) 

        foreach ($list->getMessages() as $mlist) 

            $message_id = $mlist->id;
            $optParamsGet2['format'] = 'full';
            $single_message = $gmail->users_messages->get('me', $message_id, $optParamsGet2);
            $payload = $single_message->getPayload();
            $parts = $payload->getParts();
            // With no attachment, the payload might be directly in the body, encoded.
            $body = $payload->getBody();
            $FOUND_BODY = FALSE;
            // If we didn't find a body, let's look for the parts
            if(!$FOUND_BODY) 
                foreach ($parts  as $part) 
                    if($part['parts'] && !$FOUND_BODY) 
                        foreach ($part['parts'] as $p) 
                            if($p['parts'] && count($p['parts']) > 0)
                                foreach ($p['parts'] as $y) 
                                    if(($y['mimeType'] === 'text/html') && $y['body']) 
                                        $FOUND_BODY = decodeBody($y['body']->data);
                                        break;
                                    
                                
                             else if(($p['mimeType'] === 'text/html') && $p['body']) 
                                $FOUND_BODY = decodeBody($p['body']->data);
                                break;
                            
                        
                    
                    if($FOUND_BODY) 
                        break;
                    
                
            
            // let's save all the images linked to the mail's body:
            if($FOUND_BODY && count($parts) > 1)
                $images_linked = array();
                foreach ($parts  as $part) 
                    if($part['filename'])
                        array_push($images_linked, $part);
                     else
                        if($part['parts']) 
                            foreach ($part['parts'] as $p) 
                                if($p['parts'] && count($p['parts']) > 0)
                                    foreach ($p['parts'] as $y) 
                                        if(($y['mimeType'] === 'text/html') && $y['body']) 
                                            array_push($images_linked, $y);
                                        
                                    
                                 else if(($p['mimeType'] !== 'text/html') && $p['body']) 
                                    array_push($images_linked, $p);
                                
                            
                        
                    
                
                // special case for the wdcid...
                preg_match_all('/wdcid(.*)"/Uims', $FOUND_BODY, $wdmatches);
                if(count($wdmatches)) 
                    $z = 0;
                    foreach($wdmatches[0] as $match) 
                        $z++;
                        if($z > 9)
                            $FOUND_BODY = str_replace($match, 'image0' . $z . '@', $FOUND_BODY);
                         else 
                            $FOUND_BODY = str_replace($match, 'image00' . $z . '@', $FOUND_BODY);
                        
                    
                
                preg_match_all('/src="cid:(.*)"/Uims', $FOUND_BODY, $matches);
                if(count($matches)) 
                    $search = array();
                    $replace = array();
                    // let's trasnform the CIDs as base64 attachements 
                    foreach($matches[1] as $match) 
                        foreach($images_linked as $img_linked) 
                            foreach($img_linked['headers'] as $img_lnk) 
                                if( $img_lnk['name'] === 'Content-ID' || $img_lnk['name'] === 'Content-Id' || $img_lnk['name'] === 'X-Attachment-Id')
                                    if ($match === str_replace('>', '', str_replace('<', '', $img_lnk->value)) 
                                            || explode("@", $match)[0] === explode(".", $img_linked->filename)[0]
                                            || explode("@", $match)[0] === $img_linked->filename)
                                        $search = "src=\"cid:$match\"";
                                        $mimetype = $img_linked->mimeType;
                                        $attachment = $gmail->users_messages_attachments->get('me', $mlist->id, $img_linked['body']->attachmentId);
                                        $data64 = strtr($attachment->getData(), array('-' => '+', '_' => '/'));
                                        $replace = "src=\"data:" . $mimetype . ";base64," . $data64 . "\"";
                                        $FOUND_BODY = str_replace($search, $replace, $FOUND_BODY);
                                    
                                
                            
                        
                    
                
            
            // If we didn't find the body in the last parts, 
            // let's loop for the first parts (text-html only)
            if(!$FOUND_BODY) 
                foreach ($parts  as $part) 
                    if($part['body'] && $part['mimeType'] === 'text/html') 
                        $FOUND_BODY = decodeBody($part['body']->data);
                        break;
                    
                
            
            // With no attachment, the payload might be directly in the body, encoded.
            if(!$FOUND_BODY) 
                $FOUND_BODY = decodeBody($body['data']);
            
            // Last try: if we didn't find the body in the last parts, 
            // let's loop for the first parts (text-plain only)
            if(!$FOUND_BODY) 
                foreach ($parts  as $part) 
                    if($part['body']) 
                        $FOUND_BODY = decodeBody($part['body']->data);
                        break;
                    
                
            
            if(!$FOUND_BODY) 
                $FOUND_BODY = '(No message)';
            
            // Finally, print the message ID and the body
            print_r($message_id . ": " . $FOUND_BODY);
        

        if ($list->getNextPageToken() != null) 
            $pageToken = $list->getNextPageToken();
            $list = $gmail->users_messages->listUsersMessages('me', ['pageToken' => $pageToken, 'maxResults' => 1000]);
         else 
            break;
        
    
 catch (Exception $e) 
    echo $e->getMessage();

干杯。

【讨论】:

适用于所有类型的附件,但不适用于 jpg 或 jpeg。 Bmp虽然下载得很好。你能帮忙吗?? 实际上,我可以毫无问题地显示位于电子邮件正文中的所有类型的图像。对于位于附件中的那些,您可能希望在 $payload->getParts() 上循环。也许这是你的问题? 身体工作得很好。所以我需要应用 $payload->getParts() 迭代?请问您能提供额外的帮助吗? 我欠你一杯啤酒!!优秀的代码!绝对完美! 这是一个很好的解决方案!完美地在不同的情况下找到身体!谢谢!【参考方案4】:

我编写此代码是为了改进 @F3L1X79 的答案,因为它可以正确过滤 html 响应。

<?php
ini_set("display_errors", 1);
ini_set("track_errors", 1);
ini_set("html_errors", 1);
error_reporting(E_ALL);
require_once __DIR__ . '/vendor/autoload.php';

session_start();

function decodeBody($body) 
    $rawData = $body;
    $sanitizedData = strtr($rawData,'-_', '+/');
    $decodedMessage = base64_decode($sanitizedData);
    if(!$decodedMessage)
        $decodedMessage = FALSE;
    
    return $decodedMessage;


function fetchMails($gmail, $q) 

try
    $list = $gmail->users_messages->listUsersMessages('me', array('q' => $q));
    while ($list->getMessages() != null) 

        foreach ($list->getMessages() as $mlist) 

            $message_id = $mlist->id;
            $optParamsGet2['format'] = 'full';
            $single_message = $gmail->users_messages->get('me', $message_id, $optParamsGet2);
            $payload = $single_message->getPayload();

            // With no attachment, the payload might be directly in the body, encoded.
            $body = $payload->getBody();
            $FOUND_BODY = decodeBody($body['data']);

            // If we didn't find a body, let's look for the parts
            if(!$FOUND_BODY) 
                $parts = $payload->getParts();
                foreach ($parts  as $part) 
                    if($part['body'] && $part['mimeType'] == 'text/html') 
                        $FOUND_BODY = decodeBody($part['body']->data);
                        break;
                    
                
             if(!$FOUND_BODY) 
                foreach ($parts  as $part) 
                    // Last try: if we didn't find the body in the first parts, 
                    // let's loop into the parts of the parts (as @Tholle suggested).
                    if($part['parts'] && !$FOUND_BODY) 
                        foreach ($part['parts'] as $p) 
                            // replace 'text/html' by 'text/plain' if you prefer
                            if($p['mimeType'] === 'text/html' && $p['body']) 
                                $FOUND_BODY = decodeBody($p['body']->data);
                                break;
                            
                        
                    
                    if($FOUND_BODY) 
                        break;
                    
                
            
            // Finally, print the message ID and the body
            print_r($message_id . " <br> <br> <br> *-*-*- " . $FOUND_BODY);
        

        if ($list->getNextPageToken() != null) 
            $pageToken = $list->getNextPageToken();
            $list = $gmail->users_messages->listUsersMessages('me', array('pageToken' => $pageToken));
         else 
            break;
        
    
 catch (Exception $e) 
    echo $e->getMessage();




$client = new Google_Client();
$client->setAuthConfig('client_secrets.json');
$client->addScope(Google_Service_Gmail::GMAIL_READONLY);

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) 
    $client->setAccessToken($_SESSION['access_token']);
    $gmail = new Google_Service_Gmail($client);
    $q = ' after:2016/11/7';
    fetchMails($gmail, $q);
 else 
    $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/gmail-api/oauth2callback.php';
    header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));

【讨论】:

这是解决问题最全面的方法。 谁能帮帮我。我使用这个网址 $endpoint = "googleapis.com/gmail/v1/users/me/messages/$id?format=full";但它只在一封电子邮件中获得 194 个字符,而不是完整的电子邮件。我该怎么办? format=full 是默认的,不需要发送。尝试不使用,您会得到不同的结果吗?另外,最好把它放在一个单独的问题中! :-)【参考方案5】:

作为进一步改进,代码应该是递归的,您还需要以“完整”格式加载消息以提取正文。您可以将以下三个函数放入您自己的类中。

private function decodeBody($body) 
    $rawData = $body;
    $sanitizedData = strtr($rawData,'-_', '+/');
    $decodedMessage = base64_decode($sanitizedData);
    if(!$decodedMessage)
        return false;

    return $decodedMessage;


private function decodeParts($parts)

    foreach ($parts as $part)
    
        if ($part->getMimeType() === 'text/html' && $part->getBody())
            if ($result = $this->decodeBody($part->getBody()->getData()))
                return $result;
    

    foreach ($parts as $part)
    
        if ($result = $this->decodeParts($part->getParts()))
            return $result;
    


/**
 * @param Google_Service_Gmail_Message $message
 * @return bool|null|string
 */
public function getMessageBody($message)

    $payload = $message->getPayload();
    if ($result = $this->decodeBody($payload->getBody()->getData()))
        return $result;

    return $this->decodeParts($payload->getParts());

【讨论】:

你能举个例子吗? @dearsina 对不起,你是对的。答案是缺少一项功能。我刚刚更新了它。您可以将它们复制到您自己的班级,然后致电getMessageBody()【参考方案6】:

简单、可靠的解决方案

我对其他答案不满意,因为它们都有缺陷(剧透中的详细说明),而且有些答案很长,并且混合了提问者(和我)没有寻找的功能。

警告您其他答案中的潜在问题: 没有纯文本回退 或未能处理 falsy 消息正文 - 字符串“0”(不太可能发生,但不太可能发生) 或者在有效载荷树结构中缺乏足够深入的搜索

所以我想我会省去其他人的麻烦并分享我的代码(在我的整个收件箱中测试过)。

// input: the message object (not the payload!)
// output: html or plain text
function msg_body($msg) 
   $body = msg_body_recursive($msg->payload);
   return array_key_exists('html', $body) ? $body['html'] : $body['plain'];


function msg_body_recursive($part) 
   if($part->mimeType == 'text/html') 
      return ['html' => decodeBody($part->body->data)];
    else if($part->mimeType == 'text/plain') 
      return ['plain' => decodeBody($part->body->data)];
    else if($part->parts) 
      $return = [];
      foreach($part->parts as $sub_part) 
         $result = msg_body_recursive($sub_part);
         $return = array_merge($return, $result);
         if(array_key_exists('html', $return))
            break;
      
      return $return;
   
   return [];


function decodeBody($encoded) 
   $sanitizedData = strtr($encoded,'-_', '+/');
   return base64_decode($sanitizedData);

【讨论】:

这是最好的答案。谢谢 我测试了其他解决方案,效果最好。确保你传递这样的东西: $service->users_messages->get('me', $message->getId());我花了一段时间才弄清楚。其他解决方案在 80% 的情况下有效,但在对象具有子部分时失败。非常感谢@potato。 这正是我所需要的,我喜欢它简短而甜美的事实。【参考方案7】:

我只是想补充@F3L1X79 的答案,在你break de foreach 循环之前,你必须检查$FOUND_BODY 变量是否为FALSE,所以我在每次break 之前添加了一个If 条件;在身体搜索中。如果你不这样做,即使没有找到主体,代码也会中断。

if($FOUND_BODY !== false) break;

【讨论】:

以上是关于无法使用 Gmail PHP API 获取电子邮件正文的主要内容,如果未能解决你的问题,请参考以下文章

GMAIL API 的 PHP 实现 - 使用多个字符串进行过滤

使用带有 Laravel PHP 的 Gmail Api 读取网站上的所有 gmail 收件箱,然后回复特定的电子邮件

Gmail API - PHP - 使用服务帐户发送电子邮件

使用 PHP 向使用 Gmail API 发送的电子邮件添加密件抄送

如何使用 java 和 google gmail-api 获取收到的邮件? [关闭]

使用 Gmail API 获取邮件正文