ワークショップ

フォームを作る vol.9

アップロードしたファイルをメールに添付する

  • このエントリーをはてなブックマークに追加

フォームからサーバーへアップロードされたファイルを、自動送信メールに添付する機能を実装します。

この記事のポイント

  • メールにファイルを添付する方法が分かる
  • メール本文の構造が分かる

目次

自動送信メールにファイルを添付

前回の「フォームにファイルアップロード機能をつける」では、フォームに画像やPDFなどのファイルをサーバー上のディレクトリへ保存する機能を実装しました。
今回はそのファイルを、自動送信されるメールへ添付する機能を実装します。

今回使用しているコードは、前回までに作成したものを使うことを前提としています。
前回のページ:vol.8 フォームにファイルアップロード機能をつける
前回作成したコードはこちら:vol.8のサンプルコード – GitHub

添付ファイル付きのメール概要

最初に、メールにファイルを添付する方法を解説します。
まずはmb_send_mail関数のパラメータを改めて確認します。

mb_send_mail( $to, $subject, $body, $header);

$toには宛先、$subjectにはメールの件名、$bodyにはメッセージ(本文)、$headerはヘッダー情報がそれぞれ入ります。
次のようなイメージ。

メールの構造

今までは本文に「この度は、お問い合わせ頂き誠にありがとうございます。」などのテキストデータだけを入れて送信してきました。

テキストデータのみのメール

メールの本文にテキストデータだけを入れたイメージ

実は、本文にはテキストデータ以外にもファイルなどを入れて送信することができます。

ファイルデータも入ったメール

本文にテキストデータとファイルデータの両方を入れたイメージ

このようにファイルデータが含まれたメールが、いわゆる「添付ファイル付きのメール」となります。もちろん複数のファイルを添付することも可能です。

これから、「本文」にテキストデータのみではなく、ファイルデータも含めた形で送信するように設定をしていきます。

今回実装するソースコード

早速コードを書いていきましょう。
今回はメール送信に関連した実装となるため、「送信」ボタンが押された後の場所にコードを追加、及び修正を加えていきます。

Note

赤い箇所は追加するコードを、オレンジの箇所は修正しているコードを示します。

index.php

<?php

define( "FILE_DIR", "images/test/");

