PHP IMAP拡張機能を置き換え、OAuth2プロトコルで動作するようにGmailAPIを構成する

ラッキーな人ならば、それは唯一のOAuthを介して実行されます2021年2月15日の認可からGmailやその他の製品にするという事実のために用意されていない、私は「記事を読んでGoogleの埋め拡張PHP IMAPを」と悲しいは、 PHP IMAP拡張交換に行動を取るようになりましたGoogleAPIでのプロジェクト。答えより質問が多かったので、同時にマニュアルを走り書きしました。



次のタスクにPHPIMAPを使用しています。



  1. メールボックスから古い文字を削除します。残念ながら、企業のG Suiteアカウントのコントロールパネルでは、受信後N日後に組織のすべてのメールボックスからメッセージを削除する期間のみを構成できます。ただし、指定されたメールボックス内で、受信後の指定された異なる日数後にのみ、文字を削除する必要があります。
  2. 文字のフィルタリング、解析、マーキング当サイトから自動モードで多くの手紙が送られてきますが、その中には受取人に届かないものもあり、それに応じて報告があります。これらのレポートをキャッチし、分解し、電子メールでクライアントを見つけ、マネージャーがクライアントに連絡して電子メールアドレスの関連性を明確にできるように、人間が読める手紙を作成する必要があります。


この記事では、Gmail APIを使用してこれら2つのタスクを解決します(同時に、PHP IMAPが機能するように有効にされたメールボックス設定で、安全でないアプリケーションへのアクセスを無効にします。実際、2021年2月のひどい日に機能を停止します)。Gmailアプリケーションのいわゆるサービスアカウントを使用します。これを適切に構成すると、組織のすべてのメールボックスに接続して、それらのメールボックスで任意のアクションを実行できます。



1. GoogleAPI開発者コンソールでプロジェクトを作成します



このプロジェクトの助けを借りて、GmailとのAPIインタラクションを実行し、その中で同じサービスアカウントを作成します。



プロジェクトを作成するには:



  1. Google API開発者コンソールに移動し、G Suite管理者としてログインします(または、すべての権限を持つユーザーは誰ですか)
  2. 「プロジェクトの作成」ボタンを探しています。



    私はここで見つけました:
    image



    そしてここに:
    image



    プロジェクト名を入力して保存します。



    プロジェクトの作成
    image



  3. プロジェクトに移動し、[APIとサービスを有効にする]ボタンをクリックします。



    APIとサービスを有効にする
    image



    GmailAPIの選択



2.サービスアカウントを作成して構成します



これを行うには、公式マニュアルを使用するか、以下を読み続けてください。



  1. 追加したGmailAPIに移動し、[資格情報の作成]ボタンをクリックして、[サービスアカウント]を選択します。



    サービスアカウントの作成
    image



    何かを入力して[作成]をクリックします。



    サービスアカウントの詳細
    image



    他のすべては空白のままにすることができます:



    サービスアカウントのアクセス権
    image



    image



  2. , . G Suite, « — API».



    API
    image

    image



  3. « »:



    image



    «», « » , « OAuth» — :



    - https://mail.google.com/ -

    - https://www.googleapis.com/auth/gmail.modify -

    - https://www.googleapis.com/auth/gmail.readonly -

    - https://www.googleapis.com/auth/gmail.metadata -




    image

    image



  4. « G Suite»:



    image



    また、下のフィールドに製品の名前を入力してください。

  5. 次に、サービスアカウントキーを作成する必要があります。これは、アプリケーションで使用できるはずのファイルです。実際、彼は承認のために使用されます。



    これを行うには、プロジェクトの[資格情報]ページから、[サービスアカウントの管理]リンクをたどります。



    資格情報
    image



    「アクション-キーの作成」を選択し、次のように入力します。JSON:



    サービスアカウント管理
    image



    その後、キーファイルが生成されてコンピュータにダウンロードされます。このファイルはプロジェクトに配置され、GmailAPIを呼び出すときにアクセスできるようにする必要があります。



