PHPでGmailの受信トレイのメール一覧を取得する例
「いろんな作業を自動化してWeb運営を楽にしよう」と言い続けているぼくですが、そういえばGmailの自動チェックについてはまだ書いていなかったなぁと気がついたので、今回はPHPでGmailに接続してメール一覧を取得するお話。
PHPでGmailに接続するためにはGoogleアカウントの設定変更が必要
PHPでGmailへ接続するためには一般的にimap関連の関数を使うのですが、Googleアカウントの設定を変更していない場合はPHPからのアクセスがブロックされます。
昔はGmail上でIMAP接続さえ許可されていれば良かったのですが、昨今はアカウントハックのためのアタックが日常茶飯事ですから、よくわからないアプリ(PHP)からの接続を拒否するようにしているのは当然と言えるでしょう。
でも開発者(やWeb運営者)としては、セキュリティと利便性を天秤にかけ、捨てアカに近いGoogleアカウントを用意してでも、メール受信とそのチェックを自動化したいケースもあります。
というわけで、PHPで開発を行うぼくらは下記ページでGoogleアカウントのセキュリティ設定で[安全性の低いアプリのアクセスを有効にする]を選択。
(テスト用のGoogleアカウントだったとしてもパスワードはきちんと設定しましょう)
https://myaccount.google.com/
また、こちらはデフォルトで許可されているとは思いますが、Gmailの[設定]→[メール転送とPOP/IMAP]というページで[IMAPを有効にする]をチェックしておく必要もあります。
PHPでGmailに接続する例
それほど難しくないので、HTMLも含めた全体をいきなりドン!
■PHPサンプルコード
<?php
//Gmailのアカウント情報
$cfg['GMAIL_ACCOUNT'] = '[Gmailのメールアドレス]';
$cfg['GMAIL_PASSWORD'] = '[Gmailのパスワード]';
//Gmailの接続情報
$cfg['MAILBOX'] = '{imap.gmail.com:993/imap/ssl}';
?>
<html lang="ja">
<head><meta charset="utf-8"></head>
<body>
<h1>GmailへIMAP接続してタイトル一覧を取得する例</h1>
<?php
//IMAP接続
if (($mbox = imap_open($cfg['MAILBOX'], $cfg['GMAIL_ACCOUNT'], $cfg['GMAIL_PASSWORD'])) == false) {
echo 'Gmailへの接続に失敗しました';
} else {
//未読のみ取得する場合
$mails = imap_search($mbox, 'UNSEEN');
$i = 0;
foreach($mails as $msgno) {
//メールのヘッダー情報を取得
$header = imap_header($mbox, $msgno);
//メールのタイトルを取得
$subject = getSubject($header);
echo $msgno.':'.$subject.'<br>';
$i++;
if ($i > 100) break;
}
imap_close($mbox);
}
//ヘッダーからタイトルを取得してデコードする関数
function getSubject($header)
{
if (!isset($header->subject)) {
//タイトルがない場合もある
return '';
}
// タイトルをデコード
$mhead = imap_mime_header_decode($header->subject);
$subject = '';
//タイトル部分は分割されているのでコード変換しながら結合する
foreach($mhead as $key => $value) {
if($value->charset == 'default') {
$subject .= $value->text; //変換しない
} else {
$subject .= mb_convert_encoding($value->text, 'UTF-8', $value->charset);
}
}
return $subject;
}
?>
</body>
</html>
解説
imap_openで接続し、imap_searchで一覧を取得し、imap_headerでタイトルを取得し、imap_closeで切断する、というのが一連の流れです。
接続~切断の流れはシンプルなものなので、どちらかというと、タイトル部分のデコードのほうが長いくらいですね。
これは仕方ないというか、メールヘッダの1行の長さは78文字という制限があるため、大抵の日本語タイトルは分割されて入っています。そのため、これをループ処理で(文字変換しながら)結合する、ということをやっているわけです。
$value->charsetに文字コードも入っているので、そのまま指定するだけで別段難しいことはないのですが、慣れないうちはたかがタイトルを取るだけなのにややこしいなぁと感じるかも知れません。
トラブルシューティング
- 下記のようなエラーが出る場合
Fatal error: Uncaught Error: Call to undefined function imap_open()
Windowsで動かしている場合はphp.iniにextension=imapが必要です。レンタルサーバーの場合は普通imapは含まれていると思います。…含まれていなかったらホスティング会社へ相談してください(;´Д`)
- 下記のようなエラーが出る場合
Warning: imap_open(): Couldn't open stream
接続文字列({imap.gmail.com:993/imap/ssl})が間違っているか、ログイン情報が間違っているか、先述した[安全性の低いアプリのアクセスを有効にする]の設定が完了していない可能性があります。もしそうなら、使おうとしたGoogleアカウントのメールボックスに[重大なセキュリティ通知]と題したメールが届いているハズなので、チェックしてみると良いでしょう。
おまけ
■既読/未読関係なく、新しい順にメールを取得したい場合
//メールボックス情報を取得
$info = imap_check($mbox);
$max = 50;//最大50件取得
for ($i = 0; $i < $max; $i++) {
$msgno = $info->Nmsgs - $i;
if ($msgno < 0) break;
//メールのヘッダー情報を取得
$header = imap_header($mbox, $msgno);
//メールのタイトルを取得
$subject = getSubject($header);
echo $msgno.':'.$subject.'<br>';
}
先述の例の「//未読のみ取得する場合」部分を上記のコードに変更すれば未読/既読関係なく、新しい順にメールタイトルの一覧を取得できます。ただ、デフォルトでは全件取得できる設定になっているため、何千通も溜め込んでいるとフリーズしたかのように時間がかかってしまうかも知れません。
そのため、$max = 50;というように最大50件までにしています。そのへんは適宜書き換えて使うと良いでしょう。
まとめ
- PHPでGmailの受信トレイのメール一覧を取得するにはimap_open、imap_search、imap_header、imap_closeを使う
- また、imap_checkで受信トレイ内のメール件数が取得できる
- それを使ってメッセージ番号を逆順にリクエストすれば、未読/既読関係なく新しい順にメール一覧の取得ができる
といったところでしょうか。
本文の取得まで書くと長くなりそうだったので、今回はひとまずヘッダー(タイトル)までとしました。