[0037]laravel-imapを利用してメールサーバからIMAPでメール受信

■インストールと設定

まず、laravel-imapをインストールします。

この例の環境は、Lalavelフレームワークのバージョン→10

PHPのバージョン→8.2.28

lalavel-imapのバージョン→6.2(特に指定せずインストールしたときのバージョン)

コマンドプロンプト

              
#インストール
% composer require webklex/laravel-imap
#config配下にimap.php作成
% php artisan vendor:publish --provider="Webklex\IMAP\Providers\LaravelServiceProvider"
              
            

vendor配下にwebklexフォルダ、config配下にimap.phpが作成されます。

次にimap.phpを修正します。

imap.php

              
/*
    |--------------------------------------------------------------------------
    | Available IMAP accounts
    |--------------------------------------------------------------------------
    |
    | Please list all IMAP accounts which you are planning to use within the
    | array below.
    |
    */
    'accounts' => [

        'default' => [// account identifier
            'host'  => env('IMAP_HOST', 'ホスト'),
            'port'  => env('IMAP_PORT', ポート),
            'protocol'  => env('IMAP_PROTOCOL', 'imap'), //might also use imap, [pop3 or nntp (untested)]
            'encryption'    => env('IMAP_ENCRYPTION', 'ssl'), // Supported: false, 'ssl', 'tls', 'notls', 'starttls'
            'validate_cert' => env('IMAP_VALIDATE_CERT', false),
            'username' => env('IMAP_USERNAME', 'ユーザー'),
            'password' => env('IMAP_PASSWORD', 'パスワード'),
            'authentication' => env('IMAP_AUTHENTICATION', null),
            'proxy' => [
                'socket' => null,
                'request_fulluri' => false,
                'username' => null,
                'password' => null,
            ],
            "timeout" => 30,
            "extensions" => []
        ],
        'test2' => [// account identifier
            'host'  => env('IMAP_HOST', 'ホスト'),
            'port'  => env('IMAP_PORT',ポート),
            'protocol'  => env('IMAP_PROTOCOL', 'imap'), //might also use imap, [pop3 or nntp (untested)]
            'encryption'    => env('IMAP_ENCRYPTION', 'ssl'), // Supported: false, 'ssl', 'tls', 'notls', 'starttls'
            'validate_cert' => env('IMAP_VALIDATE_CERT', false),
            'username' => env('IMAP_USERNAME', 'ユーザー'),
            'password' => env('IMAP_PASSWORD', 'パスワード'),
            'authentication' => env('IMAP_AUTHENTICATION', null),
            'proxy' => [
                'socket' => null,
                'request_fulluri' => false,
                'username' => null,
                'password' => null,
            ],
            "timeout" => 30,
            "extensions" => []
        ],
        'test3' => [// account identifier
            'host'  => env('IMAP_HOST', 'ホスト'),
            'port'  => env('IMAP_PORT', ポート),
            'protocol'  => env('IMAP_PROTOCOL', 'imap'), //might also use imap, [pop3 or nntp (untested)]
            'encryption'    => env('IMAP_ENCRYPTION', 'ssl'), // Supported: false, 'ssl', 'tls', 'notls', 'starttls'
            'validate_cert' => env('IMAP_VALIDATE_CERT', false),
            'username' => env('IMAP_USERNAME', 'ユーザー'),
            'password' => env('IMAP_PASSWORD', 'パスワード'),
            'authentication' => env('IMAP_AUTHENTICATION', null),
            'proxy' => [
                'socket' => null,
                'request_fulluri' => false,
                'username' => null,
                'password' => null,
            ],
            "timeout" => 30,
            "extensions" => []
        ],

        /*
        'gmail' => [ // account identifier
            'host' => 'imap.gmail.com',
            'port' => 993,
            'encryption' => 'ssl',
            'validate_cert' => true,
            'username' => 'example@gmail.com',
            'password' => 'PASSWORD',
            'authentication' => 'oauth',
        ],

        'another' => [ // account identifier
            'host' => '',
            'port' => 993,
            'encryption' => false,
            'validate_cert' => true,
            'username' => '',
            'password' => '',
            'authentication' => null,
        ]
        */
    ],
              
            

default以外にもtest2,test3のように追加し、複数設定することができます。

■メール受信

次は利用する側です。今回の場合はCronでメール受信をしてDBへ保持するものです

メール受信に関係のある資料が少ない。。試行錯誤しました。

受信に関係あるところだけ抜粋しています。

Cronの一部

              
use Webklex\IMAP\Facades\Client;
use Storage;

//接続先 imap.phpのdefaultの設定に接続
$client = Client::account('default');
//test2に接続したい場合は、accountを変更するだけ
$client = Client::account('test2');
//接続
$client->connect();
//接続できた場合はtrue
$status = $client->isConnected();
//フォルダ操作
$folders = $client->getFolders();
foreach ($folders as $folder) {
    echo 'フォルダーの名前は' .$folder->name;
    echo 'メールの数は'.$folder->query()->all()->count();
    echo "通です";
}
//フォルダ名を指定し、フォルダ情報を取得
$info = $client->checkFolder("INBOX");
//UIDの最後を取得
$uidlast =  $info["uidnext"];
//フォルダ名を指定
$oFolder = $client->getFolder("INBOX");
//添付ファイル保存場所
$file_path = "/file_up/other/mail_attach_file/";
//メッセージの取得 それぞれ
$messages = $oFolder->messages()->UID($uid)->get();//UIDを指定し、1件取得
if(_helper_cnt_chk(@$messages) == 0){
    echo "無いので終了uid:".$uid."\n";
    break;//抜ける
}
//query() と messages() はどちらも変わらないよう?同じコードでもデータがない日付までさかのぼるとエラーになったりした
$query = $oFolder->query();
$messages = $query->since(now()->subDays(1))->get();
$messages = $query->since('9.05.2025')->get();
$messages = $query->since('16.05.2025')->setFetchOrder("desc")->limit()->get();