これでGmailAPIの構成が完了し、実際には、これまでにIMAPPHP拡張機能によって解決された関数を実装する私のココアコードが少しあります。



3.コードを書く



私が使用した GmailAPIの非常に優れた公式ドキュメント(クリックアンドクリック)がありますしかし、私は詳細なマニュアルを書き始めたので、私は自分のココアコードを添付します。



そこで、まず、composerを使用してGoogleクライアントライブラリ(apiclient)をインストールします:(



composer require google/apiclient



最初は、真の文学の専門家として、PHPクイックスタート示されているようにバージョン2.0のapiクライアントをインストールしましたが、最初のスタートでは、あらゆる種類のボーニングとアラームがPHP7.4に落ちました。 、したがって、同じことを行うことはお勧めしません)



次に、公式ドキュメントの例に基づいて、サービスアカウントキーファイルを指定することを忘れずに、Gmailを操作するための独自のクラスを作成します。



Gmailを操作するためのクラス
<?php
//     Gmail
class GmailAPI
{
    private $credentials_file = __DIR__ . '/../Gmail/credentials.json'; //   

    // ---------------------------------------------------------------------------------------------
    /**
     *   Google_Service_Gmail Authorized Gmail API instance
     *
     * @param  string $strEmail  
     * @return Google_Service_Gmail Authorized Gmail API instance
     * @throws Exception
     */
    function getService(string $strEmail){
        //    
        try{
            $client = new Google_Client();
            $client->setAuthConfig($this->credentials_file);
            $client->setApplicationName('My Super Project');
            $client->setScopes(Google_Service_Gmail::MAIL_GOOGLE_COM);
            $client->setSubject($strEmail);
            $service = new Google_Service_Gmail($client);
        }catch (Exception $e) {
            throw new \Exception('   getService: '.$e->getMessage());
        }
        return $service;
    }
    // ---------------------------------------------------------------------------------------------

    /**
     *    ID    
     *
     * @param  Google_Service_Gmail $service Authorized Gmail API instance.
     * @param  string $strEmail  
     * @param  array $arrOptionalParams      
     *         Gmail  after: 2020/08/20 in:inbox label:
     *      q  $opt_param
     * @return array  ID     array('arrErrors' => $arrErrors),   
     * @throws Exception
     */
    function listMessageIDs(Google_Service_Gmail $service, string $strEmail, array $arrOptionalParams = array()) {
        $arrIDs = array(); //  ID 

        $pageToken = NULL; //     
        $messages = array(); //    

        //  
        $opt_param = array();
        //    ,       Gmail      q
        if (count($arrOptionalParams)) $opt_param['q'] = str_replace('=', ':', http_build_query($arrOptionalParams, null, ' '));

        //   ,   ,     
        do {
            try {
                if ($pageToken) {
                    $opt_param['pageToken'] = $pageToken;
                }
                $messagesResponse = $service->users_messages->listUsersMessages($strEmail, $opt_param);
                if ($messagesResponse->getMessages()) {
                    $messages = array_merge($messages, $messagesResponse->getMessages());
                    $pageToken = $messagesResponse->getNextPageToken();
                }
            } catch (Exception $e) {
                throw new \Exception('   listMessageIDs: '.$e->getMessage());
            }
        } while ($pageToken);

        //   ID  
        if (count($messages)) {
            foreach ($messages as $message) {
                $arrIDs[] = $message->getId();
            }
        }
        return $arrIDs;
    }
    // ---------------------------------------------------------------------------------------------

    /**
     *      ID  batchDelete
     *
     * @param  Google_Service_Gmail $service Authorized Gmail API instance.
     * @param  string $strEmail  
     * @param  array $arrIDs  ID      listMessageIDs
     * @throws Exception
     */
    function deleteMessages(Google_Service_Gmail $service, string $strEmail, array $arrIDs){
        //      1000 ,      batchDelete
        $arrParts = array_chunk($arrIDs, 999);
        if (count($arrParts)){
            foreach ($arrParts as $arrPartIDs){
                try{
                    //     
                    $objBatchDeleteMessages = new Google_Service_Gmail_BatchDeleteMessagesRequest();
                    //   
                    $objBatchDeleteMessages->setIds($arrPartIDs);
                    //  
                    $service->users_messages->batchDelete($strEmail,$objBatchDeleteMessages);
                }catch (Exception $e) {
                    throw new \Exception('   deleteMessages: '.$e->getMessage());
                }
            }
        }
    }
    // ---------------------------------------------------------------------------------------------