...省略...

} elseif( !empty($clean['btn_submit']) ) {

	$page_flag = 2;

	// 変数とタイムゾーンを初期化
	$header = null;
	$body = null;
	$auto_reply_subject = null;
	$auto_reply_text = null;
	$admin_reply_subject = null;
	$admin_reply_text = null;
	date_default_timezone_set('Asia/Tokyo');
	
	//日本語の使用宣言
	mb_language("ja");
	mb_internal_encoding("UTF-8");

	$header = "MIME-Version: 1.0\n";
	$header = "Content-Type: multipart/mixed;boundary=\"__BOUNDARY__\"\n";
	$header .= "From: GRAYCODE <noreply@gray-code.com>\n";
	$header .= "Reply-To: GRAYCODE <noreply@gray-code.com>\n";

	// 件名を設定
	$auto_reply_subject = 'お問い合わせありがとうございます。';

	// 本文を設定
	$auto_reply_text = "この度は、お問い合わせ頂き誠にありがとうございます。
下記の内容でお問い合わせを受け付けました。\n\n";
	$auto_reply_text .= "お問い合わせ日時:" . date("Y-m-d H:i") . "\n";
	$auto_reply_text .= "氏名:" . $clean['your_name'] . "\n";
	$auto_reply_text .= "メールアドレス:" . $clean['email'] . "\n";

	if( $clean['gender'] === "male" ) {
		$auto_reply_text .= "性別:男性\n";
	} else {
		$auto_reply_text .= "性別:女性\n";
	}
	
	if( $clean['age'] === "1" ){
		$auto_reply_text .= "年齢:〜19歳\n";
	} elseif ( $clean['age'] === "2" ){
		$auto_reply_text .= "年齢:20歳〜29歳\n";
	} elseif ( $clean['age'] === "3" ){
		$auto_reply_text .= "年齢:30歳〜39歳\n";
	} elseif ( $clean['age'] === "4" ){
		$auto_reply_text .= "年齢:40歳〜49歳\n";
	} elseif( $clean['age'] === "5" ){
		$auto_reply_text .= "年齢:50歳〜59歳\n";
	} elseif( $clean['age'] === "6" ){
		$auto_reply_text .= "年齢:60歳〜\n";
	}

	$auto_reply_text .= "お問い合わせ内容:" . nl2br($clean['contact']) . "\n\n";
	$auto_reply_text .= "GRAYCODE 事務局";

	// テキストメッセージをセット
	$body = "--__BOUNDARY__\n";
	$body .= "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n\n";
	$body .= $auto_reply_text . "\n";
	$body .= "--__BOUNDARY__\n";

	// ファイルを添付
	if( !empty($clean['attachment_file']) ) {
		$body .= "Content-Type: application/octet-stream; name=\"{$clean['attachment_file']}\"\n";
		$body .= "Content-Disposition: attachment; filename=\"{$clean['attachment_file']}\"\n";
		$body .= "Content-Transfer-Encoding: base64\n";
		$body .= "\n";
		$body .= chunk_split(base64_encode(file_get_contents(FILE_DIR.$clean['attachment_file'])));
		$body .= "--__BOUNDARY__\n";
	}

	// 自動返信メール送信
	mb_send_mail( $clean['email'], $auto_reply_subject, $body, $header);

	// 運営側へ送るメールの件名
	$admin_reply_subject = "お問い合わせを受け付けました";

	// 本文を設定
	$admin_reply_text = "下記の内容でお問い合わせがありました。\n\n";
	$admin_reply_text .= "お問い合わせ日時:" . date("Y-m-d H:i") . "\n";
	$admin_reply_text .= "氏名:" . $clean['your_name'] . "\n";
	$admin_reply_text .= "メールアドレス:" . $clean['email'] . "\n";

	if( $clean['gender'] === "male" ) {
		$admin_reply_text .= "性別:男性\n";
	} else {
		$admin_reply_text .= "性別:女性\n";
	}

	if( $clean['age'] === "1" ){
		$admin_reply_text .= "年齢:〜19歳\n";
	} elseif ( $clean['age'] === "2" ){
		$admin_reply_text .= "年齢:20歳〜29歳\n";
	} elseif ( $clean['age'] === "3" ){
		$admin_reply_text .= "年齢:30歳〜39歳\n";
	} elseif ( $clean['age'] === "4" ){
		$admin_reply_text .= "年齢:40歳〜49歳\n";
	} elseif( $clean['age'] === "5" ){
		$admin_reply_text .= "年齢:50歳〜59歳\n";
	} elseif( $clean['age'] === "6" ){
		$admin_reply_text .= "年齢:60歳〜\n";
	}

	$admin_reply_text .= "お問い合わせ内容:" . nl2br($clean['contact']) . "\n\n";
	
	// テキストメッセージをセット
	$body = "--__BOUNDARY__\n";
	$body .= "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n\n";
	$body .= $admin_reply_text . "\n";
	$body .= "--__BOUNDARY__\n";

	// ファイルを添付
	if( !empty($clean['attachment_file']) ) {
		$body .= "Content-Type: application/octet-stream; name=\"{$clean['attachment_file']}\"\n";
		$body .= "Content-Disposition: attachment; filename=\"{$clean['attachment_file']}\"\n";
		$body .= "Content-Transfer-Encoding: base64\n";
		$body .= "\n";
		$body .= chunk_split(base64_encode(file_get_contents(FILE_DIR.$clean['attachment_file'])));
		$body .= "--__BOUNDARY__\n";
	}

	// 管理者へメール送信
	mb_send_mail( 'webmaster@gray-code.com', $admin_reply_subject, $body, $header);
}

...省略...

実行結果

下図のようにテキストメッセージに加え、ファイル添付のあるメールが届きます。

メーラーでの表示例

コード解説

新しく追加したコードについて、上から順に解説していきます。
まず、次の2行では使用する言語、文字コードを指定しています。

//日本語の使用宣言
mb_language("ja");
mb_internal_encoding("UTF-8");

ヘッダー部に追加した1行は、ファイルデータを扱うに当たって必要なコンテンツタイプの指定を行なっています。

$header = "MIME-Version: 1.0\n";
$header = "Content-Type: multipart/mixed;boundary=\"__BOUNDARY__\"\n";
$header .= "From: GRAYCODE <noreply@gray-code.com>\n";
$header .= "Reply-To: GRAYCODE <noreply@gray-code.com>\n";

multipart/mixed;boundary=\”__BOUNDARY__\”」という指定は、メッセージ本文のデータを「__BOUNDARY__」で区切って複数の形式のデータを扱うという内容です。

実際にそれを行なっているのが次の行です。

