| (同じ利用者による、間の2版が非表示) | |||
| 198行目: | 198行目: | ||
<br> | <br> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
<?php | |||
// Composerで使用されるPHPのパッケージ管理システムに関連する重要な記述 | |||
// 必要なクラスファイルを自動的にrequire/includeする | |||
require 'vendor/autoload.php'; | |||
$ | use PhpImap\Mailbox; | ||
use PhpImap\Exceptions\ConnectionException; | |||
use PhpImap\Exceptions\InvalidParameterException; | |||
/* | |||
* メール処理を行うクラス | |||
*/ | |||
class MailProcessor | |||
{ | |||
private $mailbox; | |||
private $server; | |||
private $username; | |||
private $password; | |||
/** | |||
* コンストラクタ | |||
* | |||
* @param string $server IMAPサーバーアドレス (例: imap.example.com) | |||
* @param string $username ユーザー名 | |||
* @param string $password パスワード | |||
*/ | |||
public function __construct(string $server, string $username, string $password) | |||
{ | |||
$this->server = $server; | |||
$this->username = $username; | |||
$this->password = $password; | |||
} | |||
/** | |||
* メールボックスへの接続を確立 | |||
* | |||
* @throws ConnectionException 接続エラー時 | |||
* @return bool 接続成功時にtrue | |||
*/ | |||
public function connect(): bool | |||
{ | |||
try { | |||
// IMAPサーバへの接続文字列を構築 | |||
$imapPath = sprintf('{%s:993/imap/ssl}INBOX', $this->server); | |||
// メールボックスオブジェクトを初期化 | |||
$this->mailbox = new Mailbox($imapPath, $this->username, $this->password, | |||
__DIR__ . '/attachments', // 添付ファイル保存ディレクトリ | |||
'UTF-8' // 文字エンコーディング | |||
); | |||
// 接続 | |||
$this->mailbox->checkMailbox(); | |||
return true; | |||
} | |||
catch (ConnectionException $e) { | |||
throw new ConnectionException('メールサーバーへの接続に失敗しました: ' . $e->getMessage()); | |||
} | |||
} | |||
/** | |||
* メールを検索して取得 | |||
* | |||
* @param string $criteria 検索条件 (例: 'ALL', 'UNSEEN', 'FROM "someone@example.com"') | |||
* @return array 検索結果のメール情報配列 | |||
*/ | |||
public function searchMails(string $criteria = 'ALL'): array | |||
{ | |||
try { | |||
// メールを検索 | |||
$mailsIds = $this->mailbox->searchMailbox($criteria); | |||
$results = []; | |||
foreach ($mailsIds as $mailId) { | |||
try { | |||
$email = $this->mailbox->getMail($mailId); | |||
$results[] = [ | |||
'id' => $mailId, | |||
'subject' => $email->subject, | |||
'from' => $email->fromAddress, | |||
'date' => $email->date, | |||
'body' => $email->textPlain, | |||
'hasAttachments' => $email->hasAttachments() | |||
]; | |||
} | |||
catch (\Exception $e) { | |||
// 個別のメール取得エラーをログに記録し、処理を継続 | |||
error_log("メールID {$mailId} の取得に失敗: " . $e->getMessage()); | |||
continue; | |||
} | |||
} | |||
return $results; | |||
} | |||
catch (InvalidParameterException $e) { | |||
throw new InvalidParameterException('無効な検索条件が指定されました: ' . $e->getMessage()); | |||
} | |||
} | |||
/** | |||
* メールボックスの接続を終了 | |||
*/ | |||
public function disconnect(): void | |||
{ | |||
if ($this->mailbox) $this->mailbox->disconnect(); | |||
} | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
<br> | <br> | ||
==== | <syntaxhighlight lang="php"> | ||
===== Google Gmail API | // 使用例 | ||
try { | |||
// メールプロセッサのインスタンスを生成 | |||
$processor = new MailProcessor( | |||
'imap.example.com', | |||
'<ユーザー名>', | |||
'<パスワード>' | |||
); | |||
// 接続 | |||
$processor->connect(); | |||
// 未読メールを検索 | |||
$unreadMails = $processor->searchMails('UNSEEN'); | |||
// 結果を処理 | |||
foreach ($unreadMails as $mail) { | |||
echo "Subject: " . $mail['subject'] . "\n"; | |||
echo "From: " . $mail['from'] . "\n"; | |||
echo "Date: " . $mail['date'] . "\n"; | |||
} | |||
} | |||
catch (ConnectionException $e) { | |||
// 接続エラーの処理 | |||
error_log("接続エラー: " . $e->getMessage()); | |||
exit(1); | |||
} | |||
catch (InvalidParameterException $e) { | |||
// パラメータエラーの処理 | |||
error_log("パラメータエラー: " . $e->getMessage()); | |||
exit(1); | |||
} | |||
catch (\Exception $e) { | |||
// その他の予期せぬエラーの処理 | |||
error_log("予期せぬエラー: " . $e->getMessage()); | |||
exit(1); | |||
} | |||
finally { | |||
// 確実に接続を終了 | |||
if (isset($processor)) { | |||
$processor->disconnect(); | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== 推奨されるアプローチ ==== | |||
新規システムを設計する場合は、以下に示す順序で検討することが推奨される。<br> | |||
# クラウドメールサービスのAPIを使用 | |||
#* Gmail API | |||
#* Microsoft Graph API | |||
#* その他のモダンなメールサービスAPI | |||
#: <br> | |||
# メールサービスプロバイダのAPIが使用できない場合 | |||
#* SMTP/IMAPの代わりにRESTful APIを提供する中間サービス | |||
#*: 例: Mailgun、SendGrid、Amazon SES等 | |||
#: <br> | |||
# IMAPを使わざるを得ない場合 | |||
#* php-imap/php-imapを使用 | |||
#*: より現代的なライブラリとして保守されているため | |||
<br> | |||
上記の理由から、可能であれば、よりモダンなAPIベースのソリューションを検討することが推奨される。<br> | |||
<br><br> | |||
== APIベースのソリューション == | |||
==== Google Gmail API ==== | |||
Composerで必要なライブラリをインストールする。<br> | Composerで必要なライブラリをインストールする。<br> | ||
composer require google/apiclient | composer require google/apiclient | ||
<br> | <br> | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
// クライアントの初期化 | // クライアントの初期化 | ||
$client = new Google_Client(); | $client = new Google_Client(); | ||
$client->setApplicationName('Your Application Name'); | $client->setApplicationName('Your Application Name'); | ||
| 277行目: | 442行目: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br> | <br> | ||
===== Microsoft Graph API | * 検索条件を指定してメッセージを取得する場合 | ||
<syntaxhighlight lang="php"> | |||
$optParams = [ | |||
'q' => 'from:example@gmail.com', // 検索クエリ | |||
'maxResults' => 5 | |||
]; | |||
// 昨日以降のメール | |||
$optParams = ['q' => 'after:' . date('Y/m/d', strtotime('-1 day'))]; | |||
// 未読メール | |||
$optParams = ['q' => 'is:unread']; | |||
// 特定の件名のメール | |||
$optParams = ['q' => 'subject:"Meeting Invitation"']; | |||
// 添付ファイルがあるメール | |||
$optParams = ['q' => 'has:attachment']; | |||
</syntaxhighlight> | |||
<br> | |||
* メッセージの詳細情報の取得例 | |||
<syntaxhighlight lang="php"> | |||
function getEmailContent($gmail, $messageId) | |||
{ | |||
$message = $gmail->users_messages->get('me', $messageId, ['format' => 'full']); | |||
$payload = $message->getPayload(); | |||
// メール本文の取得 | |||
$body = ''; | |||
if ($payload->getBody()->getData()) { | |||
$body = base64url_decode($payload->getBody()->getData()); | |||
} | |||
else { | |||
// マルチパートの場合 | |||
$parts = $payload->getParts(); | |||
foreach ($parts as $part) { | |||
if ($part->getMimeType() === 'text/plain') { | |||
$body = base64url_decode($part->getBody()->getData()); | |||
break; | |||
} | |||
} | |||
} | |||
return [ | |||
'id' => $messageId, | |||
'threadId' => $message->getThreadId(), | |||
'labelIds' => $message->getLabelIds(), | |||
'body' => $body, | |||
// その他必要な情報 | |||
]; | |||
} | |||
// base64url_decode関数の定義 | |||
function base64url_decode($data) | |||
{ | |||
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
<u>※注意</u><br> | |||
<u>メールを取得する場合には、以下に示す事柄に注意すること。</u><br> | |||
* レート制限に注意する。 | |||
* 必要な権限(スコープ)が設定されていることを確認する。 | |||
* 大量のメールを処理する場合はページネーションを使用する。 | |||
<br> | |||
==== Microsoft Graph API ==== | |||
Composerで必要なライブラリをインストールする。<br> | Composerで必要なライブラリをインストールする。<br> | ||
composer require microsoft/microsoft-graph | composer require microsoft/microsoft-graph | ||
| 329行目: | 560行目: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br><br> | <br><br> | ||