    /**
     *     get
     *
     * @param  Google_Service_Gmail $service Authorized Gmail API instance.
     * @param  string $strEmail  
     * @param  string $strMessageID ID 
     * @param  string $strFormat The format to return the message in.
     * Acceptable values are:
     * "full": Returns the full email message data with body content parsed in the payload field; the raw field is not used. (default)
     * "metadata": Returns only email message ID, labels, and email headers.
     * "minimal": Returns only email message ID and labels; does not return the email headers, body, or payload.
     * "raw": Returns the full email message data with body content in the raw field as a base64url encoded string; the payload field is not used.
     * @param  array $arrMetadataHeaders When given and format is METADATA, only include headers specified.
     * @return  object Message
     * @throws Exception
     */
    function getMessage(Google_Service_Gmail $service, string $strEmail, string $strMessageID, string $strFormat = 'full', array $arrMetadataHeaders = array()){
        $arrOptionalParams = array(
            'format' => $strFormat // ,    
        );
        //   - metadata,     
        if (($strFormat == 'metadata') and count($arrMetadataHeaders))
            $arrOptionalParams['metadataHeaders'] = implode(',',$arrMetadataHeaders);

        try{
            $objMessage = $service->users_messages->get($strEmail, $strMessageID,$arrOptionalParams);
            return $objMessage;
        }catch (Exception $e) {
            throw new \Exception('   getMessage: '.$e->getMessage());
        }
    }
    // ---------------------------------------------------------------------------------------------

    /**
     *   ,    
     *
     * @param  Google_Service_Gmail $service Authorized Gmail API instance.
     * @param  string $strEmail  
     * @return  object $objLabels -  -  
     * @throws Exception
     */
    function listLabels(Google_Service_Gmail $service, string $strEmail){
        try{
            $objLabels = $service->users_labels->listUsersLabels($strEmail);
            return $objLabels;
        }catch (Exception $e) {
            throw new \Exception('   listLabels: '.$e->getMessage());
        }
    }
    // ---------------------------------------------------------------------------------------------

    /**
     *     ()  
     *
     * @param  Google_Service_Gmail $service Authorized Gmail API instance.
     * @param  string $strEmail  
     * @param  string $strMessageID ID 
     * @param  array $arrAddLabelIds  ID ,     
     * @param  array $arrRemoveLabelIds  ID ,     
     * @return  object Message -  
     * @throws Exception
     */
    function modifyLabels(Google_Service_Gmail $service, string $strEmail, string $strMessageID, array $arrAddLabelIds = array(), array $arrRemoveLabelIds = array()){
        try{
            $objPostBody = new Google_Service_Gmail_ModifyMessageRequest();
            $objPostBody->setAddLabelIds($arrAddLabelIds);
            $objPostBody->setRemoveLabelIds($arrRemoveLabelIds);
            $objMessage = $service->users_messages->modify($strEmail,$strMessageID,$objPostBody);
            return $objMessage;
        }catch (Exception $e) {
            throw new \Exception('   modifyLabels: '.$e->getMessage());
        }
    }
    // ---------------------------------------------------------------------------------------------

}




