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のチェックとかも必要ですけどね。

adsbygoogle

フォロー