foreach ($messages as $message) {
        echo "uid:".$uid."\n";
        //エンコードを知りたいのでattributeを取得
        $attributes = $message->getAttributes();
        $content_type = $attributes['content_type'][0];
        echo "content_type:".$content_type."\n";
        //charset=gb2312の場合はタイトルが文字化けするので対策
        if(strpos($content_type,'charset=gb2312') !== false){
            $setArr['title'] = mb_convert_encoding($message->getSubject(), "UTF-8", "GBK");//文字化け対策
        }else{
            $setArr['title'] = strval($message->getSubject());//タイトルの取得
        }
		//受信時間はtimezoneが日本とは限らないので日本時間に合わせる
        $dates  = $message->getDate()[0];//Carbon
        if($dates->timezone != "+09:00"){
            if(strpos($dates->timezone,'+') !== false){
                $timezones = str_replace("+", "", $dates->timezone);
                $exs = explode(":", $timezones);
                $timecnt = 9-intval($exs[0]);
            }else{
                $timezones = str_replace("-", "", $dates->timezone);
                $exs = explode(":", $timezones);
                $timecnt = 9+intval($exs[0]);
            }
            $dates  = $message->getDate()[0]->addHours($timecnt);
        }

        $setArr['mail_date'] = $dates->toDateTimeString();//秒まで取得
        $setArr['mail_d'] = $dates->toDateString();//日付のみ取得
        $setArr['mail_t'] = $dates->toTimeString();//時分秒のみ取得
        $setArr['uid'] = $message->getUid();//UID取得

		//Fromアドレスと名前を分けて保持する
        $setArr['from_nm'] = "";
        $setArr['from_mails'] = $message->getFrom()[0]->mail;
        if($message->getFrom()[0]->mail != $message->getFrom()[0]->full){
            $setArr['from_nm'] = $message->getFrom()[0]->full;
            $setArr['from_nm'] = str_replace('"','', $setArr['from_nm']);
            if(strpos($setArr['from_nm'],'<') !== false){
                $setArr['from_nm'] = str_replace("<".$setArr['from_mails'].">", "", $setArr['from_nm']);
                $setArr['from_nm'] = str_replace(' ','', $setArr['from_nm']);
            }
        }
		//Toは複数ある可能性があり、Toの数を取得するような関数が見つからなかったので、max宛先数を最大にしてToアドレスと名前を分けて保持する
        $to_nm = "";
        $tos = $message->getTo();
        $cntm = 500;//max宛先数
        $to_mails = array();
        $to_nms = array();
        for($i=0;$i < $cntm;$i++){
            if(empty($tos[$i])){
                break;
            }else{
                if($tos[$i]->mail != $tos[$i]->full){
                    $full = $tos[$i]->full;
                    $full = str_replace('"','', $full);
                    if(strpos($full,'<') !== false){
                        $full = str_replace("<".$tos[$i]->mail.">", "", $full);
                        $full = str_replace(' ','', $full);
                    }
                    $to_nms[] = $full;
                }
                $to_mails[] = $tos[$i]->mail;
            }
        }
        if(!empty($from_nms)){
            $setArr['to_nm'] = _helper_imp_chg(",",$to_nms);
        }
        $setArr['to_mails'] = _helper_imp_chg(",",$to_mails);
		//Ccアドレスも同様
        $tos = $message->getCc();
        $cntm = 500;//max宛先数
        $cc_mails = array();
        for($i=0;$i < $cntm;$i++){
            if(empty($tos[$i])){
                break;
            }else{
                $cc_mails[] = $tos[$i]->mail;
            }
        }
        $setArr['cc_mails'] = _helper_imp_chg(",",$cc_mails);

        if($message->hasHTMLBody()){
            //HTMLメールの場合の本文
            $setArr['body'] = $message->getHTMLBody();
        }else{
            if($message->hasTextBody()){
                //テキストメールの場合の本文
                $setArr['body'] = $message->getTextBody();
            }
        }
        if(empty($setArr['body'])){
            $setArr['body'] = null;
        }
        //迷惑メールと判定されるもの除外 ※「XXX」は各時それぞれ
        if(strpos($setArr['body'],'XXX') !== false && strpos($setArr['from_mails'],'XXXX') !== false){
            continue;
        }

        $setArr['created_at'] = date('Y-m-d H:i:s');

        if ($message->hasAttachments()) { //添付ファイルがあるかどうか
            $fc = 0;
            foreach ($message->getAttachments() as $attachment) {
                $uniqid = $setArr['mail_id']."_".$fc;
                if(!file_exists($file_path.$uniqid)){
                    mkdir($file_path.$uniqid);
                }
                Storage::put($uniqid.'/'.$attachment->name, $attachment->content);//添付ファイルを保存
                $fc++;
            }
        }

        echo "Insertデータ↓\n";
        //var_dump($setArr);
    }
              
            

文字化け、受信時間が日本時間に統一されていない、ToやCcアドレスは複数あるなど色々対応し、無事完了!