Gmailを操作するときはいつでも、最初に行うことは、GmailAPIクラスのgetService($ strEmail)関数を呼び出すことです。この関数は、$ strEmailメールボックスを操作するための「承認済み」オブジェクトを返します。さらに、このオブジェクトは、必要なアクションを直接実行するために、他の関数にすでに渡されています。GmailAPIクラスの他のすべての関数は、すでに特定のタスクを実行しています。



  • listMessageIDs-指定された基準に従ってメッセージを検索し、そのIDを返します(listUsersMessages Gmail API関数に渡される検索文字列は、メールボックスWebインターフェイスの検索文字列と類似している必要があります)。
  • deleteMessages-IDが渡されたメッセージを削除します(batchDelete API Gmail関数は1回のパスで1000個以下のメッセージを削除するため、関数に渡されたIDの配列をそれぞれ999文字の複数の配列に分割し、削除を数回実行する必要がありました)、
  • getMessage-IDが渡されたメッセージに関するすべての情報を取得します。
  • listLabels-メールボックス内のフラグのリストを返します(メールボックスWebインターフェイスで最初に作成され、目的のメッセージに割り当てられたフラグのIDを取得するために使用しました)
  • modifyLabels-メッセージにフラグを追加または削除します


次に、さまざまなメールボックスの古い文字を削除するタスクがあります。同時に、メールボックスごとに数日前に受け取った古い手紙を考慮します。このタスクを実行するために、cronによって毎日実行される次のスクリプトを記述します。



古いメールを削除する
<?php
/**
 *      Gmail
 *      
 */
require __DIR__ .'/../general/config/config.php'; //   
require __DIR__ .'/../vendor/autoload.php'; //   

//       
$arrMailBoxesForClean = array(
    'a@domain.com' => 30,
    'b@domain.com' => 30,
    'c@domain.com' => 7,
    'd@domain.com' => 7,
    'e@domain.com' => 7,
    'f@domain.com' => 1
);

$arrErrors = array(); //  
$objGmailAPI = new GmailAPI(); //     GMail

//     ,      
foreach ($arrMailBoxesForClean as $strEmail => $intDays) {
    try{
        //    
        $service = $objGmailAPI->getService($strEmail);
        //       
        $arrParams = array('before' => date('Y/m/d', (time() - 60 * 60 * 24 * $intDays)));
        //   ,   
        $arrIDs = $objGmailAPI->listMessageIDs($service,$strEmail,$arrParams);
        //     ID   $arrIDs
        if (count($arrIDs)) $objGmailAPI->deleteMessages($service,$strEmail,$arrIDs);
        //    
        unset($service,$arrIDs);
    }catch (Exception $e) {
        $arrErrors[] = $e->getMessage();
    }
}

if (count($arrErrors)){
    $strTo = 'my_email@domain.com';
    $strSubj = '       ';
    $strMessage = '         :'.
        '<ul><li>'.implode('</li><li>',$arrErrors).'</li></ul>'.
        '<br/>URL: '.filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL);
    $objMailSender = new mailSender();
    $objMailSender->sendMail($strTo,$strSubj,$strMessage);
}




スクリプトは、指定された各メールボックスに接続し、古い文字を選択して削除します。



自動レポートに基づいて未配信の電子メールに関するマネージャーのレポートを生成するタスクは、次のスクリプトによって解決されます。



メールのフィルタリングとマーキング
<?php
/*
 *    a@domain.com
 *      ,     : : mailer-daemon@googlemail.com
 *      .        ,   b@domain.com
 *   
 */
require __DIR__ .'/../general/config/config.php'; //   
require __DIR__ .'/../vendor/autoload.php'; //   

$strEmail = 'a@domain.com';
$strLabelID = 'Label_2399611988534712153'; //  reportProcessed -    

//  
$arrParams = array(
    'from' => 'mailer-daemon@googlemail.com', //       
    'in' => 'inbox', //  
    'after' => date('Y/m/d', (time() - 60 * 60 * 24)), //   
    'has' => 'nouserlabels' //  
);

$arrErrors = array(); //  
$objGmailAPI = new GmailAPI(); //     GMail
$arrClientEmails = array(); //    ,      

