PHPでIMAPを使いメールの本文を取得する例
前回の記事「PHPでGmailの受信トレイのメール一覧を取得する例」ではGmailへIMAP接続し、メールの一覧(タイトルのみ)を取得する例を紹介しました。
今回は引き続き、メールの本文を取得する例です。
前提
前回の記事でIMAPの接続とメール一覧を取得するところまでは書いてあるハズですので、そこにgetBodyというメール本文を取得する関数を組み込む感じで進めます。
■サンプルコード
//Gmailのアカウント情報
$cfg['GMAIL_ACCOUNT'] = '[Gmailのメールアドレス]';
$cfg['GMAIL_PASSWORD'] = '[Gmailのパスワード]';
//Gmailの接続情報
$cfg['MAILBOX'] = '{imap.gmail.com:993/imap/ssl}';
//IMAP接続
if (($mbox = imap_open($cfg['MAILBOX'], $cfg['GMAIL_ACCOUNT'], $cfg['GMAIL_PASSWORD'])) == false) {
echo 'Gmailへの接続に失敗しました';
} else {
//メールボックス情報を取得
$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>';
echo '<textarea>'.getBody($mbox, $msgno).'</textarea>';
}
imap_close($mbox);
}
PHPでIMAPメールの本文を取得する例(手抜き版)
■サンプルコード
//メール本文の取得(マルチパート非対応)
function getBody($mbox, $msgno)
{
$body = imap_body($mbox, $msgno);
$body = mb_convert_encoding($body, 'UTF-8', 'auto');
return $body;
}
解説
PHPのimap_body関数で本文を取得し、文字コードの変換もautoで任せてしまうという手抜きっぷり。
でも、昔ながらのiso-2022-jpなテキストのみのメールならこれだけでけっこう動きます。
特に「いろんな作業を自動化してWeb運営を楽にしよう」というコンセプトでPHPスクリプトの紹介をしている当ブログとしては、メール送信するのも受信するのも自分のプログラムだったりするので、ぶっちゃけコレだけでも良いかな、と思わなくもありません。
PHPでIMAPメールの本文を取得する例(もう少し真面目版)
■サンプルコード
//メール本文の取得(マルチパートほんのり対応)
function getBody($mbox, $msgno)
{
//マルチパートだろうとそうでなかろうと1個目を取得する
$body = imap_fetchbody($mbox, $msgno, 1, FT_INTERNAL);
//メールの構造を取得
$s = imap_fetchstructure($mbox, $msgno);
//マルチパートのメールかどうか確認しつつ、文字コードとエンコード方式を確認
if (isset($s->parts)) {
//マルチパートの場合
$charset = $s->parts[0]->parameters[0]->value;
$encoding = $s->parts[0]->encoding;
} else {
//マルチパートではない場合
$charset = $s->parameters[0]->value;
$encoding = $s->encoding;
}
//エンコード方式に従いデコードする
switch ($encoding) {
case 1://8bit
$body = imap_8bit($body);
$body = imap_qprint($body);
break;
case 3://Base64
$body = imap_base64($body);
break;
case 4: //Quoted-Printable
$body = imap_qprint($body);
break;
case 0: //7bit
case 2: //Binary
case 5: //other
default:
//7bitやBinaryは何もしない
}
//メールの文字コードをUTF-8へ変換する
$body = mb_convert_encoding($body, 'UTF-8', $charset);
return $body;
}
解説
いきなり長くなりましたが、これでも完全と言えるかどうかは微妙なところ。
1行目でいきなりその理由がわかるかと思いますが、
//マルチパートだろうとそうでなかろうと1個目を取得する
$body = imap_fetchbody($mbox, $msgno, 1, FT_INTERNAL);
このとおり、マルチパートメールだろうとそうでなかろうと、1個目のメール本文を取得しています。
そもそもマルチパートメールとはなんぞや、という話ですが、1つのメールの中に異なる形式のデータを含むメールのことです。
例えば添付ファイル付きのメールが良い例ですが、あれは1個目にメール本文、2個目に添付ファイルをエンコードした文字列が並んでいるだけのものです。なので、その場合、1個目のメール本文だけわかれば良いよね、ってことで1個目しか取得していません。
また、HTMLメールの場合、それを読めないメールソフトのことを考え、1個目にテキストメール、2個目にHTML、と並べているケースがあります。まぁ最近だいぶ少なくなりましたけどね。HTMLメールが読めないメールソフトなんてほとんどないやろ、という風潮もありますのでw
ともあれ、どっちにしろ、これも1個目のメール本文だけ読めれば良いんじゃないかな…という理由(言い訳)で上記のような作りにしました。本気でメールソフトレベルのモノが作りたい場合は$s->partsが連想配列になっていますので、ループして本文を取得すると良いでしょう。
文字コードについて
マルチパートの場合は1個目のパラメーターから文字コードを取得しています。
$charset = $s->parts[0]->parameters[0]->value;
マルチパートじゃない場合は $s->partsがないため、下記のとおり、parameters[0]から取得です。
$charset = $s->parameters[0]->value;
どちらの場合も $charset にはUTF-8やらiso-2022-jpやら、メール本文で使われている文字コードの名称が入ってきますので、それに従って最後の最後に mb_convert_encoding しているという寸法。
エンコード方式について
メールの場合、気にするのは文字コードだけではないのですよね。エンコード方式が8bit / Base64 / Quoted-Printableだったりするので、それに従って変換をしています。7bitは何も処理する必要がないのと、binaryとotherは見たことがないのでそのままスルーしています(手抜き)。
まとめ
- メール本文を簡単に取得するならimap_body関数を使う
- 但し、メール本文がBase64などにエンコードされている可能性がある場合はimap_fetchstructureでメール構造と文字コードとエンコード方式を調べて、それぞれ適切に変換する必要がある
といったところでしょうか。
マルチパートのメールについてはもうちょい真面目にやろうかなとも思ったのですが、うーん、やっぱり自動化処理においては1つ目の本文だけ取得できれば良いよなぁ…としか思えなかったので、これ以上サンプルが長くなるよりは、ということで手抜き版とさせて頂きました。
とりあえず、ここまで作れれば、例えば自動的にメールチェックして、本文中のリンクをブラウザで全部開く、とか簡単に自動化できると思います。もちろんそれによってSPAMメールを自動で開いたら大変なので、差出人やURLのチェックとかも必要ですけどね。