// テキストメッセージをセット
$body = "--__BOUNDARY__\n";
$body .= "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n\n";
$body .= $auto_reply_text . "\n";
$body .= "--__BOUNDARY__\n";

// ファイルを添付
if( !empty($clean['attachment_file']) ) {
	$body .= "Content-Type: application/octet-stream; name=\"{$clean['attachment_file']}\"\n";
	$body .= "Content-Disposition: attachment; filename=\"{$clean['attachment_file']}\"\n";
	$body .= "Content-Transfer-Encoding: base64\n";
	$body .= "\n";
	$body .= chunk_split(base64_encode(file_get_contents(FILE_DIR.$clean['attachment_file'])));
	$body .= "--__BOUNDARY__\n";
}

今までと同じ方法で作成したテキストデータ「$auto_reply_text」と、添付したいファイルの2つを「__BOUNDARY__」で区切って1つのメッセージを生成します。

データの種類によって、それぞれにコンテンツタイプを指定している点にも注目してください。
テキストデータは「text/plain」と文字コードの「ISO-2022-JP」を、添付ファイルについては様々なファイル形式に対応した「application/octet-stream」を指定しています。
もし添付するファイル形式が限られていたら「image/jpeg」などと指定することも可能です。

添付ファイルについてはコンテンツタイプ以外にも「Content-Disposition」と「Content-Transfer-Encoding」を記述しています。

Content-Disposition

「Content-Disposition」はコンテンツの表示方法をします。
初期値は「inline」で、そのまま表示する指定となっています。

しかし今回はファイルの添付なので、「attachment」を指定し、「このデータはダウンロード形式にする」という指定です。

Content-Transfer-Encoding

「Content-Transfer-Encoding」はデータのエンコード形式を指定します。
ただのテキスト形式のデータであればこの指定は不要ですが、画像やPDFのような独自の形式をもつデータの場合は、メールで送信するための形式にエンコード(変換)しなければなりません。

ここで指定している「base64」というものは、メールのデータを送信する規格である「MIME(Multipurpose Internet Mail Extensions)」で使われているエンコード方式です。
一般的に使われているメールでは、通常のテキストを除き、基本的にこの「base64」という形式にエンコード・デコードしてやり取りを行います。

実際にこのbase64形式へエンコード処理をしているのが、次の1行です。

$body .= chunk_split(base64_encode(file_get_contents(FILE_DIR.$clean['attachment_file'])));

3つの関数が入れ子になっており少々見づらいですが、内側から順にみていきます。

まず、file_get_contents関数でサーバーに保存されているファイルを取得します。
その取得したファイルを、続くbase64_encode関数でbase64の形式へエンコード。
最後に、chunk_split関数でエンコードしたデータに改行を加えます。

最後の改行を加える処理は地味ですが、メールの送信形式に合わせた形にデータの形式を整えてあげる重要な処理です。

以上で送信する本文データの準備が整いました。
本文データが入った$bodymb_send_mail関数に渡して実行すれば添付ファイル付きのメール送信完了です。
以上と同じ処理を、管理者宛のメールにも行います。

// テキストメッセージをセット
$body = "--__BOUNDARY__\n";
$body .= "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n\n";
$body .= $admin_reply_text . "\n";
$body .= "--__BOUNDARY__\n";

// ファイルを添付
if( !empty($clean['attachment_file']) ) {
	$body .= "Content-Type: application/octet-stream; name=\"{$clean['attachment_file']}\"\n";
	$body .= "Content-Disposition: attachment; filename=\"{$clean['attachment_file']}\"\n";
	$body .= "Content-Transfer-Encoding: base64\n";
	$body .= "\n";
	$body .= chunk_split(base64_encode(file_get_contents(FILE_DIR.$clean['attachment_file'])));
	$body .= "--__BOUNDARY__\n";
}

// 管理者へメール送信
mb_send_mail( 'webmaster@gray-code.com', $admin_reply_subject, $body, $header)

以上で、添付ファイル付きのメールを送信する処理が実装されました。
次回は、セッションを使ったフォームの2重送信を防ぐ機能を実装します。

今回作成したコードはこちら:vol.9のサンプルコード – GitHub

こちらの記事は役に立ちましたか?

ありがとうございます。
もしよろしければ、あわせてフィードバックや要望などをご入力ください。

ありがとうございます。
コメントを送信しました。

  • このエントリーをはてなブックマークに追加
前のページへ 一覧ページへ一覧 次のページへ