try{
    //    
    $service = $objGmailAPI->getService($strEmail);
    //         ,    
    $arrIDs = $objGmailAPI->listMessageIDs($service,$strEmail, $arrParams);
    //      'X-Failed-Recipients',    ,      
    if (count($arrIDs)){
        foreach ($arrIDs as $strMessageID){
            //   
            $objMessage = $objGmailAPI->getMessage($service,$strEmail,$strMessageID,'metadata',array('X-Failed-Recipients'));
            //  
            $arrHeaders = $objMessage->getPayload()->getHeaders();
            //  
            foreach ($arrHeaders as $objMessagePartHeader){
                if ($objMessagePartHeader->getName() == 'X-Failed-Recipients'){
                    $strClientEmail = mb_strtolower(trim($objMessagePartHeader->getValue()), 'UTF-8');
                    if (!empty($strClientEmail)) {
                        if (!in_array($strClientEmail, $arrClientEmails)) $arrClientEmails[] = $strClientEmail;
                    }
                    //    reportProcessed,       
                    $objGmailAPI->modifyLabels($service,$strEmail,$strMessageID,array($strLabelID));
                }
            }
        }
    }
    unset($service,$arrIDs,$strMessageID);
}catch (Exception $e) {
    $arrErrors[] = $e->getMessage();
}

//     ,      ,    
if (count($arrClientEmails)) {
    $objClients = new clients();
    //   email  
    $arrAllClientsEmails = $objClients->getAllEmails();

    foreach ($arrClientEmails as $strClientEmail){
        $arrUsages = array();
        foreach ($arrAllClientsEmails as $arrRow){
            if (strpos($arrRow['email'], $strClientEmail) !== false) {
                $arrUsages[] = '  email  "<a href="'.MANAGEURL.'?m=admin&sm=clients&edit='.$arrRow['s_users_id'].'">'.$arrRow['name'].'</a>"';
            }
            if (strpos($arrRow['email2'], $strClientEmail) !== false) {
                $arrUsages[] = '  email  "<a href="'.MANAGEURL.'?m=admin&sm=clients&edit='.$arrRow['s_users_id'].'">'.$arrRow['name'].'</a>"';
            }
            if (strpos($arrRow['site_user_settings_contact_email'], $strClientEmail) !== false) {
                $arrUsages[] = '  email  "<a href="'.MANAGEURL.'?m=admin&sm=clients&edit='.$arrRow['s_users_id'].'">'.$arrRow['name'].'</a>"';
            }
        }
        $intUsagesCnt = count($arrUsages);
        if ($intUsagesCnt > 0){
            $strMessage = '          <span style="color: #000099;">'.$strClientEmail.'</span><br/>
                  ';
            if ($intUsagesCnt == 1){
                $strMessage .= ' '.$arrUsages[0].'<br/>';
            }else{
                $strMessage .= ':<ul>';
                foreach ($arrUsages as $strUsage){
                    $strMessage .= '<li>'.$strUsage.'</li>';
                }
                $strMessage .= '</ul>';
            }
            $strMessage .= '<br/>,        .<br/><br/>
                    ,    ';
            if (empty($objMailSender)) $objMailSender = new mailSender();
            $objMailSender->sendMail('b@domain.com',' email ',$strMessage);
        }
    }
}

if (count($arrErrors)){
    $strTo = 'my_email@domain.com';
    $strSubj = '      ';
    $strMessage = '        :'.
        '<ul><li>'.implode('</li><li>',$arrErrors).'</li></ul>'.
        '<br/>URL: '.filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL);
    if (empty($objMailSender)) $objMailSender = new mailSender();
    $objMailSender->sendMail($strTo,$strSubj,$strMessage);
}




このスクリプトは、最初のスクリプトと同様に、指定されたメールボックスに接続し、フラグなしで必要な文字を選択し(未配信のメッセージを報告します)、文字の送信を試みた電子メールアドレスを文字内で見つけ、この文字に「処理済み」フラグを付けます。 ..。次に、見つかった電子メールアドレスを使用して操作が実行され、その結果、担当の従業員に人間が読み取れる手紙が作成されます。



ソースはGitHubで入手できます



この記事で伝えたかったのはそれだけです。読んでくれてありがとう!私のコードがあなたの目に刺さった場合は、スポイラーを巻き上げるか、コメントを書いてください-建設的な批判をうれしく思います。



All Articles